Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2021-07-13 15:08:38 +00:00
parent 8ce82c1eaf
commit e1189e4c3b
144 changed files with 2132 additions and 556 deletions

View File

@ -7,3 +7,4 @@
/public/
/tmp/
/vendor/
/sitespeed-result/

View File

@ -4,6 +4,7 @@
/public/
/vendor/
/tmp/
/sitespeed-result/
# ignore stylesheets for now as this clashes with our linter
*.css

View File

@ -1 +1 @@
d4ea957f6131538cd78e490a585ea3a455251064
40511f7a14ded77c826809d054d740a66e1c106f

View File

@ -41,7 +41,7 @@ export default {
watch: {
filterParams: {
handler() {
if (this.list.id) {
if (this.list.id && !this.list.collapsed) {
this.fetchItemsForList({ listId: this.list.id });
}
},

View File

@ -240,7 +240,7 @@ export default {
},
updateList: (
{ commit, state: { issuableType } },
{ commit, state: { issuableType, boardItemsByListId = {} }, dispatch },
{ listId, position, collapsed, backupList },
) => {
gqlClient
@ -255,6 +255,12 @@ export default {
.then(({ data }) => {
if (data?.updateBoardList?.errors.length) {
commit(types.UPDATE_LIST_FAILURE, backupList);
return;
}
// Only fetch when board items havent been fetched on a collapsed list
if (!boardItemsByListId[listId]) {
dispatch('fetchItemsForList', { listId });
}
})
.catch(() => {

View File

@ -1,10 +1,65 @@
import { Image } from '@tiptap/extension-image';
import { defaultMarkdownSerializer } from 'prosemirror-markdown/src/to_markdown';
import { VueNodeViewRenderer } from '@tiptap/vue-2';
import { Plugin, PluginKey } from 'prosemirror-state';
import { __ } from '~/locale';
import ImageWrapper from '../components/wrappers/image.vue';
import { uploadFile } from '../services/upload_file';
import { getImageAlt, readFileAsDataURL } from '../services/utils';
export const acceptedMimes = ['image/jpeg', 'image/png', 'image/gif', 'image/jpg'];
const resolveImageEl = (element) =>
element.nodeName === 'IMG' ? element : element.querySelector('img');
const startFileUpload = async ({ editor, file, uploadsPath, renderMarkdown }) => {
const encodedSrc = await readFileAsDataURL(file);
const { view } = editor;
editor.commands.setImage({ uploading: true, src: encodedSrc });
const { state } = view;
const position = state.selection.from - 1;
const { tr } = state;
try {
const { src, canonicalSrc } = await uploadFile({ file, uploadsPath, renderMarkdown });
view.dispatch(
tr.setNodeMarkup(position, undefined, {
uploading: false,
src: encodedSrc,
alt: getImageAlt(src),
canonicalSrc,
}),
);
} catch (e) {
editor.commands.deleteRange({ from: position, to: position + 1 });
editor.emit('error', __('An error occurred while uploading the image. Please try again.'));
}
};
const handleFileEvent = ({ editor, file, uploadsPath, renderMarkdown }) => {
if (acceptedMimes.includes(file?.type)) {
startFileUpload({ editor, file, uploadsPath, renderMarkdown });
return true;
}
return false;
};
const ExtendedImage = Image.extend({
defaultOptions: {
...Image.options,
uploadsPath: null,
renderMarkdown: null,
},
addAttributes() {
return {
...this.parent?.(),
uploading: {
default: false,
},
src: {
default: null,
/*
@ -14,17 +69,25 @@ const ExtendedImage = Image.extend({
* attribute.
*/
parseHTML: (element) => {
const img = element.querySelector('img');
const img = resolveImageEl(element);
return {
src: img.dataset.src || img.getAttribute('src'),
};
},
},
canonicalSrc: {
default: null,
parseHTML: (element) => {
return {
canonicalSrc: element.dataset.canonicalSrc,
};
},
},
alt: {
default: null,
parseHTML: (element) => {
const img = element.querySelector('img');
const img = resolveImageEl(element);
return {
alt: img.getAttribute('alt'),
@ -44,9 +107,58 @@ const ExtendedImage = Image.extend({
},
];
},
addCommands() {
return {
...this.parent(),
uploadImage: ({ file }) => () => {
const { uploadsPath, renderMarkdown } = this.options;
handleFileEvent({ file, uploadsPath, renderMarkdown, editor: this.editor });
},
};
},
addProseMirrorPlugins() {
const { editor } = this;
return [
new Plugin({
key: new PluginKey('handleDropAndPasteImages'),
props: {
handlePaste: (_, event) => {
const { uploadsPath, renderMarkdown } = this.options;
return handleFileEvent({
editor,
file: event.clipboardData.files[0],
uploadsPath,
renderMarkdown,
});
},
handleDrop: (_, event) => {
const { uploadsPath, renderMarkdown } = this.options;
return handleFileEvent({
editor,
file: event.dataTransfer.files[0],
uploadsPath,
renderMarkdown,
});
},
},
}),
];
},
addNodeView() {
return VueNodeViewRenderer(ImageWrapper);
},
});
const serializer = defaultMarkdownSerializer.nodes.image;
const serializer = (state, node) => {
const { alt, canonicalSrc, src, title } = node.attrs;
const quotedTitle = title ? ` ${state.quote(title)}` : '';
state.write(`![${state.esc(alt || '')}](${state.esc(canonicalSrc || src)}${quotedTitle})`);
};
export const configure = ({ renderMarkdown, uploadsPath }) => {
return {

View File

@ -3,3 +3,15 @@ export const hasSelection = (tiptapEditor) => {
return from < to;
};
export const getImageAlt = (src) => {
return src.replace(/^.*\/|\..*$/g, '').replace(/\W+/g, ' ');
};
export const readFileAsDataURL = (file) => {
return new Promise((resolve) => {
const reader = new FileReader();
reader.addEventListener('load', (e) => resolve(e.target.result), { once: true });
reader.readAsDataURL(file);
});
};

View File

@ -1,6 +1,7 @@
<script>
import { GlTooltipDirective, GlIcon, GlLink, GlSafeHtmlDirective } from '@gitlab/ui';
import { ApolloMutation } from 'vue-apollo';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { __ } from '~/locale';
import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
@ -48,6 +49,9 @@ export default {
author() {
return this.note.author;
},
authorId() {
return getIdFromGraphQLId(this.author.id);
},
noteAnchorId() {
return findNoteId(this.note.id);
},
@ -94,7 +98,7 @@ export default {
v-once
:href="author.webUrl"
class="js-user-link"
:data-user-id="author.id"
:data-user-id="authorId"
:data-username="author.username"
>
<span class="note-header-author-name gl-font-weight-bold">{{ author.name }}</span>

View File

@ -97,7 +97,7 @@ export default (resolvers = {}, config = {}) => {
*/
const fetchIntervention = (url, options) => {
return fetch(stripWhitespaceFromQuery(url, path), options);
return fetch(stripWhitespaceFromQuery(url, uri), options);
};
const requestLink = ApolloLink.split(

View File

@ -1,8 +1,7 @@
<script>
import { GlFilteredSearchToken } from '@gitlab/ui';
import { mapState } from 'vuex';
// eslint-disable-next-line import/no-deprecated
import { getParameterByName, setUrlParams, urlParamsToObject } from '~/lib/utils/url_utility';
import { getParameterByName, setUrlParams, queryToObject } from '~/lib/utils/url_utility';
import { s__ } from '~/locale';
import {
SEARCH_TOKEN_TYPE,
@ -68,8 +67,7 @@ export default {
},
},
created() {
// eslint-disable-next-line import/no-deprecated
const query = urlParamsToObject(window.location.search);
const query = queryToObject(window.location.search);
const tokens = this.tokens
.filter((token) => query[token.type])

View File

@ -66,6 +66,7 @@ export default {
data() {
return {
currentFilter: null,
renderSkeleton: !this.shouldShow,
};
},
computed: {
@ -93,7 +94,7 @@ export default {
return this.noteableData.noteableType;
},
allDiscussions() {
if (this.isLoading) {
if (this.renderSkeleton || this.isLoading) {
const prerenderedNotesCount = parseInt(this.notesData.prerenderedNotesCount, 10) || 0;
return new Array(prerenderedNotesCount).fill({
@ -122,6 +123,10 @@ export default {
if (!this.isNotesFetched) {
this.fetchNotes();
}
setTimeout(() => {
this.renderSkeleton = !this.shouldShow;
});
},
discussionTabCounterText(val) {
if (this.discussionsCount) {

View File

@ -74,6 +74,7 @@ const deriveProjectPathFromUrl = ($projectImportUrl) => {
const bindEvents = () => {
const $newProjectForm = $('#new_project');
const $projectImportUrl = $('#project_import_url');
const $projectImportUrlWarning = $('.js-import-url-warning');
const $projectPath = $('.tab-pane.active #project_path');
const $useTemplateBtn = $('.template-button > input');
const $projectFieldsForm = $('.project-fields-form');
@ -134,7 +135,25 @@ const bindEvents = () => {
$projectPath.val($projectPath.val().trim());
});
$projectImportUrl.keyup(() => deriveProjectPathFromUrl($projectImportUrl));
function updateUrlPathWarningVisibility() {
const url = $projectImportUrl.val();
const URL_PATTERN = /(?:git|https?):\/\/.*\/.*\.git$/;
const isUrlValid = URL_PATTERN.test(url);
$projectImportUrlWarning.toggleClass('hide', isUrlValid);
}
let isProjectImportUrlDirty = false;
$projectImportUrl.on('blur', () => {
isProjectImportUrlDirty = true;
updateUrlPathWarningVisibility();
});
$projectImportUrl.on('keyup', () => {
deriveProjectPathFromUrl($projectImportUrl);
// defer error message till first input blur
if (isProjectImportUrlDirty) {
updateUrlPathWarningVisibility();
}
});
$('.js-import-git-toggle-button').on('click', () => {
const $projectMirror = $('#project_mirror');

View File

@ -0,0 +1,51 @@
<script>
import { GlIcon, GlLink } from '@gitlab/ui';
import { numberToHumanSize } from '~/lib/utils/number_utils';
import { sprintf, __ } from '~/locale';
export default {
components: {
GlIcon,
GlLink,
},
props: {
fileName: {
type: String,
required: true,
},
filePath: {
type: String,
required: true,
},
fileSize: {
type: Number,
required: false,
default: 0,
},
},
computed: {
downloadFileSize() {
return numberToHumanSize(this.fileSize);
},
downloadText() {
if (this.fileSize > 0) {
return sprintf(__('Download (%{fileSizeReadable})'), {
fileSizeReadable: this.downloadFileSize,
});
}
return __('Download');
},
},
};
</script>
<template>
<div class="gl-text-center gl-py-13 gl-bg-gray-50">
<gl-link :href="filePath" rel="nofollow" :download="fileName" target="_blank">
<div>
<gl-icon :size="16" name="download" class="gl-text-gray-900" />
</div>
<h4>{{ downloadText }}</h4>
</gl-link>
</div>
</template>

View File

@ -5,8 +5,7 @@ export const loadViewer = (type) => {
case 'text':
return () => import(/* webpackChunkName: 'blob_text_viewer' */ './text_viewer.vue');
case 'download':
// TODO (follow-up): import the download viewer
return null; // () => import(/* webpackChunkName: 'blob_download_viewer' */ './download_viewer.vue');
return () => import(/* webpackChunkName: 'blob_download_viewer' */ './download_viewer.vue');
default:
return null;
}
@ -19,5 +18,10 @@ export const viewerProps = (type, blob) => {
fileName: blob.name,
readOnly: true,
},
download: {
fileName: blob.name,
filePath: blob.rawPath,
fileSize: blob.rawSize,
},
}[type];
};

View File

@ -87,6 +87,12 @@
padding-bottom: $gl-spacing-scale-8;
}
// Will be moved to @gitlab/ui in https://gitlab.com/gitlab-org/gitlab-ui/-/issues/1495
.gl-py-13 {
padding-top: $gl-spacing-scale-13;
padding-bottom: $gl-spacing-scale-13;
}
.gl-transition-property-stroke-opacity {
transition-property: stroke-opacity;
}

View File

@ -325,7 +325,11 @@ module Ci
build.run_after_commit do
build.run_status_commit_hooks!
BuildFinishedWorker.perform_async(id)
if Feature.enabled?(:ci_build_finished_worker_namespace_changed, build.project, default_enabled: :yaml)
Ci::BuildFinishedWorker.perform_async(id)
else
::BuildFinishedWorker.perform_async(id)
end
end
end

View File

@ -11,11 +11,48 @@ module Ci
scope :queued_before, ->(time) { where(arel_table[:created_at].lt(time)) }
def self.upsert_from_build!(build)
entry = self.new(build: build, project: build.project, protected: build.protected?)
entry = self.new(args_from_build(build))
entry.validate!
self.upsert(entry.attributes.compact, returning: %w[build_id], unique_by: :build_id)
end
def self.args_from_build(build)
args = {
build: build,
project: build.project,
protected: build.protected?
}
if Feature.enabled?(:ci_pending_builds_maintain_shared_runners_data, type: :development, default_enabled: :yaml)
args.merge(instance_runners_enabled: shareable?(build))
else
args
end
end
private_class_method :args_from_build
def self.shareable?(build)
shared_runner_enabled?(build) &&
builds_access_level?(build) &&
project_not_removed?(build)
end
private_class_method :shareable?
def self.shared_runner_enabled?(build)
build.project.shared_runners.exists?
end
private_class_method :shared_runner_enabled?
def self.project_not_removed?(build)
!build.project.pending_delete?
end
private_class_method :project_not_removed?
def self.builds_access_level?(build)
build.project.project_feature.builds_access_level.nil? || build.project.project_feature.builds_access_level > 0
end
private_class_method :builds_access_level?
end
end

View File

@ -224,7 +224,7 @@ module Ci
end
after_transition [:created, :waiting_for_resource, :preparing, :pending, :running] => :success do |pipeline|
# We wait a little bit to ensure that all BuildFinishedWorkers finish first
# We wait a little bit to ensure that all Ci::BuildFinishedWorkers finish first
# because this is where some metrics like code coverage is parsed and stored
# in CI build records which the daily build metrics worker relies on.
pipeline.run_after_commit { Ci::DailyBuildGroupReportResultsWorker.perform_in(10.minutes, pipeline.id) }

View File

@ -10,12 +10,12 @@ module PartitionedTable
monthly: Gitlab::Database::Partitioning::MonthlyStrategy
}.freeze
def partitioned_by(partitioning_key, strategy:)
def partitioned_by(partitioning_key, strategy:, **kwargs)
strategy_class = PARTITIONING_STRATEGIES[strategy.to_sym] || raise(ArgumentError, "Unknown partitioning strategy: #{strategy}")
@partitioning_strategy = strategy_class.new(self, partitioning_key)
@partitioning_strategy = strategy_class.new(self, partitioning_key, **kwargs)
Gitlab::Database::Partitioning::PartitionCreator.register(self)
Gitlab::Database::Partitioning::PartitionManager.register(self)
end
end
end

View File

@ -9,7 +9,7 @@ class WebHookLog < ApplicationRecord
self.primary_key = :id
partitioned_by :created_at, strategy: :monthly
partitioned_by :created_at, strategy: :monthly, retain_for: 3.months
belongs_to :web_hook

View File

@ -46,6 +46,7 @@ module Groups
def ensure_allowed_transfer
raise_transfer_error(:group_is_already_root) if group_is_already_root?
raise_transfer_error(:same_parent_as_current) if same_parent?
raise_transfer_error(:has_subscription) if has_subscription?
raise_transfer_error(:invalid_policies) unless valid_policies?
raise_transfer_error(:namespace_with_same_path) if namespace_with_same_path?
raise_transfer_error(:group_contains_images) if group_projects_contain_registry_images?
@ -73,6 +74,10 @@ module Groups
@new_parent_group && @new_parent_group.id == @group.parent_id
end
def has_subscription?
@group.paid?
end
def transfer_to_subgroup?
@new_parent_group && \
@group.self_and_descendants.pluck_primary_key.include?(@new_parent_group.id)

View File

@ -0,0 +1,34 @@
# frozen_string_literal: true
module ServicePing
class PermitDataCategoriesService
STANDARD_CATEGORY = 'Standard'
SUBSCRIPTION_CATEGORY = 'Subscription'
OPERATIONAL_CATEGORY = 'Operational'
OPTIONAL_CATEGORY = 'Optional'
CATEGORIES = [
STANDARD_CATEGORY,
SUBSCRIPTION_CATEGORY,
OPERATIONAL_CATEGORY,
OPTIONAL_CATEGORY
].to_set.freeze
def execute
return [] unless product_intelligence_enabled?
CATEGORIES
end
def product_intelligence_enabled?
pings_enabled? && !User.single_user&.requires_usage_stats_consent?
end
private
def pings_enabled?
::Gitlab::CurrentSettings.usage_ping_enabled?
end
end
end
ServicePing::PermitDataCategoriesService.prepend_mod_with('ServicePing::PermitDataCategoriesService')

View File

@ -18,8 +18,7 @@ module ServicePing
SubmissionError = Class.new(StandardError)
def execute
return unless Gitlab::CurrentSettings.usage_ping_enabled?
return if User.single_user&.requires_usage_stats_consent?
return unless ServicePing::PermitDataCategoriesService.new.product_intelligence_enabled?
usage_data = Gitlab::UsageData.data(force_refresh: true)

View File

@ -24,21 +24,6 @@
"data-bind-in" => "#{'create_chat_team' if Gitlab.config.mattermost.enabled}"
= f.submit s_('GroupSettings|Change group URL'), class: 'btn gl-button btn-warning'
.sub-section
%h4.warning-title= s_('GroupSettings|Transfer group')
= form_for @group, url: transfer_group_path(@group), method: :put, html: { class: 'js-group-transfer-form' } do |f|
.form-group
= dropdown_tag('Select parent group', options: { toggle_class: 'js-groups-dropdown', title: 'Parent Group', filter: true, dropdown_class: 'dropdown-open-top dropdown-group-transfer', placeholder: 'Search groups', data: { data: parent_group_options(@group), qa_selector: 'select_group_dropdown' } })
= hidden_field_tag 'new_parent_group_id'
%ul
- side_effects_link_start = '<a href="https://docs.gitlab.com/ee/user/project/index.html#redirects-when-changing-repository-paths" target="_blank">'.html_safe
- warning_text = s_("GroupSettings|Be careful. Changing a group's parent can have unintended %{side_effects_link_start}side effects%{side_effects_link_end}.") % { side_effects_link_start: side_effects_link_start, side_effects_link_end: '</a>'.html_safe }
%li= warning_text.html_safe
%li= s_('GroupSettings|You can only transfer the group to a group you manage.')
%li= s_('GroupSettings|You will need to update your local repositories to point to the new location.')
%li= s_("GroupSettings|If the parent group's visibility is lower than the group current visibility, visibility levels for subgroups and projects will be changed to match the new parent group's visibility.")
= f.submit s_('GroupSettings|Transfer group'), class: 'btn gl-button btn-warning', data: { qa_selector: "transfer_group_button" }
= render 'groups/settings/transfer', group: @group
= render 'groups/settings/remove', group: @group
= render_if_exists 'groups/settings/restore', group: @group

View File

@ -0,0 +1,22 @@
.sub-section
%h4.warning-title= s_('GroupSettings|Transfer group')
= form_for group, url: transfer_group_path(group), method: :put, html: { class: 'js-group-transfer-form' } do |f|
.form-group
= dropdown_tag('Select parent group', options: { toggle_class: 'js-groups-dropdown', title: 'Parent Group', filter: true, dropdown_class: 'dropdown-open-top dropdown-group-transfer', placeholder: 'Search groups', disabled: group.paid?, data: { data: parent_group_options(group), qa_selector: 'select_group_dropdown' } })
= hidden_field_tag 'new_parent_group_id'
%ul
- side_effects_link_start = '<a href="https://docs.gitlab.com/ee/user/project/index.html#redirects-when-changing-repository-paths" target="_blank">'.html_safe
- warning_text = s_("GroupSettings|Be careful. Changing a group's parent can have unintended %{side_effects_link_start}side effects%{side_effects_link_end}.") % { side_effects_link_start: side_effects_link_start, side_effects_link_end: '</a>'.html_safe }
%li= warning_text.html_safe
%li= s_('GroupSettings|You can only transfer the group to a group you manage.')
%li= s_('GroupSettings|You will need to update your local repositories to point to the new location.')
%li= s_("GroupSettings|If the parent group's visibility is lower than the group current visibility, visibility levels for subgroups and projects will be changed to match the new parent group's visibility.")
- if group.paid?
.gl-alert.gl-alert-info.gl-mb-5{ data: { testid: 'group-to-transfer-has-linked-subscription-alert' } }
= sprite_icon('information-o', size: 16, css_class: 'gl-icon gl-alert-icon gl-alert-icon-no-title')
.gl-alert-body
= html_escape(_("This group can't be transfered because it is linked to a subscription. To transfer this group, %{linkStart}link the subscription%{linkEnd} with a different group.")) % { linkStart: "<a href=\"#{help_page_path('subscriptions/index', anchor: 'change-the-linked-namespace')}\">".html_safe, linkEnd: '</a>'.html_safe }
= f.submit s_('GroupSettings|Transfer group'), class: 'btn gl-button btn-warning', data: { qa_selector: "transfer_group_button" }

View File

@ -14,7 +14,7 @@
.row.mt-3
.col-sm-12
%h1.mb-3.font-weight-normal
= current_appearance&.title.presence || "GitLab"
= current_appearance&.title.presence || _('GitLab')
.row.mb-3
.col-sm-7.order-12.order-sm-1.brand-holder
- unless recently_confirmed_com?

View File

@ -5,6 +5,7 @@
= sprite_icon('document')
%strong
= search_blob_title(project, path)
= copy_file_path_button(path)
- if blob.data
.file-content.code.term{ data: { qa_selector: 'file_text_content' } }
= render 'shared/file_highlight', blob: blob, first_line_number: blob.startline, blob_link: blob_link, highlight_line: blob.highlight_line

View File

@ -8,7 +8,18 @@
= _('Git repository URL')
= f.text_field :import_url, value: import_url.sanitized_url,
autocomplete: 'off', class: 'form-control gl-form-input', placeholder: 'https://gitlab.company.com/group/project.git', required: true
= render 'shared/global_alert',
variant: :warning,
alert_class: 'gl-mt-3 js-import-url-warning hide',
dismissible: false,
close_button_class: 'js-close-2fa-enabled-success-alert' do
.gl-alert-body
= s_('Import|A repository URL usually ends in a .git suffix, although this is not required. Double check to make sure your repository URL is correct.')
.gl-alert.gl-alert-not-dismissible.gl-alert-warning.gl-mt-3.hide#project_import_url_warning
.gl-alert-container
= sprite_icon('warning-solid', css_class: 'gl-icon s16 gl-alert-icon gl-alert-icon-no-title')
.gl-alert-content{ role: 'alert' }
.row
.form-group.col-md-6
= f.label :import_url_user, class: 'label-bold' do

View File

@ -247,6 +247,15 @@
:idempotent: true
:tags:
- :exclude_from_kubernetes
- :name: cronjob:database_partition_management
:worker_name: Database::PartitionManagementWorker
:feature_category: :database
:has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
:idempotent: true
:tags: []
- :name: cronjob:environments_auto_stop_cron
:worker_name: Environments::AutoStopCronWorker
:feature_category: :continuous_delivery
@ -1365,6 +1374,15 @@
:weight: 1
:idempotent:
:tags: []
- :name: pipeline_background:ci_archive_trace
:worker_name: Ci::ArchiveTraceWorker
:feature_category: :continuous_integration
:has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 1
:idempotent:
:tags: []
- :name: pipeline_background:ci_build_trace_chunk_flush
:worker_name: Ci::BuildTraceChunkFlushWorker
:feature_category: :continuous_integration
@ -1585,6 +1603,15 @@
:weight: 5
:idempotent:
:tags: []
- :name: pipeline_processing:ci_build_finished
:worker_name: Ci::BuildFinishedWorker
:feature_category: :continuous_integration
:has_external_dependencies:
:urgency: :high
:resource_boundary: :cpu
:weight: 5
:idempotent:
:tags: []
- :name: pipeline_processing:ci_build_prepare
:worker_name: Ci::BuildPrepareWorker
:feature_category: :continuous_integration

View File

@ -1,16 +1,5 @@
# frozen_string_literal: true
class ArchiveTraceWorker # rubocop:disable Scalability/IdempotentWorker
include ApplicationWorker
sidekiq_options retry: 3
include PipelineBackgroundQueue
# rubocop: disable CodeReuse/ActiveRecord
def perform(job_id)
Ci::Build.without_archived_trace.find_by(id: job_id).try do |job|
Ci::ArchiveTraceService.new.execute(job, worker_name: self.class.name)
end
end
# rubocop: enable CodeReuse/ActiveRecord
class ArchiveTraceWorker < ::Ci::ArchiveTraceWorker # rubocop:disable Scalability/IdempotentWorker
# DEPRECATED: Not triggered since https://gitlab.com/gitlab-org/gitlab/-/merge_requests/64934/
end

View File

@ -1,61 +1,9 @@
# frozen_string_literal: true
class BuildFinishedWorker # rubocop:disable Scalability/IdempotentWorker
include ApplicationWorker
class BuildFinishedWorker < ::Ci::BuildFinishedWorker # rubocop:disable Scalability/IdempotentWorker
# DEPRECATED: Not triggered since https://gitlab.com/gitlab-org/gitlab/-/merge_requests/64934/
sidekiq_options retry: 3
include PipelineQueue
queue_namespace :pipeline_processing
# We need to explicitly specify these settings. They aren't inheriting from the parent class.
urgency :high
worker_resource_boundary :cpu
ARCHIVE_TRACES_IN = 2.minutes.freeze
# rubocop: disable CodeReuse/ActiveRecord
def perform(build_id)
Ci::Build.find_by(id: build_id).try do |build|
process_build(build)
end
end
# rubocop: enable CodeReuse/ActiveRecord
private
# Processes a single CI build that has finished.
#
# This logic resides in a separate method so that EE can extend it more
# easily.
#
# @param [Ci::Build] build The build to process.
def process_build(build)
# We execute these in sync to reduce IO.
build.parse_trace_sections!
build.update_coverage
Ci::BuildReportResultService.new.execute(build)
# We execute these async as these are independent operations.
BuildHooksWorker.perform_async(build.id)
ChatNotificationWorker.perform_async(build.id) if build.pipeline.chat?
if build.failed?
::Ci::MergeRequests::AddTodoWhenBuildFailsWorker.perform_async(build.id)
end
##
# We want to delay sending a build trace to object storage operation to
# validate that this fixes a race condition between this and flushing live
# trace chunks and chunks being removed after consolidation and putting
# them into object storage archive.
#
# TODO This is temporary fix we should improve later, after we validate
# that this is indeed the culprit.
#
# See https://gitlab.com/gitlab-org/gitlab/-/issues/267112 for more
# details.
#
ArchiveTraceWorker.perform_in(ARCHIVE_TRACES_IN, build.id)
end
end
BuildFinishedWorker.prepend_mod_with('BuildFinishedWorker')

View File

@ -0,0 +1,18 @@
# frozen_string_literal: true
module Ci
class ArchiveTraceWorker # rubocop:disable Scalability/IdempotentWorker
include ApplicationWorker
sidekiq_options retry: 3
include PipelineBackgroundQueue
# rubocop: disable CodeReuse/ActiveRecord
def perform(job_id)
Ci::Build.without_archived_trace.find_by(id: job_id).try do |job|
Ci::ArchiveTraceService.new.execute(job, worker_name: self.class.name)
end
end
# rubocop: enable CodeReuse/ActiveRecord
end
end

View File

@ -12,7 +12,7 @@ module Ci
# rubocop: disable CodeReuse/ActiveRecord
def perform
# Archive stale live traces which still resides in redis or database
# This could happen when ArchiveTraceWorker sidekiq jobs were lost by receiving SIGKILL
# This could happen when Ci::ArchiveTraceWorker sidekiq jobs were lost by receiving SIGKILL
# More details in https://gitlab.com/gitlab-org/gitlab-foss/issues/36791
Ci::Build.with_stale_live_trace.find_each(batch_size: 100) do |build|
Ci::ArchiveTraceService.new.execute(build, worker_name: self.class.name)

View File

@ -0,0 +1,71 @@
# frozen_string_literal: true
module Ci
class BuildFinishedWorker # rubocop:disable Scalability/IdempotentWorker
include ApplicationWorker
sidekiq_options retry: 3
include PipelineQueue
queue_namespace :pipeline_processing
urgency :high
worker_resource_boundary :cpu
ARCHIVE_TRACES_IN = 2.minutes.freeze
# rubocop: disable CodeReuse/ActiveRecord
def perform(build_id)
Ci::Build.find_by(id: build_id).try do |build|
process_build(build)
end
end
# rubocop: enable CodeReuse/ActiveRecord
private
# Processes a single CI build that has finished.
#
# This logic resides in a separate method so that EE can extend it more
# easily.
#
# @param [Ci::Build] build The build to process.
def process_build(build)
# We execute these in sync to reduce IO.
build.parse_trace_sections!
build.update_coverage
Ci::BuildReportResultService.new.execute(build)
# We execute these async as these are independent operations.
BuildHooksWorker.perform_async(build.id)
ChatNotificationWorker.perform_async(build.id) if build.pipeline.chat?
if build.failed?
::Ci::MergeRequests::AddTodoWhenBuildFailsWorker.perform_async(build.id)
end
##
# We want to delay sending a build trace to object storage operation to
# validate that this fixes a race condition between this and flushing live
# trace chunks and chunks being removed after consolidation and putting
# them into object storage archive.
#
# TODO This is temporary fix we should improve later, after we validate
# that this is indeed the culprit.
#
# See https://gitlab.com/gitlab-org/gitlab/-/issues/267112 for more
# details.
#
archive_trace_worker_class(build).perform_in(ARCHIVE_TRACES_IN, build.id)
end
def archive_trace_worker_class(build)
if Feature.enabled?(:ci_build_finished_worker_namespace_changed, build.project, default_enabled: :yaml)
Ci::ArchiveTraceWorker
else
::ArchiveTraceWorker
end
end
end
end
Ci::BuildFinishedWorker.prepend_mod_with('Ci::BuildFinishedWorker')

View File

@ -36,25 +36,13 @@ module Gitlab
importer_class.new(object, project, client).execute
increment_counters(project)
Gitlab::GithubImport::ObjectCounter.increment(project, object_type, :imported)
info(project.id, message: 'importer finished')
rescue StandardError => e
error(project.id, e, hash)
end
# Counters incremented:
# - global (prometheus): for metrics in Grafana
# - project (redis): used in FinishImportWorker to report number of objects imported
def increment_counters(project)
counter.increment
Gitlab::GithubImport::ObjectCounter.increment(project, object_type, :imported)
end
def counter
@counter ||= Gitlab::Metrics.counter(counter_name, counter_description)
end
def object_type
raise NotImplementedError
end
@ -70,16 +58,6 @@ module Gitlab
raise NotImplementedError
end
# Returns the name (as a Symbol) of the Prometheus counter.
def counter_name
raise NotImplementedError
end
# Returns the description (as a String) of the Prometheus counter.
def counter_description
raise NotImplementedError
end
private
attr_accessor :github_id

View File

@ -0,0 +1,19 @@
# frozen_string_literal: true
module Database
class PartitionManagementWorker
include ApplicationWorker
sidekiq_options retry: 3
include CronjobQueue # rubocop:disable Scalability/CronWorkerContext
feature_category :database
idempotent!
def perform
Gitlab::Database::Partitioning::PartitionManager.new.sync_partitions
ensure
Gitlab::Database::Partitioning::PartitionMonitoring.new.report_metrics
end
end
end

View File

@ -16,14 +16,6 @@ module Gitlab
def object_type
:diff_note
end
def counter_name
:github_importer_imported_diff_notes
end
def counter_description
'The number of imported GitHub pull request review comments'
end
end
end
end

View File

@ -16,14 +16,6 @@ module Gitlab
def object_type
:issue
end
def counter_name
:github_importer_imported_issues
end
def counter_description
'The number of imported GitHub issues'
end
end
end
end

View File

@ -16,14 +16,6 @@ module Gitlab
def object_type
:lfs_object
end
def counter_name
:github_importer_imported_lfs_objects
end
def counter_description
'The number of imported GitHub Lfs Objects'
end
end
end
end

View File

@ -16,14 +16,6 @@ module Gitlab
def object_type
:note
end
def counter_name
:github_importer_imported_notes
end
def counter_description
'The number of imported GitHub comments'
end
end
end
end

View File

@ -18,14 +18,6 @@ module Gitlab
def object_type
:pull_request_merged_by
end
def counter_name
:github_importer_imported_pull_requests_merged_by
end
def counter_description
'The number of imported GitHub pull requests merged by'
end
end
end
end

View File

@ -18,14 +18,6 @@ module Gitlab
def object_type
:pull_request_review
end
def counter_name
:github_importer_imported_pull_request_reviews
end
def counter_description
'The number of imported GitHub pull request reviews'
end
end
end
end

View File

@ -16,14 +16,6 @@ module Gitlab
def object_type
:pull_request
end
def counter_name
:github_importer_imported_pull_requests
end
def counter_description
'The number of imported GitHub pull requests'
end
end
end
end

View File

@ -10,8 +10,7 @@ class PartitionCreationWorker
idempotent!
def perform
Gitlab::Database::Partitioning::PartitionCreator.new.create_partitions
ensure
Gitlab::Database::Partitioning::PartitionMonitoring.new.report_metrics
# This worker has been removed in favor of Database::PartitionManagementWorker
Database::PartitionManagementWorker.new.perform
end
end

View File

@ -1,8 +1,8 @@
---
name: helm_packages
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/61014
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/331693
milestone: '14.0'
name: ci_build_finished_worker_namespace_changed
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/64934
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/335499
milestone: '14.1'
type: development
group: group::package
group: group::pipeline execution
default_enabled: false

View File

@ -0,0 +1,8 @@
---
name: ci_pending_builds_maintain_shared_runners_data
introduced_by_url:
rollout_issue_url:
milestone: '14.1'
type: development
group: group::pipeline execution
default_enabled: false

View File

@ -0,0 +1,8 @@
---
name: partition_pruning_dry_run
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/65093
rollout_issue_url:
milestone: '14.1'
type: development
group: group::database
default_enabled: false

View File

@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/59763
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/328700
type: development
group: group::runner
default_enabled: false
default_enabled: true
milestone: '13.12'

View File

@ -540,9 +540,9 @@ Settings.cron_jobs['authorized_project_update_periodic_recalculate_worker']['job
Settings.cron_jobs['update_container_registry_info_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['update_container_registry_info_worker']['cron'] ||= '0 0 * * *'
Settings.cron_jobs['update_container_registry_info_worker']['job_class'] = 'UpdateContainerRegistryInfoWorker'
Settings.cron_jobs['postgres_dynamic_partitions_creator'] ||= Settingslogic.new({})
Settings.cron_jobs['postgres_dynamic_partitions_creator']['cron'] ||= '21 */6 * * *'
Settings.cron_jobs['postgres_dynamic_partitions_creator']['job_class'] ||= 'PartitionCreationWorker'
Settings.cron_jobs['postgres_dynamic_partitions_manager'] ||= Settingslogic.new({})
Settings.cron_jobs['postgres_dynamic_partitions_manager']['cron'] ||= '21 */6 * * *'
Settings.cron_jobs['postgres_dynamic_partitions_manager']['job_class'] ||= 'Database::PartitionManagementWorker'
Settings.cron_jobs['ci_platform_metrics_update_cron_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['ci_platform_metrics_update_cron_worker']['cron'] ||= '47 9 * * *'
Settings.cron_jobs['ci_platform_metrics_update_cron_worker']['job_class'] = 'CiPlatformMetricsUpdateCronWorker'

View File

@ -3,15 +3,15 @@
# Make sure we have loaded partitioned models here
# (even with eager loading disabled).
Gitlab::Database::Partitioning::PartitionCreator.register(AuditEvent)
Gitlab::Database::Partitioning::PartitionCreator.register(WebHookLog)
Gitlab::Database::Partitioning::PartitionManager.register(AuditEvent)
Gitlab::Database::Partitioning::PartitionManager.register(WebHookLog)
if Gitlab.ee?
Gitlab::Database::Partitioning::PartitionCreator.register(IncidentManagement::PendingEscalations::Alert)
Gitlab::Database::Partitioning::PartitionManager.register(IncidentManagement::PendingEscalations::Alert)
end
begin
Gitlab::Database::Partitioning::PartitionCreator.new.create_partitions unless ENV['DISABLE_POSTGRES_PARTITION_CREATION_ON_STARTUP']
Gitlab::Database::Partitioning::PartitionManager.new.sync_partitions unless ENV['DISABLE_POSTGRES_PARTITION_CREATION_ON_STARTUP']
rescue ActiveRecord::ActiveRecordError, PG::Error
# ignore - happens when Rake tasks yet have to create a database, e.g. for testing
end

View File

@ -1,7 +1,7 @@
---
data_category: Optional
key_path: counts.ci_runners
description: Total configured Runners in project
description: Total configured Runners of all types
product_section: ops
product_stage: verify
product_group: group::pipeline execution

View File

@ -2,7 +2,7 @@
data_category: Optional
key_path: counts.ci_runners_instance_type_active
name: "count_active_instance_ci_runners"
description: Total active group Runners
description: Total active Shared (Instance) Runners
product_section: ops
product_stage: verify
product_group: group::pipeline execution

View File

@ -2,7 +2,7 @@
data_category: Optional
key_path: counts.ci_runners_group_type_active
name: "count_active_group_ci_runners"
description: Total active instance Runners
description: Total active Group Runners
product_section: ops
product_stage: verify
product_group: group::pipeline execution

View File

@ -2,7 +2,7 @@
data_category: Optional
key_path: counts.ci_runners_project_type_active
name: "count_active_project_ci_runners"
description: Total active project Runners
description: Total active Specific (Project) Runners
product_section: ops
product_stage: verify
product_group: group::pipeline execution

View File

@ -2,7 +2,7 @@
data_category: Optional
key_path: counts.ci_runners_online
name: "counts_online_runners"
description: Total online Runners
description: Total online Runners of all types
product_section: ops
product_stage: verify
product_group: group::pipeline execution

View File

@ -2,7 +2,7 @@
data_category: Optional
key_path: counts.ci_runners_instance_type_active_online
name: "count_instance_active_online_ci_runners"
description: Total active and online instance Runners
description: Total active and online Shared (Instance) Runners
product_section: ops
product_stage: verify
product_group: group::pipeline execution

View File

@ -2,7 +2,7 @@
data_category: Optional
key_path: counts.ci_runners_group_type_active_online
name: "count_group_active_online_ci_runners"
description: Total active and online group Runners
description: Total active and online Group Runners
product_section: ops
product_stage: verify
product_group: group::pipeline execution

View File

@ -2,7 +2,7 @@
data_category: Optional
key_path: counts.ci_runners_project_type_active_online
name: "count_project_active_online_ci_runners"
description: Total active and online project Runners
description: Total active and online Specific (Project) Runners
product_section: ops
product_stage: verify
product_group: group::pipeline execution

View File

@ -0,0 +1,7 @@
{
"type": "array",
"items": {
"type": ["string", "null"],
"enum": ["Standard", "Subscription", "Operational", "Optional"]
}
}

View File

@ -0,0 +1,23 @@
---
key_path: settings.collected_data_categories
name: collected_data_categories
description: List of collected data categories corresponding to instance settings
product_section: growth
product_stage: growth
product_group: group::product intelligence
product_category: collection
value_type: object
status: implemented
milestone: "14.1"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/65336
time_frame: none
data_source: system
data_category: Standard
distribution:
- ce
- ee
tier:
- free
- premium
- ultimate
value_json_schema: 'config/metrics/objects_schemas/collected_data_categories_schema.json'

View File

@ -0,0 +1,19 @@
# frozen_string_literal: true
class AddInstanceRunnersEnabledToCiPendingBuild < ActiveRecord::Migration[6.1]
include Gitlab::Database::MigrationHelpers
disable_ddl_transaction!
def up
with_lock_retries do
add_column :ci_pending_builds, :instance_runners_enabled, :boolean, null: false, default: false
end
end
def down
with_lock_retries do
remove_column :ci_pending_builds, :instance_runners_enabled
end
end
end

View File

@ -0,0 +1 @@
9ba27b5e2599262846a06736db72fb0d31dc904e2ef4d167c1ee9530feb6367f

View File

@ -10833,7 +10833,8 @@ CREATE TABLE ci_pending_builds (
build_id bigint NOT NULL,
project_id bigint NOT NULL,
created_at timestamp with time zone DEFAULT now() NOT NULL,
protected boolean DEFAULT false NOT NULL
protected boolean DEFAULT false NOT NULL,
instance_runners_enabled boolean DEFAULT false NOT NULL
);
CREATE SEQUENCE ci_pending_builds_id_seq

View File

@ -26,6 +26,7 @@ The Package Registry supports the following formats:
<tr><td><a href="https://docs.gitlab.com/ee/user/packages/nuget_repository/index.html">NuGet</a></td><td>12.8+</td></tr>
<tr><td><a href="https://docs.gitlab.com/ee/user/packages/pypi_repository/index.html">PyPI</a></td><td>12.10+</td></tr>
<tr><td><a href="https://docs.gitlab.com/ee/user/packages/generic_packages/index.html">Generic packages</a></td><td>13.5+</td></tr>
<tr><td><a href="https://docs.gitlab.com/ee/user/packages/helm_repository/index.html">Helm Charts</a></td><td>14.1+</td></tr>
</table>
</div>
</div>

View File

@ -26,7 +26,7 @@ GET /projects/:id/packages
| `id` | integer/string | yes | ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) |
| `order_by`| string | no | The field to use as order. One of `created_at` (default), `name`, `version`, or `type`. |
| `sort` | string | no | The direction of the order, either `asc` (default) for ascending order or `desc` for descending order. |
| `package_type` | string | no | Filter the returned packages by type. One of `conan`, `maven`, `npm`, `pypi`, `composer`, `nuget`, or `golang`. (_Introduced in GitLab 12.9_)
| `package_type` | string | no | Filter the returned packages by type. One of `conan`, `maven`, `npm`, `pypi`, `composer`, `nuget`, `helm`, or `golang`. (_Introduced in GitLab 12.9_)
| `package_name` | string | no | Filter the project packages with a fuzzy search by name. (_Introduced in GitLab 12.9_)
| `include_versionless` | boolean | no | When set to true, versionless packages are included in the response. (_Introduced in GitLab 13.8_)
| `status` | string | no | Filter the returned packages by status. One of `default` (default), `hidden`, or `processing`. (_Introduced in GitLab 13.9_)
@ -91,7 +91,7 @@ GET /groups/:id/packages
| `exclude_subgroups` | boolean | false | If the parameter is included as true, packages from projects from subgroups are not listed. Default is `false`. |
| `order_by`| string | no | The field to use as order. One of `created_at` (default), `name`, `version`, `type`, or `project_path`. |
| `sort` | string | no | The direction of the order, either `asc` (default) for ascending order or `desc` for descending order. |
| `package_type` | string | no | Filter the returned packages by type. One of `conan`, `maven`, `npm`, `pypi`, `composer`, `nuget`, or `golang`. (_Introduced in GitLab 12.9_) |
| `package_type` | string | no | Filter the returned packages by type. One of `conan`, `maven`, `npm`, `pypi`, `composer`, `nuget`, `helm`, or `golang`. (_Introduced in GitLab 12.9_) |
| `package_name` | string | no | Filter the project packages with a fuzzy search by name. (_[Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/30980) in GitLab 13.0_)
| `include_versionless` | boolean | no | When set to true, versionless packages are included in the response. (_Introduced in GitLab 13.8_)
| `status` | string | no | Filter the returned packages by status. One of `default` (default), `hidden`, or `processing`. (_Introduced in GitLab 13.9_)

View File

@ -22,23 +22,6 @@ These endpoints do not adhere to the standard API authentication methods.
See the [Helm registry documentation](../../user/packages/helm_repository/index.md)
for details on which headers and token types are supported.
## Enable the Helm API
The Helm API for GitLab is behind a feature flag that is disabled by default. GitLab
administrators with access to the GitLab Rails console can enable this API for your instance.
To enable it:
```ruby
Feature.enable(:helm_packages)
```
To disable it:
```ruby
Feature.disable(:helm_packages)
```
## Download a chart index
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/62757) in GitLab 14.1.

View File

@ -38,6 +38,7 @@ Example response:
{
"conan_max_file_size": 3221225472,
"generic_packages_max_file_size": 5368709120,
"helm_max_file_size": 5242880,
"maven_max_file_size": 3221225472,
"npm_max_file_size": 524288000,
"nuget_max_file_size": 524288000,
@ -59,6 +60,7 @@ PUT /application/plan_limits
| `plan_name` | string | yes | Name of the plan to update. |
| `conan_max_file_size` | integer | no | Maximum Conan package file size in bytes. |
| `generic_packages_max_file_size` | integer | no | Maximum generic package file size in bytes. |
| `helm_max_file_size` | integer | no | Maximum Helm chart file size in bytes. |
| `maven_max_file_size` | integer | no | Maximum Maven package file size in bytes. |
| `npm_max_file_size` | integer | no | Maximum NPM package file size in bytes. |
| `nuget_max_file_size` | integer | no | Maximum NuGet package file size in bytes. |
@ -75,6 +77,7 @@ Example response:
{
"conan_max_file_size": 3221225472,
"generic_packages_max_file_size": 5368709120,
"helm_max_file_size": 5242880,
"maven_max_file_size": 3221225472,
"npm_max_file_size": 524288000,
"nuget_max_file_size": 524288000,

View File

@ -62,6 +62,9 @@ The following guides provide a quick introduction and links to follow on more ad
- Guide on [understanding EXPLAIN plans](../understanding_explain_plans.md).
- [Explaining the unexplainable series in `depesz`](https://www.depesz.com/tag/unexplainable/).
We also have licensed access to The Art of PostgreSQL available, if you are interested in getting access please check out the
[issue (confidential)](https://gitlab.com/gitlab-org/database-team/team-tasks/-/issues/23).
Finally, you can find various guides in the [Database guides](index.md) page that cover more specific
topics and use cases. The most frequently required during database reviewing are the following:

View File

@ -151,7 +151,7 @@ test its execution using `CREATE INDEX CONCURRENTLY` in the `#database-lab` Slac
- Provide a public link to the plan from either:
- [postgres.ai](https://postgres.ai/): Follow the link in `#database-lab` and generate a shareable, public link
by clicking the **Share** button in the upper right corner.
- [explain.depesz.com](https://explain.depesz.com): Paste both the plan and the query used in the form.
- [explain.depesz.com](https://explain.depesz.com) or [explain.dalibo.com](https://explain.dalibo.com): Paste both the plan and the query used in the form.
- When providing query plans, make sure it hits enough data:
- You can use a GitLab production replica to test your queries on a large scale,
through the `#database-lab` Slack channel or through [ChatOps](understanding_explain_plans.md#chatops).

View File

@ -513,6 +513,11 @@ expect(experiment(:example)).to track(:my_event, value: 1, property: '_property_
experiment(:example, :variant_name, foo: :bar).track(:my_event, value: 1, property: '_property_')
```
### Recording and assignment tracking
To test assignment tracking and the `record!` method, you can use or adopt the following
shared example: [tracks assignment and records the subject](https://gitlab.com/gitlab-org/gitlab/blob/master/spec/support/shared_examples/lib/gitlab/experimentation_shared_examples.rb).
## Experiments in the client layer
This is in flux as of GitLab 13.10, and can't be documented just yet.

View File

@ -825,3 +825,5 @@ For more information about the available options, run:
A more extensive guide on understanding query plans can be found in
the [presentation](https://public.dalibo.com/exports/conferences/_archives/_2012/201211_explain/understanding_explain.pdf)
from [Dalibo.org](https://www.dalibo.com/en/).
Depesz's blog also has a good [section](https://www.depesz.com/tag/unexplainable) dedicated to query plans.

View File

@ -666,7 +666,7 @@ Tiers: `free`, `premium`, `ultimate`
### `counts.ci_runners`
Total configured Runners in project
Total configured Runners of all types
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/counts_all/20210216175520_ci_runners.yml)
@ -680,7 +680,7 @@ Tiers: `free`, `premium`, `ultimate`
### `counts.ci_runners_group_type_active`
Total active instance Runners
Total active Group Runners
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/counts_all/20210502050341_ci_runners_group_type_active.yml)
@ -694,7 +694,7 @@ Tiers: `free`, `premium`, `ultimate`
### `counts.ci_runners_group_type_active_online`
Total active and online group Runners
Total active and online Group Runners
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/counts_all/20210502051922_ci_runners_group_type_active_online.yml)
@ -708,7 +708,7 @@ Tiers: `free`, `premium`, `ultimate`
### `counts.ci_runners_instance_type_active`
Total active group Runners
Total active Shared (Instance) Runners
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/counts_all/20210502045402_ci_runners_instance_type_active.yml)
@ -722,7 +722,7 @@ Tiers: `free`, `premium`, `ultimate`
### `counts.ci_runners_instance_type_active_online`
Total active and online instance Runners
Total active and online Shared (Instance) Runners
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/counts_all/20210502051651_ci_runners_instance_type_active_online.yml)
@ -736,7 +736,7 @@ Tiers: `free`, `premium`, `ultimate`
### `counts.ci_runners_online`
Total online Runners
Total online Runners of all types
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/counts_all/20210502050942_ci_runners_online.yml)
@ -750,7 +750,7 @@ Tiers: `free`, `premium`, `ultimate`
### `counts.ci_runners_project_type_active`
Total active project Runners
Total active Specific (Project) Runners
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/counts_all/20210502050834_ci_runners_project_type_active.yml)
@ -764,7 +764,7 @@ Tiers: `free`, `premium`, `ultimate`
### `counts.ci_runners_project_type_active_online`
Total active and online project Runners
Total active and online Specific (Project) Runners
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/counts_all/20210502052036_ci_runners_project_type_active_online.yml)
@ -18316,6 +18316,22 @@ Status: `data_available`
Tiers: `free`, `premium`, `ultimate`
### `settings.collected_data_categories`
List of collected data categories corresponding to instance settings
[Object JSON schema](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/objects_schemas/collected_data_categories_schema.json)
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/settings/20210702140138_collected_data_categories.yml)
Group: `group::product intelligence`
Data Category: `Standard`
Status: `implemented`
Tiers: `free`, `premium`, `ultimate`
### `settings.gitaly_apdex`
Gitaly application performance

View File

@ -275,7 +275,7 @@ Post-processing is currently limited to a project's default branch, see the abov
sequenceDiagram
autonumber
Rails->>+Sidekiq: gl-secret-detection-report.json
Sidekiq-->+Sidekiq: BuildFinishedWorker
Sidekiq-->+Sidekiq: Ci::BuildFinishedWorker
Sidekiq-->+RevocationAPI: GET revocable keys types
RevocationAPI-->>-Sidekiq: OK
Sidekiq->>+RevocationAPI: POST revoke revocable keys

View File

@ -18,24 +18,6 @@ packages whenever you need to use them as a dependency.
For documentation of the specific API endpoints that Helm package manager
clients use, see the [Helm API documentation](../../../api/packages/helm.md).
## Enable the Helm repository feature
Helm repository support is still a work in progress. It's gated behind a feature flag that's
**disabled by default**. [GitLab administrators with access to the GitLab Rails console](../../../administration/feature_flags.md)
can opt to enable it.
To enable it:
```ruby
Feature.enable(:helm_packages)
```
To disable it:
```ruby
Feature.disable(:helm_packages)
```
## Build a Helm package
Creating a Helm package is documented [in the Helm documentation](https://helm.sh/docs/intro/using_helm/#creating-your-own-charts).
@ -73,8 +55,16 @@ Once built, a chart can be uploaded to the `stable` channel with `curl` or `helm
To install the latest version of a chart, use the following command:
```shell
helm repo add project-1 https://gitlab.example.com/api/v4/projects/1/packages/helm/stable
helm repo add --username <username> --password <personal_access_token> project-1 https://gitlab.example.com/api/v4/projects/1/packages/helm/stable
helm install my-release project-1/mychart
```
If the repo has previously been added, you may need to run:
```shell
helm repo update
```
To update the Helm client with the most currently available charts.
See [Using Helm](https://helm.sh/docs/intro/using_helm/) for more information.

View File

@ -35,7 +35,7 @@ For information on how to create and upload a package, view the GitLab documenta
## Use GitLab CI/CD to build packages
You can use [GitLab CI/CD](../../../ci/index.md) to build packages.
For Maven, NuGet, npm, Conan, and PyPI packages, and Composer dependencies, you can
For Maven, NuGet, npm, Conan, Helm, and PyPI packages, and Composer dependencies, you can
authenticate with GitLab by using the `CI_JOB_TOKEN`.
CI/CD templates, which you can use to get started, are in [this repository](https://gitlab.com/gitlab-org/gitlab/-/tree/master/lib/gitlab/ci/templates).

View File

@ -29,10 +29,6 @@ module API
require_packages_enabled!
end
after_validation do
not_found! unless Feature.enabled?(:helm_packages, authorized_user_project)
end
params do
requires :id, type: String, desc: 'The ID or full path of a project'
end

View File

@ -4,16 +4,17 @@ module Gitlab
module Database
module Partitioning
class MonthlyStrategy
attr_reader :model, :partitioning_key
attr_reader :model, :partitioning_key, :retain_for
# We create this many partitions in the future
HEADROOM = 6.months
delegate :table_name, to: :model
def initialize(model, partitioning_key)
def initialize(model, partitioning_key, retain_for: nil)
@model = model
@partitioning_key = partitioning_key
@retain_for = retain_for
end
def current_partitions
@ -27,13 +28,21 @@ module Gitlab
desired_partitions - current_partitions
end
def extra_partitions
current_partitions - desired_partitions
end
private
def desired_partitions
[].tap do |parts|
min_date, max_date = relevant_range
parts << partition_for(upper_bound: min_date)
if pruning_old_partitions? && min_date <= oldest_active_date
min_date = oldest_active_date.beginning_of_month
else
parts << partition_for(upper_bound: min_date)
end
while min_date < max_date
next_date = min_date.next_month
@ -52,13 +61,17 @@ module Gitlab
# to start from MINVALUE to a specific date `x`. The range returned
# does not include the range of the first, half-unbounded partition.
def relevant_range
if first_partition = current_partitions.min
if (first_partition = current_partitions.min)
# Case 1: First partition starts with MINVALUE, i.e. from is nil -> start with first real partition
# Case 2: Rather unexpectedly, first partition does not start with MINVALUE, i.e. from is not nil
# In this case, use first partition beginning as a start
min_date = first_partition.from || first_partition.to
end
if pruning_old_partitions?
min_date ||= oldest_active_date
end
# In case we don't have a partition yet
min_date ||= Date.today
min_date = min_date.beginning_of_month
@ -72,6 +85,14 @@ module Gitlab
TimePartition.new(table_name, lower_bound, upper_bound)
end
def pruning_old_partitions?
Feature.enabled?(:partition_pruning_dry_run) && retain_for.present?
end
def oldest_active_date
(Date.today - retain_for).beginning_of_month
end
def connection
ActiveRecord::Base.connection
end

View File

@ -3,7 +3,7 @@
module Gitlab
module Database
module Partitioning
class PartitionCreator
class PartitionManager
def self.register(model)
raise ArgumentError, "Only models with a #partitioning_strategy can be registered." unless model.respond_to?(:partitioning_strategy)
@ -15,7 +15,7 @@ module Gitlab
end
LEASE_TIMEOUT = 1.minute
LEASE_KEY = 'database_partition_creation_%s'
MANAGEMENT_LEASE_KEY = 'database_partition_management_%s'
attr_reader :models
@ -23,23 +23,25 @@ module Gitlab
@models = models
end
def create_partitions
def sync_partitions
Gitlab::AppLogger.info("Checking state of dynamic postgres partitions")
models.each do |model|
# Double-checking before getting the lease:
# The prevailing situation is no missing partitions
next if missing_partitions(model).empty?
# The prevailing situation is no missing partitions and no extra partitions
next if missing_partitions(model).empty? && extra_partitions(model).empty?
only_with_exclusive_lease(model) do
only_with_exclusive_lease(model, lease_key: MANAGEMENT_LEASE_KEY) do
partitions_to_create = missing_partitions(model)
create(partitions_to_create) unless partitions_to_create.empty?
next if partitions_to_create.empty?
create(model, partitions_to_create)
if Feature.enabled?(:partition_pruning_dry_run)
partitions_to_detach = extra_partitions(model)
detach(partitions_to_detach) unless partitions_to_detach.empty?
end
end
rescue StandardError => e
Gitlab::AppLogger.error("Failed to create partition(s) for #{model.table_name}: #{e.class}: #{e.message}")
Gitlab::AppLogger.error("Failed to create / detach partition(s) for #{model.table_name}: #{e.class}: #{e.message}")
end
end
@ -51,15 +53,22 @@ module Gitlab
model.partitioning_strategy.missing_partitions
end
def only_with_exclusive_lease(model)
lease = Gitlab::ExclusiveLease.new(LEASE_KEY % model.table_name, timeout: LEASE_TIMEOUT)
def extra_partitions(model)
return [] unless Feature.enabled?(:partition_pruning_dry_run)
return [] unless connection.table_exists?(model.table_name)
model.partitioning_strategy.extra_partitions
end
def only_with_exclusive_lease(model, lease_key:)
lease = Gitlab::ExclusiveLease.new(lease_key % model.table_name, timeout: LEASE_TIMEOUT)
yield if lease.try_obtain
ensure
lease&.cancel
end
def create(model, partitions)
def create(partitions)
connection.transaction do
with_lock_retries do
partitions.each do |partition|
@ -71,6 +80,18 @@ module Gitlab
end
end
def detach(partitions)
connection.transaction do
with_lock_retries do
partitions.each { |p| detach_one_partition(p) }
end
end
end
def detach_one_partition(partition)
Gitlab::AppLogger.info("Planning to detach #{partition.partition_name} for table #{partition.table}")
end
def with_lock_retries(&block)
Gitlab::Database::WithLockRetries.new(
klass: self.class,

View File

@ -6,7 +6,7 @@ module Gitlab
class PartitionMonitoring
attr_reader :models
def initialize(models = PartitionCreator.models)
def initialize(models = PartitionManager.models)
@models = models
end

View File

@ -38,7 +38,10 @@ module Gitlab
where('NOT EXISTS (?)', recent_actions)
end
alias_method :reset, :reload
def reset
reload # rubocop:disable Cop/ActiveRecordAssociationReload
clear_memoization(:bloat_size)
end
def bloat_size
strong_memoize(:bloat_size) { bloat_estimate&.bloat_size || 0 }

View File

@ -1,24 +1,24 @@
# frozen_string_literal: true
# Count objects fetched or imported from Github in the context of the
# project being imported.
# Count objects fetched or imported from Github.
module Gitlab
module GithubImport
class ObjectCounter
OPERATIONS = %w[fetched imported].freeze
COUNTER_LIST_KEY = 'github-importer/object-counters-list/%{project}/%{operation}'
COUNTER_KEY = 'github-importer/object-counter/%{project}/%{operation}/%{object_type}'
PROJECT_COUNTER_LIST_KEY = 'github-importer/object-counters-list/%{project}/%{operation}'
PROJECT_COUNTER_KEY = 'github-importer/object-counter/%{project}/%{operation}/%{object_type}'
GLOBAL_COUNTER_KEY = 'github_importer_%{operation}_%{object_type}'
GLOBAL_COUNTER_DESCRIPTION = 'The number of %{operation} Github %{object_type}'
CACHING = Gitlab::Cache::Import::Caching
class << self
def increment(project, object_type, operation)
validate_operation!(operation)
counter_key = COUNTER_KEY % { project: project.id, operation: operation, object_type: object_type }
add_counter_to_list(project, operation, counter_key)
CACHING.increment(counter_key)
increment_project_counter(project, object_type, operation)
increment_global_counter(object_type, operation)
end
def summary(project)
@ -37,12 +37,40 @@ module Gitlab
private
# Global counters are long lived, in Prometheus,
# and it's used to report the health of the Github Importer
# in the Grafana Dashboard
# https://dashboards.gitlab.net/d/2zgM_rImz/github-importer?orgId=1
def increment_global_counter(object_type, operation)
key = GLOBAL_COUNTER_KEY % {
operation: operation,
object_type: object_type
}
description = GLOBAL_COUNTER_DESCRIPTION % {
operation: operation,
object_type: object_type.to_s.humanize
}
Gitlab::Metrics.counter(key.to_sym, description).increment
end
# Project counters are short lived, in Redis,
# and it's used to report how successful a project
# import was with the #summary method.
def increment_project_counter(project, object_type, operation)
counter_key = PROJECT_COUNTER_KEY % { project: project.id, operation: operation, object_type: object_type }
add_counter_to_list(project, operation, counter_key)
CACHING.increment(counter_key)
end
def add_counter_to_list(project, operation, key)
CACHING.set_add(counter_list_key(project, operation), key)
end
def counter_list_key(project, operation)
COUNTER_LIST_KEY % { project: project.id, operation: operation }
PROJECT_COUNTER_LIST_KEY % { project: project.id, operation: operation }
end
def validate_operation!(operation)

View File

@ -0,0 +1,15 @@
# frozen_string_literal: true
module Gitlab
module Usage
module Metrics
module Instrumentations
class CollectedDataCategoriesMetric < GenericMetric
def value
::ServicePing::PermitDataCategoriesService.new.execute
end
end
end
end
end
end

View File

@ -256,7 +256,8 @@ module Gitlab
settings: {
ldap_encrypted_secrets_enabled: alt_usage_data(fallback: nil) { Gitlab::Auth::Ldap::Config.encrypted_secrets.active? },
operating_system: alt_usage_data(fallback: nil) { operating_system },
gitaly_apdex: alt_usage_data { gitaly_apdex }
gitaly_apdex: alt_usage_data { gitaly_apdex },
collected_data_categories: alt_usage_data(fallback: []) { Gitlab::Usage::Metrics::Instrumentations::CollectedDataCategoriesMetric.new(time_frame: 'none').value }
}
}
end

View File

@ -118,7 +118,7 @@ namespace :gitlab do
desc 'Create missing dynamic database partitions'
task create_dynamic_partitions: :environment do
Gitlab::Database::Partitioning::PartitionCreator.new.create_partitions
Gitlab::Database::Partitioning::PartitionManager.new.sync_partitions
end
# This is targeted towards deploys and upgrades of GitLab.

View File

@ -3855,6 +3855,9 @@ msgstr ""
msgid "An error occurred while updating the notification settings. Please try again."
msgstr ""
msgid "An error occurred while uploading the image. Please try again."
msgstr ""
msgid "An error occurred while validating group path"
msgstr ""
@ -11683,6 +11686,9 @@ msgstr ""
msgid "Download %{name} artifact"
msgstr ""
msgid "Download (%{fileSizeReadable})"
msgstr ""
msgid "Download (%{size})"
msgstr ""
@ -13075,9 +13081,6 @@ msgstr ""
msgid "EscalationPolicies|Edit escalation policy"
msgstr ""
msgid "EscalationPolicies|Elapsed time must be greater than or equal to zero."
msgstr ""
msgid "EscalationPolicies|Email on-call user in schedule"
msgstr ""
@ -13096,6 +13099,9 @@ msgstr ""
msgid "EscalationPolicies|IF alert is not %{alertStatus} in %{minutes} minutes"
msgstr ""
msgid "EscalationPolicies|Minutes must be between 0 and 1440."
msgstr ""
msgid "EscalationPolicies|Remove escalation rule"
msgstr ""
@ -16757,6 +16763,9 @@ msgstr[1] ""
msgid "Importing..."
msgstr ""
msgid "Import|A repository URL usually ends in a .git suffix, although this is not required. Double check to make sure your repository URL is correct."
msgstr ""
msgid "Improve customer support with Service Desk"
msgstr ""
@ -33477,6 +33486,9 @@ msgstr ""
msgid "This group can't be removed because it is linked to a subscription. To remove this group, %{linkStart}link the subscription%{linkEnd} with a different group."
msgstr ""
msgid "This group can't be transfered because it is linked to a subscription. To transfer this group, %{linkStart}link the subscription%{linkEnd} with a different group."
msgstr ""
msgid "This group cannot be invited to a project inside a group with enforced SSO"
msgstr ""

View File

@ -157,6 +157,7 @@
"prosemirror-inputrules": "^1.1.3",
"prosemirror-markdown": "^1.5.1",
"prosemirror-model": "^1.13.3",
"prosemirror-state": "^1.3.4",
"raphael": "^2.2.7",
"raw-loader": "^4.0.2",
"scrollparent": "^2.0.1",

View File

@ -24,7 +24,7 @@ gem 'parallel', '~> 1.19'
gem 'rspec-parameterized', '~> 0.4.2'
gem 'github_api', '~> 0.18.2'
gem 'chemlab', '~> 0.5'
gem 'chemlab', '~> 0.7'
gem 'chemlab-library-www-gitlab-com', '~> 0.1'
group :development do

View File

@ -41,18 +41,21 @@ GEM
capybara-screenshot (1.0.23)
capybara (>= 1.0, < 4)
launchy
chemlab (0.5.0)
rake (~> 12.3.0)
selenium-webdriver (~> 3.12)
watir (~> 6.17)
chemlab (0.7.2)
colorize (~> 0.8)
i18n (~> 1.8)
rake (>= 12, < 14)
selenium-webdriver (>= 3, < 5)
watir (>= 6, < 8)
chemlab-library-www-gitlab-com (0.1.1)
chemlab (~> 0.4)
childprocess (4.1.0)
coderay (1.1.2)
colorize (0.8.1)
concord (0.1.5)
adamantium (~> 0.2.0)
equalizer (~> 0.0.9)
concurrent-ruby (1.1.8)
concurrent-ruby (1.1.9)
descendants_tracker (0.0.4)
thread_safe (~> 0.3, >= 0.3.1)
diff-lcs (1.3)
@ -129,7 +132,7 @@ GEM
rack-test (1.1.0)
rack (>= 1.0, < 3)
rake (12.3.3)
regexp_parser (1.6.0)
regexp_parser (1.8.2)
require_all (3.0.0)
rest-client (2.1.0)
http-accept (>= 1.7.0, < 2.0)
@ -163,7 +166,7 @@ GEM
rspec-core (>= 2, < 4, != 2.12.0)
ruby-debug-ide (0.7.2)
rake (>= 0.8.1)
rubyzip (2.3.0)
rubyzip (2.3.2)
selenium-webdriver (4.0.0.beta4)
childprocess (>= 0.5, < 5.0)
rexml (~> 3.2)
@ -186,9 +189,9 @@ GEM
procto (~> 0.0.2)
uuid (2.3.9)
macaddr (~> 1.0)
watir (6.18.0)
watir (6.19.1)
regexp_parser (>= 1.2, < 3)
selenium-webdriver (>= 3.8)
selenium-webdriver (>= 3.142.7)
xpath (3.2.0)
nokogiri (~> 1.8)
zeitwerk (2.4.2)
@ -202,7 +205,7 @@ DEPENDENCIES
allure-rspec (~> 2.14.1)
capybara (~> 3.29.0)
capybara-screenshot (~> 1.0.23)
chemlab (~> 0.5)
chemlab (~> 0.7)
chemlab-library-www-gitlab-com (~> 0.1)
faker (~> 1.6, >= 1.6.6)
github_api (~> 0.18.2)
@ -224,4 +227,4 @@ DEPENDENCIES
timecop (~> 0.9.1)
BUNDLED WITH
2.1.4
2.2.22

View File

@ -38,7 +38,7 @@ module QA
element :project_creation_level_dropdown
end
view 'app/views/groups/settings/_advanced.html.haml' do
view 'app/views/groups/settings/_transfer.html.haml' do
element :select_group_dropdown
element :transfer_group_button
end

View File

@ -179,6 +179,7 @@ module QA
config.browser = Capybara.current_session.driver.browser # reuse Capybara session
config.libraries = [GitlabHandbook]
config.base_url = Runtime::Scenario.attributes[:gitlab_address] # reuse GitLab address
config.hide_banner = true
end
end
# rubocop: enable Metrics/AbcSize

View File

@ -116,6 +116,12 @@ class AutomatedCleanup
delete_helm_releases(releases_to_delete)
end
def perform_stale_namespace_cleanup!(days:)
kubernetes_client = Tooling::KubernetesClient.new(namespace: nil)
kubernetes_client.cleanup_review_app_namespaces(created_before: threshold_time(days: days), wait: false)
end
def perform_stale_pvc_cleanup!(days:)
kubernetes.cleanup_by_created_at(resource_type: 'pvc', created_before: threshold_time(days: days), wait: false)
end
@ -203,6 +209,10 @@ timed('Helm releases cleanup') do
automated_cleanup.perform_helm_releases_cleanup!(days: 7)
end
timed('Stale Namespace cleanup') do
automated_cleanup.perform_stale_namespace_cleanup!(days: 14)
end
timed('Stale PVC cleanup') do
automated_cleanup.perform_stale_pvc_cleanup!(days: 30)
end

View File

@ -5,5 +5,6 @@ FactoryBot.define do
build factory: :ci_build
project
protected { build.protected }
instance_runners_enabled { true }
end
end

View File

@ -5,15 +5,16 @@ require 'spec_helper'
RSpec.describe 'Dropdown assignee', :js do
include FilteredSearchHelpers
let!(:project) { create(:project) }
let!(:user) { create(:user, name: 'administrator', username: 'root') }
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user, name: 'administrator', username: 'root') }
let_it_be(:issue) { create(:issue, project: project) }
let(:js_dropdown_assignee) { '#js-dropdown-assignee' }
let(:filter_dropdown) { find("#{js_dropdown_assignee} .filter-dropdown") }
before do
project.add_maintainer(user)
sign_in(user)
create(:issue, project: project)
visit project_issues_path(project)
end

View File

@ -5,15 +5,16 @@ require 'spec_helper'
RSpec.describe 'Dropdown author', :js do
include FilteredSearchHelpers
let!(:project) { create(:project) }
let!(:user) { create(:user, name: 'administrator', username: 'root') }
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user, name: 'administrator', username: 'root') }
let_it_be(:issue) { create(:issue, project: project) }
let(:js_dropdown_author) { '#js-dropdown-author' }
let(:filter_dropdown) { find("#{js_dropdown_author} .filter-dropdown") }
before do
project.add_maintainer(user)
sign_in(user)
create(:issue, project: project)
visit project_issues_path(project)
end

View File

@ -5,8 +5,10 @@ require 'spec_helper'
RSpec.describe 'Dropdown base', :js do
include FilteredSearchHelpers
let!(:project) { create(:project) }
let!(:user) { create(:user, name: 'administrator', username: 'root') }
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user, name: 'administrator', username: 'root') }
let_it_be(:issue) { create(:issue, project: project) }
let(:filtered_search) { find('.filtered-search') }
let(:js_dropdown_assignee) { '#js-dropdown-assignee' }
let(:filter_dropdown) { find("#{js_dropdown_assignee} .filter-dropdown") }
@ -18,7 +20,6 @@ RSpec.describe 'Dropdown base', :js do
before do
project.add_maintainer(user)
sign_in(user)
create(:issue, project: project)
visit project_issues_path(project)
end

View File

@ -5,10 +5,11 @@ require 'spec_helper'
RSpec.describe 'Dropdown emoji', :js do
include FilteredSearchHelpers
let!(:project) { create(:project, :public) }
let!(:user) { create(:user, name: 'administrator', username: 'root') }
let!(:issue) { create(:issue, project: project) }
let!(:award_emoji_star) { create(:award_emoji, name: 'star', user: user, awardable: issue) }
let_it_be(:project) { create(:project, :public) }
let_it_be(:user) { create(:user, name: 'administrator', username: 'root') }
let_it_be(:issue) { create(:issue, project: project) }
let_it_be(:award_emoji_star) { create(:award_emoji, name: 'star', user: user, awardable: issue) }
let(:filtered_search) { find('.filtered-search') }
let(:js_dropdown_emoji) { '#js-dropdown-my-reaction' }
let(:filter_dropdown) { find("#{js_dropdown_emoji} .filter-dropdown") }

View File

@ -5,8 +5,10 @@ require 'spec_helper'
RSpec.describe 'Dropdown hint', :js do
include FilteredSearchHelpers
let!(:project) { create(:project, :public) }
let!(:user) { create(:user) }
let_it_be(:project) { create(:project, :public) }
let_it_be(:user) { create(:user) }
let_it_be(:issue) { create(:issue, project: project) }
let(:filtered_search) { find('.filtered-search') }
let(:js_dropdown_hint) { '#js-dropdown-hint' }
let(:js_dropdown_operator) { '#js-dropdown-operator' }
@ -21,8 +23,6 @@ RSpec.describe 'Dropdown hint', :js do
before do
project.add_maintainer(user)
create(:issue, project: project)
create(:merge_request, source_project: project, target_project: project)
end
context 'when user not logged in' do

View File

@ -5,22 +5,23 @@ require 'spec_helper'
RSpec.describe 'Dropdown label', :js do
include FilteredSearchHelpers
let(:project) { create(:project) }
let(:user) { create(:user) }
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user) }
let_it_be(:issue) { create(:issue, project: project) }
let_it_be(:label) { create(:label, project: project, title: 'bug-label') }
let(:filtered_search) { find('.filtered-search') }
let(:filter_dropdown) { find('#js-dropdown-label .filter-dropdown') }
before do
project.add_maintainer(user)
sign_in(user)
create(:issue, project: project)
visit project_issues_path(project)
end
describe 'behavior' do
it 'loads all the labels when opened' do
create(:label, project: project, title: 'bug-label')
filtered_search.set('label:=')
expect_filtered_search_dropdown_results(filter_dropdown, 1)

View File

@ -5,10 +5,11 @@ require 'spec_helper'
RSpec.describe 'Dropdown milestone', :js do
include FilteredSearchHelpers
let!(:project) { create(:project) }
let!(:user) { create(:user) }
let!(:milestone) { create(:milestone, title: 'v1.0', project: project) }
let!(:uppercase_milestone) { create(:milestone, title: 'CAP_MILESTONE', project: project) }
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user) }
let_it_be(:milestone) { create(:milestone, title: 'v1.0', project: project) }
let_it_be(:uppercase_milestone) { create(:milestone, title: 'CAP_MILESTONE', project: project) }
let_it_be(:issue) { create(:issue, project: project) }
let(:filtered_search) { find('.filtered-search') }
let(:filter_dropdown) { find('#js-dropdown-milestone .filter-dropdown') }
@ -16,7 +17,6 @@ RSpec.describe 'Dropdown milestone', :js do
before do
project.add_maintainer(user)
sign_in(user)
create(:issue, project: project)
visit project_issues_path(project)
end

View File

@ -5,10 +5,11 @@ require 'spec_helper'
RSpec.describe 'Dropdown release', :js do
include FilteredSearchHelpers
let!(:project) { create(:project, :repository) }
let!(:user) { create(:user) }
let!(:release) { create(:release, tag: 'v1.0', project: project) }
let!(:crazy_release) { create(:release, tag: '☺!/"#%&\'{}+,-.<>;=@]_`{|}🚀', project: project) }
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { create(:user) }
let_it_be(:release) { create(:release, tag: 'v1.0', project: project) }
let_it_be(:crazy_release) { create(:release, tag: '☺!/"#%&\'{}+,-.<>;=@]_`{|}🚀', project: project) }
let_it_be(:issue) { create(:issue, project: project) }
let(:filtered_search) { find('.filtered-search') }
let(:filter_dropdown) { find('#js-dropdown-release .filter-dropdown') }
@ -16,7 +17,6 @@ RSpec.describe 'Dropdown release', :js do
before do
project.add_maintainer(user)
sign_in(user)
create(:issue, project: project)
visit project_issues_path(project)
end

Some files were not shown because too many files have changed in this diff Show More