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-02-16 15:09:03 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-02-16 15:09:03 +0300
commit8215fc964a189ae5c876a10f2e7d61933a725e24 (patch)
treeacdd0abd951ca0f392c7617821ab347d77c1a623 /app
parenta57cec4bb89b61d210d4e413571b1d85d76179f6 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/notes/components/note_header.vue24
-rw-r--r--app/assets/javascripts/pipelines/components/graph/linked_pipelines_column.vue11
-rw-r--r--app/assets/javascripts/pipelines/components/graph/stage_column_component.vue2
-rw-r--r--app/assets/javascripts/set_status_modal/components/user_availability_status.vue26
-rw-r--r--app/assets/javascripts/set_status_modal/set_status_modal_wrapper.vue3
-rw-r--r--app/assets/javascripts/set_status_modal/utils.js6
-rw-r--r--app/assets/javascripts/sidebar/components/assignees/assignee_avatar_link.vue54
-rw-r--r--app/assets/javascripts/sidebar/components/assignees/assignees.vue1
-rw-r--r--app/assets/javascripts/sidebar/components/assignees/collapsed_assignee.vue14
-rw-r--r--app/assets/javascripts/sidebar/components/assignees/collapsed_assignee_list.vue37
-rw-r--r--app/assets/javascripts/sidebar/components/assignees/uncollapsed_assignee_list.vue7
-rw-r--r--app/assets/javascripts/sidebar/components/assignees/user_name_with_status.vue40
-rw-r--r--app/assets/javascripts/vue_shared/components/user_popover/user_popover.vue12
-rw-r--r--app/models/packages/composer/cache_file.rb2
-rw-r--r--app/services/ci/pipeline_trigger_service.rb17
-rw-r--r--app/workers/all_queues.yml8
-rw-r--r--app/workers/packages/composer/cache_cleanup_worker.rb30
17 files changed, 210 insertions, 84 deletions
diff --git a/app/assets/javascripts/notes/components/note_header.vue b/app/assets/javascripts/notes/components/note_header.vue
index 101421523d0..6932af61c69 100644
--- a/app/assets/javascripts/notes/components/note_header.vue
+++ b/app/assets/javascripts/notes/components/note_header.vue
@@ -1,9 +1,9 @@
<script>
/* eslint-disable vue/no-v-html */
-import { GlIcon, GlLoadingIcon, GlTooltipDirective, GlSprintf } from '@gitlab/ui';
+import { GlIcon, GlLoadingIcon, GlTooltipDirective } from '@gitlab/ui';
import { mapActions } from 'vuex';
-import { isUserBusy } from '~/set_status_modal/utils';
import timeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
+import UserNameWithStatus from '../../sidebar/components/assignees/user_name_with_status.vue';
export default {
components: {
@@ -12,7 +12,7 @@ export default {
import('ee_component/vue_shared/components/user_avatar/badges/gitlab_team_member_badge.vue'),
GlIcon,
GlLoadingIcon,
- GlSprintf,
+ UserNameWithStatus,
},
directives: {
GlTooltip: GlTooltipDirective,
@@ -90,10 +90,6 @@ export default {
}
return false;
},
- authorIsBusy() {
- const { status } = this.author;
- return status?.availability && isUserBusy(status.availability);
- },
emojiElement() {
return this.$refs?.authorStatus?.querySelector('gl-emoji');
},
@@ -133,6 +129,9 @@ export default {
this.$refs.authorNameLink.dispatchEvent(new Event('mouseleave'));
this.isUsernameLinkHovered = false;
},
+ userAvailability(selectedAuthor) {
+ return selectedAuthor?.availability || '';
+ },
},
};
</script>
@@ -158,12 +157,11 @@ export default {
:data-username="author.username"
>
<slot name="note-header-info"></slot>
- <span class="note-header-author-name gl-font-weight-bold">
- <gl-sprintf v-if="authorIsBusy" :message="s__('UserAvailability|%{author} (Busy)')">
- <template #author>{{ authorName }}</template>
- </gl-sprintf>
- <template v-else>{{ authorName }}</template>
- </span>
+ <user-name-with-status
+ :name="authorName"
+ :availability="userAvailability(author)"
+ container-classes="note-header-author-name gl-font-weight-bold"
+ />
</a>
<span
v-if="authorStatus"
diff --git a/app/assets/javascripts/pipelines/components/graph/linked_pipelines_column.vue b/app/assets/javascripts/pipelines/components/graph/linked_pipelines_column.vue
index 30d64a58675..3ce77a1c60a 100644
--- a/app/assets/javascripts/pipelines/components/graph/linked_pipelines_column.vue
+++ b/app/assets/javascripts/pipelines/components/graph/linked_pipelines_column.vue
@@ -61,6 +61,9 @@ export default {
isUpstream() {
return this.type === UPSTREAM;
},
+ minWidth() {
+ return this.isUpstream ? 0 : this.$options.minWidth;
+ },
},
methods: {
getPipelineData(pipeline) {
@@ -132,8 +135,8 @@ export default {
this.$emit('pipelineExpandToggle', jobName, expanded);
},
- showDownstreamContainer(id) {
- return !this.isUpstream && (this.isExpanded(id) || this.isLoadingPipeline(id));
+ showContainer(id) {
+ return this.isExpanded(id) || this.isLoadingPipeline(id);
},
},
};
@@ -164,8 +167,8 @@ export default {
@pipelineExpandToggle="onPipelineExpandToggle"
/>
<div
- v-if="showDownstreamContainer(pipeline.id)"
- :style="{ minWidth: $options.minWidth }"
+ v-if="showContainer(pipeline.id)"
+ :style="{ minWidth }"
class="gl-display-inline-block"
>
<pipeline-graph
diff --git a/app/assets/javascripts/pipelines/components/graph/stage_column_component.vue b/app/assets/javascripts/pipelines/components/graph/stage_column_component.vue
index 9438c117346..0a762563114 100644
--- a/app/assets/javascripts/pipelines/components/graph/stage_column_component.vue
+++ b/app/assets/javascripts/pipelines/components/graph/stage_column_component.vue
@@ -84,7 +84,7 @@ export default {
};
</script>
<template>
- <main-graph-wrapper class="gl-px-6">
+ <main-graph-wrapper class="gl-px-6" data-testid="stage-column">
<template #stages>
<div
data-testid="stage-column-title"
diff --git a/app/assets/javascripts/set_status_modal/components/user_availability_status.vue b/app/assets/javascripts/set_status_modal/components/user_availability_status.vue
deleted file mode 100644
index e86d94f86c6..00000000000
--- a/app/assets/javascripts/set_status_modal/components/user_availability_status.vue
+++ /dev/null
@@ -1,26 +0,0 @@
-<script>
-import { AVAILABILITY_STATUS, isUserBusy, isValidAvailibility } from '../utils';
-
-export default {
- name: 'UserAvailabilityStatus',
- props: {
- availability: {
- type: String,
- required: true,
- validator: isValidAvailibility,
- },
- },
- computed: {
- isBusy() {
- const { availability = AVAILABILITY_STATUS.NOT_SET } = this;
- return isUserBusy(availability);
- },
- },
-};
-</script>
-
-<template>
- <span v-if="isBusy" class="gl-font-weight-normal gl-text-gray-500">{{
- s__('UserAvailability|(Busy)')
- }}</span>
-</template>
diff --git a/app/assets/javascripts/set_status_modal/set_status_modal_wrapper.vue b/app/assets/javascripts/set_status_modal/set_status_modal_wrapper.vue
index 639cc8a72ef..bed264341a5 100644
--- a/app/assets/javascripts/set_status_modal/set_status_modal_wrapper.vue
+++ b/app/assets/javascripts/set_status_modal/set_status_modal_wrapper.vue
@@ -10,7 +10,7 @@ import { BV_SHOW_MODAL, BV_HIDE_MODAL } from '~/lib/utils/constants';
import { __, s__ } from '~/locale';
import { updateUserStatus } from '~/rest_api';
import EmojiMenuInModal from './emoji_menu_in_modal';
-import { isUserBusy, isValidAvailibility } from './utils';
+import { isUserBusy } from './utils';
const emojiMenuClass = 'js-modal-status-emoji-menu';
export const AVAILABILITY_STATUS = {
@@ -46,7 +46,6 @@ export default {
currentAvailability: {
type: String,
required: false,
- validator: isValidAvailibility,
default: '',
},
canSetUserAvailability: {
diff --git a/app/assets/javascripts/set_status_modal/utils.js b/app/assets/javascripts/set_status_modal/utils.js
index faee4012ef4..e17d95adb25 100644
--- a/app/assets/javascripts/set_status_modal/utils.js
+++ b/app/assets/javascripts/set_status_modal/utils.js
@@ -3,7 +3,5 @@ export const AVAILABILITY_STATUS = {
NOT_SET: 'not_set',
};
-export const isUserBusy = (status) => status === AVAILABILITY_STATUS.BUSY;
-
-export const isValidAvailibility = (availability) =>
- availability.length ? Object.values(AVAILABILITY_STATUS).includes(availability) : true;
+export const isUserBusy = (status = '') =>
+ Boolean(status.length && status.toLowerCase().trim() === AVAILABILITY_STATUS.BUSY);
diff --git a/app/assets/javascripts/sidebar/components/assignees/assignee_avatar_link.vue b/app/assets/javascripts/sidebar/components/assignees/assignee_avatar_link.vue
index fbbe2e341a7..d0a65b48522 100644
--- a/app/assets/javascripts/sidebar/components/assignees/assignee_avatar_link.vue
+++ b/app/assets/javascripts/sidebar/components/assignees/assignee_avatar_link.vue
@@ -1,8 +1,46 @@
<script>
import { GlTooltipDirective, GlLink } from '@gitlab/ui';
import { __, sprintf } from '~/locale';
+import { isUserBusy } from '~/set_status_modal/utils';
import AssigneeAvatar from './assignee_avatar.vue';
+const I18N = {
+ BUSY: __('Busy'),
+ CANNOT_MERGE: __('Cannot merge'),
+ LC_CANNOT_MERGE: __('cannot merge'),
+};
+
+const paranthesize = (str) => `(${str})`;
+
+const generateAssigneeTooltip = ({
+ name,
+ availability,
+ cannotMerge = true,
+ tooltipHasName = false,
+}) => {
+ if (!tooltipHasName) {
+ return cannotMerge ? I18N.CANNOT_MERGE : '';
+ }
+
+ const statusInformation = [];
+ if (availability && isUserBusy(availability)) {
+ statusInformation.push(I18N.BUSY);
+ }
+
+ if (cannotMerge) {
+ statusInformation.push(I18N.LC_CANNOT_MERGE);
+ }
+
+ if (tooltipHasName && statusInformation.length) {
+ return sprintf(__('%{name} %{status}'), {
+ name,
+ status: statusInformation.map(paranthesize).join(' '),
+ });
+ }
+
+ return name;
+};
+
export default {
components: {
AssigneeAvatar,
@@ -37,15 +75,13 @@ export default {
return this.issuableType === 'merge_request' && !this.user.can_merge;
},
tooltipTitle() {
- if (this.cannotMerge && this.tooltipHasName) {
- return sprintf(__('%{userName} (cannot merge)'), { userName: this.user.name });
- } else if (this.cannotMerge) {
- return __('Cannot merge');
- } else if (this.tooltipHasName) {
- return this.user.name;
- }
-
- return '';
+ const { name = '', availability = '' } = this.user;
+ return generateAssigneeTooltip({
+ name,
+ availability,
+ cannotMerge: this.cannotMerge,
+ tooltipHasName: this.tooltipHasName,
+ });
},
tooltipOption() {
return {
diff --git a/app/assets/javascripts/sidebar/components/assignees/assignees.vue b/app/assets/javascripts/sidebar/components/assignees/assignees.vue
index 84e7110e2b2..5dc1ab90e00 100644
--- a/app/assets/javascripts/sidebar/components/assignees/assignees.vue
+++ b/app/assets/javascripts/sidebar/components/assignees/assignees.vue
@@ -36,7 +36,6 @@ export default {
sortedAssigness() {
const canMergeUsers = this.users.filter((user) => user.can_merge);
const canNotMergeUsers = this.users.filter((user) => !user.can_merge);
-
return [...canMergeUsers, ...canNotMergeUsers];
},
},
diff --git a/app/assets/javascripts/sidebar/components/assignees/collapsed_assignee.vue b/app/assets/javascripts/sidebar/components/assignees/collapsed_assignee.vue
index 2f654409561..af4227fa48d 100644
--- a/app/assets/javascripts/sidebar/components/assignees/collapsed_assignee.vue
+++ b/app/assets/javascripts/sidebar/components/assignees/collapsed_assignee.vue
@@ -1,9 +1,11 @@
<script>
import AssigneeAvatar from './assignee_avatar.vue';
+import UserNameWithStatus from './user_name_with_status.vue';
export default {
components: {
AssigneeAvatar,
+ UserNameWithStatus,
},
props: {
user: {
@@ -16,12 +18,20 @@ export default {
default: 'issue',
},
},
+ computed: {
+ availability() {
+ return this.user?.availability || '';
+ },
+ },
};
</script>
-
<template>
<button type="button" class="btn-link">
<assignee-avatar :user="user" :img-size="24" :issuable-type="issuableType" />
- <span class="author"> {{ user.name }} </span>
+ <user-name-with-status
+ :name="user.name"
+ :availability="availability"
+ container-classes="author"
+ />
</button>
</template>
diff --git a/app/assets/javascripts/sidebar/components/assignees/collapsed_assignee_list.vue b/app/assets/javascripts/sidebar/components/assignees/collapsed_assignee_list.vue
index b713b0f960c..20667e695ce 100644
--- a/app/assets/javascripts/sidebar/components/assignees/collapsed_assignee_list.vue
+++ b/app/assets/javascripts/sidebar/components/assignees/collapsed_assignee_list.vue
@@ -1,11 +1,30 @@
<script>
import { GlIcon, GlTooltipDirective } from '@gitlab/ui';
import { __, sprintf } from '~/locale';
+import { isUserBusy } from '~/set_status_modal/utils';
import CollapsedAssignee from './collapsed_assignee.vue';
const DEFAULT_MAX_COUNTER = 99;
const DEFAULT_RENDER_COUNT = 5;
+const generateCollapsedAssigneeTooltip = ({ renderUsers, allUsers, tooltipTitleMergeStatus }) => {
+ const names = renderUsers.map(({ name, availability }) => {
+ if (availability && isUserBusy(availability)) {
+ return sprintf(__('%{name} (Busy)'), { name });
+ }
+ return name;
+ });
+
+ if (!allUsers.length) {
+ return __('Assignee(s)');
+ }
+ if (allUsers.length > names.length) {
+ names.push(sprintf(__('+ %{amount} more'), { amount: allUsers.length - names.length }));
+ }
+ const text = names.join(', ');
+ return tooltipTitleMergeStatus ? `${text} (${tooltipTitleMergeStatus})` : text;
+};
+
export default {
directives: {
GlTooltip: GlTooltipDirective,
@@ -74,19 +93,11 @@ export default {
tooltipTitle() {
const maxRender = Math.min(DEFAULT_RENDER_COUNT, this.users.length);
const renderUsers = this.users.slice(0, maxRender);
- const names = renderUsers.map((u) => u.name);
-
- if (!this.users.length) {
- return __('Assignee(s)');
- }
-
- if (this.users.length > names.length) {
- names.push(sprintf(__('+ %{amount} more'), { amount: this.users.length - names.length }));
- }
-
- const text = names.join(', ');
-
- return this.tooltipTitleMergeStatus ? `${text} (${this.tooltipTitleMergeStatus})` : text;
+ return generateCollapsedAssigneeTooltip({
+ renderUsers,
+ allUsers: this.users,
+ tooltipTitleMergeStatus: this.tooltipTitleMergeStatus,
+ });
},
tooltipOptions() {
diff --git a/app/assets/javascripts/sidebar/components/assignees/uncollapsed_assignee_list.vue b/app/assets/javascripts/sidebar/components/assignees/uncollapsed_assignee_list.vue
index 31d5d7c0077..36775648809 100644
--- a/app/assets/javascripts/sidebar/components/assignees/uncollapsed_assignee_list.vue
+++ b/app/assets/javascripts/sidebar/components/assignees/uncollapsed_assignee_list.vue
@@ -1,12 +1,14 @@
<script>
import { __, sprintf } from '~/locale';
import AssigneeAvatarLink from './assignee_avatar_link.vue';
+import UserNameWithStatus from './user_name_with_status.vue';
const DEFAULT_RENDER_COUNT = 5;
export default {
components: {
AssigneeAvatarLink,
+ UserNameWithStatus,
},
props: {
users: {
@@ -55,6 +57,9 @@ export default {
toggleShowLess() {
this.showLess = !this.showLess;
},
+ userAvailability(u) {
+ return u?.availability || '';
+ },
},
};
</script>
@@ -68,7 +73,7 @@ export default {
:issuable-type="issuableType"
>
<div class="ml-2 gl-line-height-normal">
- <div>{{ firstUser.name }}</div>
+ <user-name-with-status :name="firstUser.name" :availability="userAvailability(firstUser)" />
<div>{{ username }}</div>
</div>
</assignee-avatar-link>
diff --git a/app/assets/javascripts/sidebar/components/assignees/user_name_with_status.vue b/app/assets/javascripts/sidebar/components/assignees/user_name_with_status.vue
new file mode 100644
index 00000000000..41b3b6c9a45
--- /dev/null
+++ b/app/assets/javascripts/sidebar/components/assignees/user_name_with_status.vue
@@ -0,0 +1,40 @@
+<script>
+import { GlSprintf } from '@gitlab/ui';
+import { isUserBusy } from '~/set_status_modal/utils';
+
+export default {
+ name: 'UserNameWithStatus',
+ components: {
+ GlSprintf,
+ },
+ props: {
+ name: {
+ type: String,
+ required: true,
+ },
+ containerClasses: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ availability: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ },
+ computed: {
+ isBusy() {
+ return isUserBusy(this.availability);
+ },
+ },
+};
+</script>
+<template>
+ <span :class="containerClasses">
+ <gl-sprintf v-if="isBusy" :message="s__('UserAvailability|%{author} (Busy)')">
+ <template #author>{{ name }}</template>
+ </gl-sprintf>
+ <template v-else>{{ name }}</template>
+ </span>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/user_popover/user_popover.vue b/app/assets/javascripts/vue_shared/components/user_popover/user_popover.vue
index f121036540e..37bde089de8 100644
--- a/app/assets/javascripts/vue_shared/components/user_popover/user_popover.vue
+++ b/app/assets/javascripts/vue_shared/components/user_popover/user_popover.vue
@@ -6,7 +6,7 @@ import {
GlDeprecatedSkeletonLoading as GlSkeletonLoading,
GlIcon,
} from '@gitlab/ui';
-import UserAvailabilityStatus from '~/set_status_modal/components/user_availability_status.vue';
+import UserNameWithStatus from '~/sidebar/components/assignees/user_name_with_status.vue';
import { glEmojiTag } from '../../../emoji';
import UserAvatarImage from '../user_avatar/user_avatar_image.vue';
@@ -26,7 +26,7 @@ export default {
GlPopover,
GlSkeletonLoading,
UserAvatarImage,
- UserAvailabilityStatus,
+ UserNameWithStatus,
},
props: {
target: {
@@ -66,7 +66,7 @@ export default {
);
},
availabilityStatus() {
- return this.user?.status?.availability || null;
+ return this.user?.status?.availability || '';
},
},
};
@@ -93,11 +93,7 @@ export default {
<template v-else>
<div class="gl-mb-3">
<h5 class="gl-m-0">
- {{ user.name }}
- <user-availability-status
- v-if="availabilityStatus"
- :availability="availabilityStatus"
- />
+ <user-name-with-status :name="user.name" :availability="availabilityStatus" />
</h5>
<span class="gl-text-gray-500">@{{ user.username }}</span>
</div>
diff --git a/app/models/packages/composer/cache_file.rb b/app/models/packages/composer/cache_file.rb
index 92659644b06..ecd7596b989 100644
--- a/app/models/packages/composer/cache_file.rb
+++ b/app/models/packages/composer/cache_file.rb
@@ -16,6 +16,8 @@ module Packages
scope :with_namespace, ->(namespace) { where(namespace: namespace) }
scope :with_sha, ->(sha) { where(file_sha256: sha) }
+ scope :expired, -> { where("delete_at <= ?", Time.current) }
+ scope :without_namespace, -> { where(namespace_id: nil) }
end
end
end
diff --git a/app/services/ci/pipeline_trigger_service.rb b/app/services/ci/pipeline_trigger_service.rb
index a31f5e9056e..dbbaefb2b2f 100644
--- a/app/services/ci/pipeline_trigger_service.rb
+++ b/app/services/ci/pipeline_trigger_service.rb
@@ -17,6 +17,9 @@ module Ci
private
+ PAYLOAD_VARIABLE_KEY = 'TRIGGER_PAYLOAD'
+ PAYLOAD_VARIABLE_HIDDEN_PARAMS = %i(token).freeze
+
def create_pipeline_from_trigger(trigger)
# this check is to not leak the presence of the project if user cannot read it
return unless trigger.project == project
@@ -70,9 +73,23 @@ module Ci
end
def variables
+ if ::Feature.enabled?(:ci_trigger_payload_into_pipeline, project, default_enabled: :yaml)
+ param_variables + [payload_variable]
+ else
+ param_variables
+ end
+ end
+
+ def param_variables
params[:variables].to_h.map do |key, value|
{ key: key, value: value }
end
end
+
+ def payload_variable
+ { key: PAYLOAD_VARIABLE_KEY,
+ value: params.except(*PAYLOAD_VARIABLE_HIDDEN_PARAMS).to_json,
+ variable_type: :file }
+ end
end
end
diff --git a/app/workers/all_queues.yml b/app/workers/all_queues.yml
index 6d4e6de30d9..59ab0a4d05b 100644
--- a/app/workers/all_queues.yml
+++ b/app/workers/all_queues.yml
@@ -267,6 +267,14 @@
:weight: 1
:idempotent:
:tags: []
+- :name: cronjob:packages_composer_cache_cleanup
+ :feature_category: :package_registry
+ :has_external_dependencies:
+ :urgency: :low
+ :resource_boundary: :unknown
+ :weight: 1
+ :idempotent: true
+ :tags: []
- :name: cronjob:pages_domain_removal_cron
:feature_category: :pages
:has_external_dependencies:
diff --git a/app/workers/packages/composer/cache_cleanup_worker.rb b/app/workers/packages/composer/cache_cleanup_worker.rb
new file mode 100644
index 00000000000..638e50e18c4
--- /dev/null
+++ b/app/workers/packages/composer/cache_cleanup_worker.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+module Packages
+ module Composer
+ class CacheCleanupWorker
+ include ApplicationWorker
+ include CronjobQueue # rubocop:disable Scalability/CronWorkerContext
+
+ feature_category :package_registry
+
+ idempotent!
+
+ def perform
+ ::Packages::Composer::CacheFile.without_namespace.find_in_batches do |cache_files|
+ cache_files.each(&:destroy)
+ rescue ActiveRecord::RecordNotFound
+ # ignore. likely due to object already being deleted.
+ end
+
+ ::Packages::Composer::CacheFile.expired.find_in_batches do |cache_files|
+ cache_files.each(&:destroy)
+ rescue ActiveRecord::RecordNotFound
+ # ignore. likely due to object already being deleted.
+ end
+ rescue => e
+ Gitlab::ErrorTracking.log_exception(e)
+ end
+ end
+ end
+end