Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
38eb51cae9
commit
3ab7e70965
103 changed files with 615 additions and 745 deletions
|
@ -18,7 +18,9 @@ import createBoardListMutation from 'ee_else_ce/boards/graphql/board_list_create
|
|||
import issueMoveListMutation from 'ee_else_ce/boards/graphql/issue_move_list.mutation.graphql';
|
||||
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
|
||||
import createGqClient, { fetchPolicies } from '~/lib/graphql';
|
||||
import { convertObjectPropsToCamelCase, urlParamsToObject } from '~/lib/utils/common_utils';
|
||||
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
|
||||
// eslint-disable-next-line import/no-deprecated
|
||||
import { urlParamsToObject } from '~/lib/utils/url_utility';
|
||||
import { s__ } from '~/locale';
|
||||
import {
|
||||
formatBoardLists,
|
||||
|
@ -74,6 +76,7 @@ export default {
|
|||
performSearch({ dispatch }) {
|
||||
dispatch(
|
||||
'setFilters',
|
||||
// eslint-disable-next-line import/no-deprecated
|
||||
convertObjectPropsToCamelCase(urlParamsToObject(window.location.search)),
|
||||
);
|
||||
|
||||
|
|
|
@ -7,13 +7,9 @@ import BoardsStoreEE from 'ee_else_ce/boards/stores/boards_store_ee';
|
|||
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
|
||||
import createDefaultClient from '~/lib/graphql';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import {
|
||||
urlParamsToObject,
|
||||
getUrlParamsArray,
|
||||
parseBoolean,
|
||||
convertObjectPropsToCamelCase,
|
||||
} from '~/lib/utils/common_utils';
|
||||
import { mergeUrlParams } from '~/lib/utils/url_utility';
|
||||
import { parseBoolean, convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
|
||||
// eslint-disable-next-line import/no-deprecated
|
||||
import { mergeUrlParams, urlParamsToObject, getUrlParamsArray } from '~/lib/utils/url_utility';
|
||||
import { ListType, flashAnimationDuration } from '../constants';
|
||||
import eventHub from '../eventhub';
|
||||
import ListAssignee from '../models/assignee';
|
||||
|
@ -601,6 +597,7 @@ const boardsStore = {
|
|||
|
||||
getListIssues(list, emptyIssues = true) {
|
||||
const data = {
|
||||
// eslint-disable-next-line import/no-deprecated
|
||||
...urlParamsToObject(this.filter.path),
|
||||
page: list.page,
|
||||
};
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { last } from 'lodash';
|
||||
import recentSearchesStorageKeys from 'ee_else_ce/filtered_search/recent_searches_storage_keys';
|
||||
import IssuableFilteredSearchTokenKeys from '~/filtered_search/issuable_filtered_search_token_keys';
|
||||
import { getParameterByName, getUrlParamsArray } from '~/lib/utils/common_utils';
|
||||
import { getParameterByName } from '~/lib/utils/common_utils';
|
||||
import {
|
||||
ENTER_KEY_CODE,
|
||||
BACKSPACE_KEY_CODE,
|
||||
|
@ -12,7 +12,7 @@ import {
|
|||
import { __ } from '~/locale';
|
||||
import createFlash from '../flash';
|
||||
import { addClassIfElementExists } from '../lib/utils/dom_utils';
|
||||
import { visitUrl } from '../lib/utils/url_utility';
|
||||
import { visitUrl, getUrlParamsArray } from '../lib/utils/url_utility';
|
||||
import FilteredSearchContainer from './container';
|
||||
import DropdownUtils from './dropdown_utils';
|
||||
import eventHub from './event_hub';
|
||||
|
|
|
@ -125,34 +125,8 @@ const createFlash = function createFlash({
|
|||
return flashContainer;
|
||||
};
|
||||
|
||||
/*
|
||||
* Flash banner supports different types of Flash configurations
|
||||
* along with ability to provide actionConfig which can be used to show
|
||||
* additional action or link on banner next to message
|
||||
*
|
||||
* @param {String} message Flash message text
|
||||
* @param {String} type Type of Flash, it can be `notice`, `success`, `warning` or `alert` (default)
|
||||
* @param {Object} parent Reference to parent element under which Flash needs to appear
|
||||
* @param {Object} actionConfig Map of config to show action on banner
|
||||
* @param {String} href URL to which action config should point to (default: '#')
|
||||
* @param {String} title Title of action
|
||||
* @param {Function} clickHandler Method to call when action is clicked on
|
||||
* @param {Boolean} fadeTransition Boolean to determine whether to fade the alert out
|
||||
*/
|
||||
const deprecatedCreateFlash = function deprecatedCreateFlash(
|
||||
message,
|
||||
type,
|
||||
parent,
|
||||
actionConfig,
|
||||
fadeTransition,
|
||||
addBodyClass,
|
||||
) {
|
||||
return createFlash({ message, type, parent, actionConfig, fadeTransition, addBodyClass });
|
||||
};
|
||||
|
||||
export {
|
||||
createFlash as default,
|
||||
deprecatedCreateFlash,
|
||||
createFlashEl,
|
||||
createAction,
|
||||
hideFlash,
|
||||
|
|
|
@ -8,13 +8,9 @@ import {
|
|||
import { toNumber, omit } from 'lodash';
|
||||
import createFlash from '~/flash';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import {
|
||||
scrollToElement,
|
||||
urlParamsToObject,
|
||||
historyPushState,
|
||||
getParameterByName,
|
||||
} from '~/lib/utils/common_utils';
|
||||
import { setUrlParams } from '~/lib/utils/url_utility';
|
||||
import { scrollToElement, historyPushState, getParameterByName } from '~/lib/utils/common_utils';
|
||||
// eslint-disable-next-line import/no-deprecated
|
||||
import { setUrlParams, urlParamsToObject } from '~/lib/utils/url_utility';
|
||||
import { __ } from '~/locale';
|
||||
import initManualOrdering from '~/manual_ordering';
|
||||
import FilteredSearchBar from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue';
|
||||
|
@ -271,6 +267,7 @@ export default {
|
|||
});
|
||||
},
|
||||
getQueryObject() {
|
||||
// eslint-disable-next-line import/no-deprecated
|
||||
return urlParamsToObject(window.location.search);
|
||||
},
|
||||
onPaginate(newPage) {
|
||||
|
|
|
@ -162,53 +162,6 @@ export const parseUrlPathname = (url) => {
|
|||
return parsedUrl.pathname.charAt(0) === '/' ? parsedUrl.pathname : `/${parsedUrl.pathname}`;
|
||||
};
|
||||
|
||||
const splitPath = (path = '') => path.replace(/^\?/, '').split('&');
|
||||
|
||||
export const urlParamsToArray = (path = '') =>
|
||||
splitPath(path)
|
||||
.filter((param) => param.length > 0)
|
||||
.map((param) => {
|
||||
const split = param.split('=');
|
||||
return [decodeURI(split[0]), split[1]].join('=');
|
||||
});
|
||||
|
||||
export const getUrlParamsArray = () => urlParamsToArray(window.location.search);
|
||||
|
||||
/**
|
||||
* Accepts encoding string which includes query params being
|
||||
* sent to URL.
|
||||
*
|
||||
* @param {string} path Query param string
|
||||
*
|
||||
* @returns {object} Query params object containing key-value pairs
|
||||
* with both key and values decoded into plain string.
|
||||
*/
|
||||
export const urlParamsToObject = (path = '') =>
|
||||
splitPath(path).reduce((dataParam, filterParam) => {
|
||||
if (filterParam === '') {
|
||||
return dataParam;
|
||||
}
|
||||
|
||||
const data = dataParam;
|
||||
let [key, value] = filterParam.split('=');
|
||||
key = /%\w+/g.test(key) ? decodeURIComponent(key) : key;
|
||||
const isArray = key.includes('[]');
|
||||
key = key.replace('[]', '');
|
||||
value = decodeURIComponent(value.replace(/\+/g, ' '));
|
||||
|
||||
if (isArray) {
|
||||
if (!data[key]) {
|
||||
data[key] = [];
|
||||
}
|
||||
|
||||
data[key].push(value);
|
||||
} else {
|
||||
data[key] = value;
|
||||
}
|
||||
|
||||
return data;
|
||||
}, {});
|
||||
|
||||
export const isMetaKey = (e) => e.metaKey || e.ctrlKey || e.altKey || e.shiftKey;
|
||||
|
||||
// Identify following special clicks
|
||||
|
|
|
@ -409,6 +409,55 @@ export function getWebSocketUrl(path) {
|
|||
return `${getWebSocketProtocol()}//${joinPaths(window.location.host, path)}`;
|
||||
}
|
||||
|
||||
const splitPath = (path = '') => path.replace(/^\?/, '').split('&');
|
||||
|
||||
export const urlParamsToArray = (path = '') =>
|
||||
splitPath(path)
|
||||
.filter((param) => param.length > 0)
|
||||
.map((param) => {
|
||||
const split = param.split('=');
|
||||
return [decodeURI(split[0]), split[1]].join('=');
|
||||
});
|
||||
|
||||
export const getUrlParamsArray = () => urlParamsToArray(window.location.search);
|
||||
|
||||
/**
|
||||
* Accepts encoding string which includes query params being
|
||||
* sent to URL.
|
||||
*
|
||||
* @param {string} path Query param string
|
||||
*
|
||||
* @returns {object} Query params object containing key-value pairs
|
||||
* with both key and values decoded into plain string.
|
||||
*
|
||||
* @deprecated Please use `queryToObject(query, { gatherArrays: true });` instead. See https://gitlab.com/gitlab-org/gitlab/-/issues/328845
|
||||
*/
|
||||
export const urlParamsToObject = (path = '') =>
|
||||
splitPath(path).reduce((dataParam, filterParam) => {
|
||||
if (filterParam === '') {
|
||||
return dataParam;
|
||||
}
|
||||
|
||||
const data = dataParam;
|
||||
let [key, value] = filterParam.split('=');
|
||||
key = /%\w+/g.test(key) ? decodeURIComponent(key) : key;
|
||||
const isArray = key.includes('[]');
|
||||
key = key.replace('[]', '');
|
||||
value = decodeURIComponent(value.replace(/\+/g, ' '));
|
||||
|
||||
if (isArray) {
|
||||
if (!data[key]) {
|
||||
data[key] = [];
|
||||
}
|
||||
|
||||
data[key].push(value);
|
||||
} else {
|
||||
data[key] = value;
|
||||
}
|
||||
|
||||
return data;
|
||||
}, {});
|
||||
|
||||
/**
|
||||
* Convert search query into an object
|
||||
*
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
<script>
|
||||
import { GlFilteredSearchToken } from '@gitlab/ui';
|
||||
import { mapState } from 'vuex';
|
||||
import { getParameterByName, urlParamsToObject } from '~/lib/utils/common_utils';
|
||||
import { setUrlParams } from '~/lib/utils/url_utility';
|
||||
import { getParameterByName } from '~/lib/utils/common_utils';
|
||||
// eslint-disable-next-line import/no-deprecated
|
||||
import { setUrlParams, urlParamsToObject } from '~/lib/utils/url_utility';
|
||||
import { s__ } from '~/locale';
|
||||
import { SEARCH_TOKEN_TYPE, SORT_PARAM } from '~/members/constants';
|
||||
import { OPERATOR_IS_ONLY } from '~/vue_shared/components/filtered_search_bar/constants';
|
||||
|
@ -64,6 +65,7 @@ export default {
|
|||
},
|
||||
},
|
||||
created() {
|
||||
// eslint-disable-next-line import/no-deprecated
|
||||
const query = urlParamsToObject(window.location.search);
|
||||
|
||||
const tokens = this.tokens
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
<script>
|
||||
import { GlTabs, GlTab, GlBadge } from '@gitlab/ui';
|
||||
import { mapState } from 'vuex';
|
||||
import { urlParamsToObject } from '~/lib/utils/common_utils';
|
||||
// eslint-disable-next-line import/no-deprecated
|
||||
import { urlParamsToObject } from '~/lib/utils/url_utility';
|
||||
import { __ } from '~/locale';
|
||||
import { MEMBER_TYPES } from '../constants';
|
||||
import MembersApp from './app.vue';
|
||||
|
@ -55,6 +56,7 @@ export default {
|
|||
},
|
||||
}),
|
||||
urlParams() {
|
||||
// eslint-disable-next-line import/no-deprecated
|
||||
return Object.keys(urlParamsToObject(window.location.search));
|
||||
},
|
||||
activeTabIndexCalculatedFromUrlParams() {
|
||||
|
|
|
@ -9,8 +9,8 @@ import {
|
|||
} from '@gitlab/ui';
|
||||
import { debounce } from 'lodash';
|
||||
import { mapState, mapActions } from 'vuex';
|
||||
import { urlParamsToObject } from '~/lib/utils/common_utils';
|
||||
import { redirectTo } from '~/lib/utils/url_utility';
|
||||
// eslint-disable-next-line import/no-deprecated
|
||||
import { redirectTo, urlParamsToObject } from '~/lib/utils/url_utility';
|
||||
import { __ } from '~/locale';
|
||||
|
||||
const tooltipMessage = __('Searching by both author and message is currently not supported.');
|
||||
|
@ -52,6 +52,7 @@ export default {
|
|||
},
|
||||
mounted() {
|
||||
this.fetchAuthors();
|
||||
// eslint-disable-next-line import/no-deprecated
|
||||
const params = urlParamsToObject(window.location.search);
|
||||
const { search: searchParam, author: authorParam } = params;
|
||||
const commitsSearchInput = this.projectCommitsEl.querySelector('#commits-search');
|
||||
|
|
|
@ -2,17 +2,23 @@
|
|||
|
||||
module Integrations
|
||||
class Pivotaltracker < Integration
|
||||
include ActionView::Helpers::UrlHelper
|
||||
API_ENDPOINT = 'https://www.pivotaltracker.com/services/v5/source_commits'
|
||||
|
||||
prop_accessor :token, :restrict_to_branch
|
||||
validates :token, presence: true, if: :activated?
|
||||
|
||||
def title
|
||||
'PivotalTracker'
|
||||
'Pivotal Tracker'
|
||||
end
|
||||
|
||||
def description
|
||||
s_('PivotalTrackerService|Add commit messages as comments to PivotalTracker stories.')
|
||||
s_('PivotalTrackerService|Add commit messages as comments to Pivotal Tracker stories.')
|
||||
end
|
||||
|
||||
def help
|
||||
docs_link = link_to _('Learn more.'), Rails.application.routes.url_helpers.help_page_url('user/project/integrations/pivotal_tracker'), target: '_blank', rel: 'noopener noreferrer'
|
||||
s_('Add commit messages as comments to Pivotal Tracker stories. %{docs_link}').html_safe % { docs_link: docs_link.html_safe }
|
||||
end
|
||||
|
||||
def self.to_param
|
||||
|
@ -24,14 +30,15 @@ module Integrations
|
|||
{
|
||||
type: 'text',
|
||||
name: 'token',
|
||||
placeholder: s_('PivotalTrackerService|Pivotal Tracker API token.'),
|
||||
help: s_('PivotalTrackerService|Pivotal Tracker API token. User must have access to the story. All comments are attributed to this user.'),
|
||||
required: true
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
name: 'restrict_to_branch',
|
||||
placeholder: s_('PivotalTrackerService|Comma-separated list of branches which will be ' \
|
||||
'automatically inspected. Leave blank to include all branches.')
|
||||
title: 'Restrict to branch (optional)',
|
||||
help: s_('PivotalTrackerService|Comma-separated list of branches to ' \
|
||||
'automatically inspect. Leave blank to include all branches.')
|
||||
}
|
||||
]
|
||||
end
|
||||
|
|
|
@ -156,7 +156,7 @@ class Member < ApplicationRecord
|
|||
distinct_members = select('DISTINCT ON (user_id, invite_email) *')
|
||||
.order('user_id, invite_email, access_level DESC, expires_at DESC, created_at ASC')
|
||||
|
||||
from(distinct_members, :members)
|
||||
unscoped.from(distinct_members, :members)
|
||||
end
|
||||
|
||||
scope :order_name_asc, -> { left_join_users.reorder(Gitlab::Database.nulls_last_order('users.name', 'ASC')) }
|
||||
|
|
|
@ -3,19 +3,16 @@
|
|||
%section.settings.no-animate#js-protected-branches-settings{ class: ('expanded' if expanded), data: { qa_selector: 'protected_branches_settings_content' } }
|
||||
.settings-header
|
||||
%h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only
|
||||
Protected branches
|
||||
= s_("ProtectedBranch|Protected branches")
|
||||
%button.btn.gl-button.btn-default.js-settings-toggle.qa-expand-protected-branches{ type: 'button' }
|
||||
= expanded ? 'Collapse' : 'Expand'
|
||||
%p
|
||||
Keep stable branches secure, and force developers to use merge requests. #{link_to "What are protected branches?", help_page_path("user/project/protected_branches")}
|
||||
= s_("ProtectedBranch|Keep stable branches secure and force developers to use merge requests.")
|
||||
= link_to s_("ProtectedBranch|What are protected branches?"), help_page_path("user/project/protected_branches")
|
||||
.settings-content
|
||||
%p
|
||||
By default, protected branches protect your code and:
|
||||
%ul
|
||||
%li Allow only users with Maintainer #{link_to "permissions", help_page_path("user/permissions")} to create new protected branches.
|
||||
%li Allow only users with Maintainer permissions to push code.
|
||||
%li Prevent <strong>anyone</strong> from #{link_to "force-pushing", help_page_path('topics/git/git_rebase', anchor: 'force-push')} to the branch.
|
||||
%li Prevent <strong>anyone</strong> from deleting the branch.
|
||||
= s_("ProtectedBranch|By default, protected branches restrict who can modify the branch.")
|
||||
= link_to s_("ProtectedBranch|Learn more."), help_page_path("user/project/protected_branches", anchor: "who-can-modify-a-protected-branch")
|
||||
|
||||
- if can? current_user, :admin_project, @project
|
||||
= content_for :create_protected_branch
|
||||
|
|
|
@ -3,18 +3,16 @@
|
|||
%section.settings.no-animate#js-protected-tags-settings{ class: ('expanded' if expanded), data: { qa_selector: 'protected_tag_settings_content' } }
|
||||
.settings-header
|
||||
%h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only
|
||||
Protected tags
|
||||
= s_("ProtectedTag|Protected tags")
|
||||
%button.btn.gl-button.btn-default.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? 'Collapse' : 'Expand'
|
||||
%p
|
||||
Limit access to creating and updating tags. #{link_to "What are protected tags?", help_page_path("user/project/protected_tags")}
|
||||
= s_("ProtectedTag|Limit access to creating and updating tags.")
|
||||
= link_to s_("ProtectedTag|What are protected tags?"), help_page_path("user/project/protected_tags")
|
||||
.settings-content
|
||||
%p
|
||||
By default, protected tags protect your code and:
|
||||
%ul
|
||||
%li Allow only users with Maintainer #{link_to "permissions", help_page_path("user/permissions")} to create tags.
|
||||
%li Prevent <strong>anyone</strong> from updating tags.
|
||||
%li Prevent <strong>anyone</strong> from deleting tags.
|
||||
= s_("ProtectedTag|By default, protected branches restrict who can modify the tag.")
|
||||
= link_to s_("ProtectedTag|Learn more."), help_page_path("user/project/protected_tags", anchor: "who-can-modify-a-protected-tag")
|
||||
|
||||
- if can? current_user, :admin_project, @project
|
||||
= yield :create_protected_tag
|
||||
|
|
|
@ -36,16 +36,29 @@ module Gitlab
|
|||
|
||||
importer_class.new(object, project, client).execute
|
||||
|
||||
counter.increment
|
||||
increment_counters(project)
|
||||
|
||||
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
|
||||
|
||||
# Returns the representation class to use for the object. This class must
|
||||
# define the class method `from_json_hash`.
|
||||
def representation_class
|
||||
|
|
|
@ -12,6 +12,7 @@ module WorkerAttributes
|
|||
VALID_URGENCIES = [:high, :low, :throttled].freeze
|
||||
|
||||
VALID_DATA_CONSISTENCIES = [:always, :sticky, :delayed].freeze
|
||||
DEFAULT_DATA_CONSISTENCY = :always
|
||||
|
||||
NAMESPACE_WEIGHTS = {
|
||||
auto_devops: 2,
|
||||
|
@ -110,7 +111,7 @@ module WorkerAttributes
|
|||
end
|
||||
|
||||
def get_data_consistency
|
||||
class_attributes[:data_consistency] || :always
|
||||
class_attributes[:data_consistency] || DEFAULT_DATA_CONSISTENCY
|
||||
end
|
||||
|
||||
def get_data_consistency_feature_flag_enabled?
|
||||
|
|
|
@ -13,6 +13,10 @@ module Gitlab
|
|||
Importer::DiffNoteImporter
|
||||
end
|
||||
|
||||
def object_type
|
||||
:diff_note
|
||||
end
|
||||
|
||||
def counter_name
|
||||
:github_importer_imported_diff_notes
|
||||
end
|
||||
|
|
|
@ -13,6 +13,10 @@ module Gitlab
|
|||
Importer::IssueAndLabelLinksImporter
|
||||
end
|
||||
|
||||
def object_type
|
||||
:issue
|
||||
end
|
||||
|
||||
def counter_name
|
||||
:github_importer_imported_issues
|
||||
end
|
||||
|
|
|
@ -13,6 +13,10 @@ module Gitlab
|
|||
Importer::LfsObjectImporter
|
||||
end
|
||||
|
||||
def object_type
|
||||
:lfs_object
|
||||
end
|
||||
|
||||
def counter_name
|
||||
:github_importer_imported_lfs_objects
|
||||
end
|
||||
|
|
|
@ -13,6 +13,10 @@ module Gitlab
|
|||
Importer::NoteImporter
|
||||
end
|
||||
|
||||
def object_type
|
||||
:note
|
||||
end
|
||||
|
||||
def counter_name
|
||||
:github_importer_imported_notes
|
||||
end
|
||||
|
|
|
@ -15,6 +15,10 @@ module Gitlab
|
|||
Importer::PullRequestMergedByImporter
|
||||
end
|
||||
|
||||
def object_type
|
||||
:pull_request_merged_by
|
||||
end
|
||||
|
||||
def counter_name
|
||||
:github_importer_imported_pull_requests_merged_by
|
||||
end
|
||||
|
|
|
@ -15,6 +15,10 @@ module Gitlab
|
|||
Importer::PullRequestReviewImporter
|
||||
end
|
||||
|
||||
def object_type
|
||||
:pull_request_review
|
||||
end
|
||||
|
||||
def counter_name
|
||||
:github_importer_imported_pull_request_reviews
|
||||
end
|
||||
|
|
|
@ -13,6 +13,10 @@ module Gitlab
|
|||
Importer::PullRequestImporter
|
||||
end
|
||||
|
||||
def object_type
|
||||
:pull_request
|
||||
end
|
||||
|
||||
def counter_name
|
||||
:github_importer_imported_pull_requests
|
||||
end
|
||||
|
|
|
@ -29,7 +29,8 @@ module Gitlab
|
|||
info(
|
||||
project.id,
|
||||
message: "GitHub project import finished",
|
||||
duration_s: duration.round(2)
|
||||
duration_s: duration.round(2),
|
||||
object_counts: ::Gitlab::GithubImport::ObjectCounter.summary(project)
|
||||
)
|
||||
end
|
||||
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
redirect_to: '../../integration/saml.md'
|
||||
remove_date: '2021-06-15'
|
||||
---
|
||||
|
||||
This document was moved to [another location](../../integration/saml.md).
|
||||
|
||||
<!-- This redirect file can be deleted after 2021-06-15>. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page -->
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
redirect_to: '../../geo/replication/remove_geo_site.md'
|
||||
remove_date: '2021-06-01'
|
||||
---
|
||||
|
||||
This document was moved to [another location](../../geo/replication/remove_geo_site.md).
|
||||
|
||||
<!-- This redirect file can be deleted after 2021-06-01 -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page -->
|
|
@ -28,9 +28,9 @@ and all **secondary** nodes:
|
|||
|
||||
1. **Optional:** [Pause replication on each **secondary** node.](../index.md#pausing-and-resuming-replication)
|
||||
1. Log into the **primary** node.
|
||||
1. [Update GitLab on the **primary** node using Omnibus's Geo-specific steps](https://docs.gitlab.com/omnibus/update/README.html#geo-deployment).
|
||||
1. [Update GitLab on the **primary** node using Omnibus](https://docs.gitlab.com/omnibus/update/#update-using-the-official-repositories).
|
||||
1. Log into each **secondary** node.
|
||||
1. [Update GitLab on each **secondary** node using Omnibus's Geo-specific steps](https://docs.gitlab.com/omnibus/update/README.html#geo-deployment).
|
||||
1. [Update GitLab on each **secondary** node using Omnibus](https://docs.gitlab.com/omnibus/update/#update-using-the-official-repositories).
|
||||
1. If you paused replication in step 1, [resume replication on each **secondary**](../index.md#pausing-and-resuming-replication)
|
||||
1. [Test](#check-status-after-updating) **primary** and **secondary** nodes, and check version in each.
|
||||
|
||||
|
|
|
@ -265,7 +265,7 @@ The following metrics are available:
|
|||
| Metric | Type | Since | Description | Labels |
|
||||
|:--------------------------------- |:--------- |:------------------------------------------------------------- |:-------------------------------------- |:--------------------------------------------------------- |
|
||||
| `db_load_balancing_hosts` | Gauge | [12.3](https://gitlab.com/gitlab-org/gitlab/-/issues/13630) | Current number of load balancing hosts | |
|
||||
| `sidekiq_load_balancing_count` | Counter | 13.11 | Sidekiq jobs using load balancing with data consistency set to :sticky or :delayed | `queue`, `boundary`, `external_dependencies`, `feature_category`, `job_status`, `urgency`, `data_consistency`, `database_chosen` |
|
||||
| `sidekiq_load_balancing_count` | Counter | 13.11 | Sidekiq jobs using load balancing with data consistency set to :sticky or :delayed | `queue`, `boundary`, `external_dependencies`, `feature_category`, `job_status`, `urgency`, `data_consistency`, `load_balancing_strategy` |
|
||||
|
||||
## Database partitioning metrics **(PREMIUM SELF)**
|
||||
|
||||
|
|
|
@ -955,13 +955,15 @@ Get Pipeline-Emails service settings for a project.
|
|||
GET /projects/:id/services/pipelines-email
|
||||
```
|
||||
|
||||
## PivotalTracker
|
||||
## Pivotal Tracker
|
||||
|
||||
Project Management Software (Source Commits Endpoint)
|
||||
Add commit messages as comments to Pivotal Tracker stories.
|
||||
|
||||
### Create/Edit PivotalTracker service
|
||||
See also the [Pivotal Tracker service documentation](../user/project/integrations/pivotal_tracker.md).
|
||||
|
||||
Set PivotalTracker service for a project.
|
||||
### Create/Edit Pivotal Tracker service
|
||||
|
||||
Set Pivotal Tracker service for a project.
|
||||
|
||||
```plaintext
|
||||
PUT /projects/:id/services/pivotaltracker
|
||||
|
@ -971,21 +973,21 @@ Parameters:
|
|||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `token` | string | true | The PivotalTracker token |
|
||||
| `token` | string | true | The Pivotal Tracker token |
|
||||
| `restrict_to_branch` | boolean | false | Comma-separated list of branches to automatically inspect. Leave blank to include all branches. |
|
||||
| `push_events` | boolean | false | Enable notifications for push events |
|
||||
|
||||
### Delete PivotalTracker service
|
||||
### Delete Pivotal Tracker service
|
||||
|
||||
Delete PivotalTracker service for a project.
|
||||
Delete Pivotal Tracker service for a project.
|
||||
|
||||
```plaintext
|
||||
DELETE /projects/:id/services/pivotaltracker
|
||||
```
|
||||
|
||||
### Get PivotalTracker service settings
|
||||
### Get Pivotal Tracker service settings
|
||||
|
||||
Get PivotalTracker service settings for a project.
|
||||
Get Pivotal Tracker service settings for a project.
|
||||
|
||||
```plaintext
|
||||
GET /projects/:id/services/pivotaltracker
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
redirect_to: 'index.md'
|
||||
remove_date: '2021-05-01'
|
||||
---
|
||||
|
||||
This document was moved to [another location](index.md).
|
||||
|
||||
<!-- This redirect file can be deleted after 2021-05-01. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page -->
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
redirect_to: 'index.md'
|
||||
remove_date: '2021-05-01'
|
||||
---
|
||||
|
||||
This document was moved to [another location](index.md).
|
||||
|
||||
<!-- This redirect file can be deleted after 2021-05-01. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page -->
|
|
@ -47,7 +47,7 @@ The JWT's payload looks like this:
|
|||
"project_id": "22", #
|
||||
"project_path": "mygroup/myproject", #
|
||||
"user_id": "42", # Id of the user executing the job
|
||||
"user_login": "myuser" # GitLab @username
|
||||
"user_login": "myuser", # GitLab @username
|
||||
"user_email": "myuser@example.com", # Email of the user executing the job
|
||||
"pipeline_id": "1212", #
|
||||
"pipeline_source": "web", # Pipeline source, see: https://docs.gitlab.com/ee/ci/yaml/#common-if-clauses-for-rules
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
redirect_to: 'README.md#contributed-examples'
|
||||
remove_date: '2021-06-01'
|
||||
---
|
||||
|
||||
This document was moved to [another location](README.md#contributed-examples).
|
||||
|
||||
<!-- This redirect file can be deleted after 2021-06-01. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page -->
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
redirect_to: 'README.md#contributed-examples'
|
||||
remove_date: '2021-06-01'
|
||||
---
|
||||
|
||||
This document was moved to [another location](README.md#contributed-examples).
|
||||
|
||||
<!-- This redirect file can be deleted after 2021-06-01. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page -->
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
redirect_to: 'README.md#contributed-examples'
|
||||
remove_date: '2021-05-26'
|
||||
---
|
||||
|
||||
This document was moved to [another location](README.md#contributed-examples).
|
||||
|
||||
<!-- This redirect file can be deleted after 2021-05-26. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page -->
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
redirect_to: 'index.md'
|
||||
remove_date: '2021-05-01'
|
||||
---
|
||||
|
||||
This document was moved to [another location](index.md).
|
||||
|
||||
<!-- This redirect file can be deleted after 2021-05-01. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page -->
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
redirect_to: 'index.md'
|
||||
remove_date: '2021-05-01'
|
||||
---
|
||||
|
||||
This document was moved to [another location](index.md).
|
||||
|
||||
<!-- This redirect file can be deleted after 2021-05-01. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page -->
|
|
@ -37,4 +37,4 @@ For more information about why `gitlab` is used for the `Host`, see
|
|||
You can also use any other Docker image available on [Docker Hub](https://hub.docker.com/u/gitlab).
|
||||
|
||||
The `gitlab` image can accept environment variables. For more details,
|
||||
see the [Omnibus documentation](../../install/README.md).
|
||||
see the [Omnibus documentation](../../install/index.md).
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
redirect_to: 'index.md'
|
||||
remove_date: '2021-05-01'
|
||||
---
|
||||
|
||||
This document was moved to [another location](index.md).
|
||||
|
||||
<!-- This redirect file can be deleted after 2021-05-01. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page -->
|
|
@ -556,6 +556,3 @@ padding. The padding is added around the element, enlarging the screenshot area.
|
|||
#### Live example
|
||||
|
||||
Please use `spec/docs_screenshots/container_registry_docs.rb` as a guide and as an example to create your own scripts.
|
||||
|
||||
<!-- This redirect file can be deleted after February 1, 2021. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page -->
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
redirect_to: 'index.md'
|
||||
remove_date: '2021-06-01'
|
||||
---
|
||||
|
||||
This document was moved to [another location](index.md).
|
||||
|
||||
<!-- This redirect file can be deleted after 2021-06-01. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page -->
|
|
@ -1,9 +1,9 @@
|
|||
---
|
||||
redirect_to: 'https://about.gitlab.com/handbook/product-development-flow/feature-flag-lifecycle/'
|
||||
remove_date: '2021-06-01'
|
||||
remove_date: '2022-03-01'
|
||||
---
|
||||
|
||||
This document was moved to [another location](https://about.gitlab.com/handbook/product-development-flow/feature-flag-lifecycle/).
|
||||
|
||||
<!-- This redirect file can be deleted after 2021-06-01. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page -->
|
||||
<!-- This redirect file can be deleted after 2022-03-01. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page -->
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
redirect_to: '../fe_guide/dependencies.md'
|
||||
remove_date: '2021-05-14'
|
||||
---
|
||||
|
||||
This document was moved to [another location](../fe_guide/dependencies.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2021-05-14>. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page -->
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
redirect_to: 'usage_ping/index.md'
|
||||
remove_date: '2021-05-23'
|
||||
---
|
||||
|
||||
This document was moved to [another location](usage_ping/index.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2021-05-23>. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page -->
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
redirect_to: 'index.md'
|
||||
remove_date: '2021-05-11'
|
||||
---
|
||||
|
||||
This document was moved to [another location](index.md).
|
||||
|
||||
<!-- This redirect file can be deleted after 2021-05-11. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page -->
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
redirect_to: 'index.md'
|
||||
remove_date: '2021-05-11'
|
||||
---
|
||||
|
||||
This document was moved to [another location](index.md).
|
||||
|
||||
<!-- This redirect file can be deleted after 2021-05-11. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page -->
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
redirect_to: '../user/project/working_with_projects.md'
|
||||
remove_date: '2021-05-05'
|
||||
---
|
||||
|
||||
This document was moved to [another location](../user/project/working_with_projects.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2021-05-05>. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page -->
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
redirect_to: '../user/project/working_with_projects.md'
|
||||
remove_date: '2021-05-04'
|
||||
---
|
||||
|
||||
This document was moved to [another location](../user/project/working_with_projects.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2021-05-04>. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page -->
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
redirect_to: 'index.md'
|
||||
remove_date: '2021-05-11'
|
||||
---
|
||||
|
||||
This document was moved to [another location](index.md).
|
||||
|
||||
<!-- This redirect file can be deleted after 2021-05-11. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page -->
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
redirect_to: 'saml.md'
|
||||
remove_date: '2021-06-15'
|
||||
---
|
||||
|
||||
This document was moved to [another location](saml.md).
|
||||
|
||||
<!-- This redirect file can be deleted after 2021-06-15>. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page -->
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
redirect_to: 'index.md'
|
||||
remove_date: '2021-05-11'
|
||||
---
|
||||
|
||||
This document was moved to [another location](index.md).
|
||||
|
||||
<!-- This redirect file can be deleted after 2021-05-11. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page -->
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
redirect_to: 'index.md'
|
||||
remove_date: '2021-05-11'
|
||||
---
|
||||
|
||||
This document was moved to [another location](index.md).
|
||||
|
||||
<!-- This redirect file can be deleted after 2021-05-11. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page -->
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
redirect_to: 'integrations.md'
|
||||
remove_date: '2021-05-03'
|
||||
---
|
||||
|
||||
This document was moved to [another location](integrations.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2021-05-03>. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page -->
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
redirect_to: 'index.md'
|
||||
remove_date: '2021-05-11'
|
||||
---
|
||||
|
||||
This document was moved to [another location](index.md).
|
||||
|
||||
<!-- This redirect file can be deleted after 2021-05-11. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page -->
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
redirect_to: 'cicd_variables.md'
|
||||
remove_date: '2021-05-15'
|
||||
---
|
||||
|
||||
This document was moved to [another location](cicd_variables.md).
|
||||
|
||||
<!-- This redirect file can be deleted after 2021-05-15. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page -->
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
redirect_to: '../topics/index.md'
|
||||
remove_date: '2021-05-11'
|
||||
---
|
||||
|
||||
This document was moved to [another location](../topics/index.md).
|
||||
|
||||
<!-- This redirect file can be deleted after 2021-05-11. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page -->
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
redirect_to: '../../topics/gitlab_flow.md'
|
||||
remove_date: '2021-05-16'
|
||||
---
|
||||
|
||||
This document was moved to [another location](../../topics/gitlab_flow.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2021-05-16>. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page -->
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
redirect_to: '../../../topics/git/cherry_picking.md'
|
||||
remove_date: '2021-06-01'
|
||||
---
|
||||
|
||||
This document was moved to [another location](../../../topics/git/cherry_picking.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2021-06-01>. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page -->
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
redirect_to: '../../../topics/git/tags.md'
|
||||
remove_date: '2021-06-01'
|
||||
---
|
||||
|
||||
This document was moved to [another location](../../../topics/git/tags.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2021-06-01>. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page -->
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
redirect_to: 'index.md'
|
||||
remove_date: '2021-05-11'
|
||||
---
|
||||
|
||||
This document was moved to [another location](index.md).
|
||||
|
||||
<!-- This redirect file can be deleted after 2021-05-11. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page -->
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
redirect_to: '../user_cohorts.md'
|
||||
remove_date: '2021-06-01'
|
||||
---
|
||||
|
||||
This document was moved to [another location](../user_cohorts.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2021-06-01>. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page -->
|
|
@ -38,7 +38,7 @@ The following is an example of the Credentials inventory page:
|
|||
|
||||
If you see a **Revoke** button, you can revoke that user's PAT. Whether you see a **Revoke** button depends on the token state, and if an expiration date has been set. For more information, see the following table:
|
||||
|
||||
| Token state | [Token expiration enforced?](settings/account_and_limit_settings.md#do-not-enforce-personal-access-token-expiration) | Show Revoke button? | Comments |
|
||||
| Token state | [Token expiration enforced?](settings/account_and_limit_settings.md#allow-expired-personal-access-tokens-to-be-used) | Show Revoke button? | Comments |
|
||||
|-------------|------------------------|--------------------|----------------------------------------------------------------------------|
|
||||
| Active | Yes | Yes | Allows administrators to revoke the PAT, such as for a compromised account |
|
||||
| Active | No | Yes | Allows administrators to revoke the PAT, such as for a compromised account |
|
||||
|
|
|
@ -199,7 +199,7 @@ Once a lifetime for personal access tokens is set, GitLab:
|
|||
allowed lifetime. Three hours is given to allow administrators to change the allowed lifetime,
|
||||
or remove it, before revocation takes place.
|
||||
|
||||
## Enforce SSH key expiration **(ULTIMATE SELF)**
|
||||
## Allow expired SSH keys to be used **(ULTIMATE SELF)**
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/250480) in GitLab 13.9.
|
||||
> - [Enabled by default](https://gitlab.com/gitlab-org/gitlab/-/issues/320970) in GitLab 14.0.
|
||||
|
@ -215,15 +215,14 @@ To allow the use of expired SSH keys:
|
|||
|
||||
Disabling SSH key expiration immediately enables all expired SSH keys.
|
||||
|
||||
## Do not enforce Personal Access Token expiration **(ULTIMATE SELF)**
|
||||
## Allow expired Personal Access Tokens to be used **(ULTIMATE SELF)**
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/214723) in GitLab Ultimate 13.1.
|
||||
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/296881) in GitLab 13.9.
|
||||
|
||||
By default, expired personal access tokens (PATs) cannot be used.
|
||||
You can allow the use of expired PATs with the following steps:
|
||||
By default, expired personal access tokens (PATs) **are not usable**.
|
||||
|
||||
To do this:
|
||||
To allow the use of expired PATs:
|
||||
|
||||
1. On the top bar, select **Menu >** **{admin}** **Admin**.
|
||||
1. In the left sidebar, select **Settings > General**.
|
||||
|
|
|
@ -209,7 +209,6 @@ request contains a denied license. For more details, see [Enabling license appro
|
|||
|
||||
Prerequisites:
|
||||
|
||||
- At least one [security scanner job](#security-scanning-tools) must be enabled.
|
||||
- Maintainer or Owner [role](../permissions.md#project-members-permissions).
|
||||
|
||||
For this approval group, you must set the number of approvals required to greater than zero.
|
||||
|
|
|
@ -16,7 +16,7 @@ If you're unable to use [OAuth2](../../api/oauth2.md), you can use a personal ac
|
|||
|
||||
In both cases, you authenticate with a personal access token in place of your password.
|
||||
|
||||
Personal access tokens are required when [Two-Factor Authentication (2FA)](account/two_factor_authentication.md) is enabled.
|
||||
Personal access tokens are required when [Two-Factor Authentication (2FA)](account/two_factor_authentication.md) is enabled.
|
||||
|
||||
For examples of how you can use a personal access token to authenticate with the API, see the [API documentation](../../api/README.md#personalproject-access-tokens).
|
||||
|
||||
|
@ -82,7 +82,7 @@ Personal access tokens expire on the date you define, at midnight UTC.
|
|||
- In GitLab Ultimate, administrators can
|
||||
[limit the lifetime of personal access tokens](../admin_area/settings/account_and_limit_settings.md#limit-the-lifetime-of-personal-access-tokens).
|
||||
- In GitLab Ultimate, administrators can choose whether or not to
|
||||
[enforce personal access token expiration](../admin_area/settings/account_and_limit_settings.md#do-not-enforce-personal-access-token-expiration).
|
||||
[enforce personal access token expiration](../admin_area/settings/account_and_limit_settings.md#allow-expired-personal-access-tokens-to-be-used).
|
||||
|
||||
## Create a personal access token programmatically **(FREE SELF)**
|
||||
|
||||
|
@ -104,10 +104,10 @@ To create a personal access token programmatically:
|
|||
```
|
||||
|
||||
1. Run the following commands to reference the username, the token, and the scopes.
|
||||
|
||||
|
||||
The token must be 20 characters long. The scopes must be valid and are visible
|
||||
[in the source code](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/auth.rb).
|
||||
|
||||
|
||||
For example, to create a token that belongs to a user with username `automation-bot`:
|
||||
|
||||
```ruby
|
||||
|
@ -141,7 +141,7 @@ To revoke a token programmatically:
|
|||
```shell
|
||||
sudo gitlab-rails console
|
||||
```
|
||||
|
||||
|
||||
1. To revoke a token of `token-string-here123`, run the following commands:
|
||||
|
||||
```ruby
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 37 KiB |
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
redirect_to: '../../../integration/jira/jira_cloud_configuration.md'
|
||||
remove_date: '2021-06-18'
|
||||
---
|
||||
|
||||
This document was moved to [another location](../../../integration/jira/jira_cloud_configuration.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2021-06-18>. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page -->
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
redirect_to: '../../../integration/jira/jira_server_configuration.md'
|
||||
remove_date: '2021-06-18'
|
||||
---
|
||||
|
||||
This document was moved to [another location](../../../integration/jira/jira_server_configuration.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2021-06-18>. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page -->
|
|
@ -15,11 +15,9 @@ functionality to GitLab.
|
|||
You can find the available integrations under your project's
|
||||
**Settings > Integrations** page.
|
||||
|
||||
There are more than 20 integrations to integrate with. Click on the one that you
|
||||
There are more than 20 integrations to integrate with. Select the one that you
|
||||
want to configure.
|
||||
|
||||
![Integrations list](img/project_integrations_v13_3.png)
|
||||
|
||||
## Integrations listing
|
||||
|
||||
Click on the service links to see further configuration instructions and details.
|
||||
|
@ -51,7 +49,7 @@ Click on the service links to see further configuration instructions and details
|
|||
| [Microsoft Teams notifications](microsoft_teams.md) | Receive event notifications. | **{dotted-circle}** No |
|
||||
| Packagist | Update your projects. | **{check-circle}** Yes |
|
||||
| Pipelines emails | Send the pipeline status to a list of recipients by email. | **{dotted-circle}** No |
|
||||
| PivotalTracker | Use PivotalTracker as the issue tracker. | **{dotted-circle}** No |
|
||||
| [Pivotal Tracker](pivotal_tracker.md) | Add commit messages as comments to Pivotal Tracker stories. | **{dotted-circle}** No |
|
||||
| [Prometheus](prometheus.md) | Monitor application metrics. | **{dotted-circle}** No |
|
||||
| Pushover | Get real-time notifications on your device. | **{dotted-circle}** No |
|
||||
| [Redmine](redmine.md) | Use Redmine as the issue tracker. | **{dotted-circle}** No |
|
||||
|
|
47
doc/user/project/integrations/pivotal_tracker.md
Normal file
47
doc/user/project/integrations/pivotal_tracker.md
Normal file
|
@ -0,0 +1,47 @@
|
|||
---
|
||||
stage: Create
|
||||
group: Ecosystem
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
# Pivotal Tracker service **(FREE)**
|
||||
|
||||
This service adds commit messages as comments to Pivotal Tracker stories.
|
||||
|
||||
Once enabled, commit messages are checked for square brackets containing a hash mark followed by
|
||||
the story ID (for example, `[#555]`). Every story ID found gets the commit comment added to it.
|
||||
|
||||
You can also close a story with a message containing: `fix [#555]`.
|
||||
You can use any of these words:
|
||||
|
||||
- `fix`
|
||||
- `fixed`
|
||||
- `fixes`
|
||||
- `complete`
|
||||
- `completes`
|
||||
- `completed`
|
||||
- `finish`
|
||||
- `finished`
|
||||
- `finishes`
|
||||
- `delivers`
|
||||
|
||||
Read more about the
|
||||
[Source Commits endpoint](https://www.pivotaltracker.com/help/api/rest/v5#Source_Commits) in
|
||||
the Pivotal Tracker API documentation.
|
||||
|
||||
See also the [Pivotal Tracker service API documentation](../../../api/services.md#pivotal-tracker).
|
||||
|
||||
## Set up Pivotal Tracker
|
||||
|
||||
In Pivotal Tracker, [create an API token](https://www.pivotaltracker.com/help/articles/api_token/).
|
||||
|
||||
Complete these steps in GitLab:
|
||||
|
||||
1. Go to the project you want to configure.
|
||||
1. Go to the [Integrations page](overview.md#accessing-integrations).
|
||||
1. Select **Pivotal Tracker**.
|
||||
1. Ensure that the **Active** toggle is enabled.
|
||||
1. Paste the token you generated in Pivotal Tracker.
|
||||
1. (Optional) To restrict this setting to specific branches, list them in the **Restrict to branch**
|
||||
field, separated with commas.
|
||||
1. Select **Save changes** or optionally select **Test settings**.
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
redirect_to: 'drafts.md'
|
||||
remove_date: '2021-05-19'
|
||||
---
|
||||
|
||||
This document was moved to [another location](drafts.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2021-05-19>. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page -->
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
redirect_to: '../../ci/README.md'
|
||||
remove_date: '2021-06-01'
|
||||
---
|
||||
|
||||
This document is deprecated. See the latest [GitLab CI/CD documentation](../../ci/README.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2021-06-01>. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page -->
|
|
@ -13,24 +13,24 @@ further restrictions on certain branches, they can be protected.
|
|||
|
||||
The default branch for your repository is protected by default.
|
||||
|
||||
## Who can access a protected branch
|
||||
## Who can modify a protected branch
|
||||
|
||||
When a branch is protected, the default behavior enforces
|
||||
these restrictions on the branch.
|
||||
When a branch is protected, the default behavior enforces these restrictions on the branch.
|
||||
|
||||
| Action | Who can do it |
|
||||
|--------------------------|---------------|
|
||||
| Protect a branch | Maintainers only. |
|
||||
| Push to the branch | GitLab administrators and anyone with **Allowed** permission. (*) |
|
||||
| Force push to the branch | No one. |
|
||||
| Delete the branch | No one. |
|
||||
| Action | Who can do it |
|
||||
|:-------------------------|:------------------------------------------------------------------|
|
||||
| Protect a branch | Maintainers only. |
|
||||
| Push to the branch | GitLab administrators and anyone with **Allowed** permission. (1) |
|
||||
| Force push to the branch | No one. |
|
||||
| Delete the branch | No one. |
|
||||
|
||||
(*) Users with the Developer role can create a project in a group,
|
||||
but might not be allowed to initially push to the [default branch](repository/branches/default.md).
|
||||
1. Users with the Developer role can create a project in a group, but might not be allowed to
|
||||
initially push to the [default branch](repository/branches/default.md).
|
||||
|
||||
### Set the default branch protection level
|
||||
|
||||
Administrators can set a default branch protection level in the [Admin Area](../admin_area/settings/visibility_and_access_controls.md#default-branch-protection).
|
||||
Administrators can set a default branch protection level in the
|
||||
[Admin Area](../admin_area/settings/visibility_and_access_controls.md#default-branch-protection).
|
||||
|
||||
## Configure a protected branch
|
||||
|
||||
|
@ -176,10 +176,10 @@ When enabled, members who are can push to this branch can also force push.
|
|||
|
||||
## Require Code Owner approval on a protected branch **(PREMIUM)**
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/13251) in GitLab Premium 12.4.
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/13251) in GitLab Premium 12.4.
|
||||
> - [In](https://gitlab.com/gitlab-org/gitlab/-/issues/35097) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.5 and later, users and groups who can push to protected branches do not have to use a merge request to merge their feature branches. This means they can skip merge request approval rules.
|
||||
|
||||
You can require at least one approval by a
|
||||
[Code Owner](code_owners.md) to a file changed by the
|
||||
You can require at least one approval by a [Code Owner](code_owners.md) to a file changed by the
|
||||
merge request.
|
||||
|
||||
To protect a new branch and enable Code Owner's approval:
|
||||
|
@ -201,9 +201,6 @@ When enabled, all merge requests for these branches require approval
|
|||
by a Code Owner per matched rule before they can be merged.
|
||||
Additionally, direct pushes to the protected branch are denied if a rule is matched.
|
||||
|
||||
[In](https://gitlab.com/gitlab-org/gitlab/-/issues/35097) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.5 and later,
|
||||
users and groups who can push to protected branches do not have to use a merge request to merge their feature branches. Thus, they can skip merge request approval rules.
|
||||
|
||||
## Run pipelines on protected branches
|
||||
|
||||
The permission to merge or push to protected branches defines
|
||||
|
|
|
@ -9,15 +9,24 @@ type: reference, howto
|
|||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/10356) in GitLab 9.1.
|
||||
|
||||
Protected tags allow control over who has permission to create tags as well as preventing accidental update or deletion once created. Each rule allows you to match either an individual tag name, or use wildcards to control multiple tags at once.
|
||||
Protected tags:
|
||||
|
||||
- Allow control over who has permission to create tags.
|
||||
- Prevent accidental update or deletion once created.
|
||||
|
||||
Each rule allows you to match either:
|
||||
|
||||
- An individual tag name.
|
||||
- Wildcards to control multiple tags at once.
|
||||
|
||||
This feature evolved out of [protected branches](protected_branches.md)
|
||||
|
||||
## Overview
|
||||
## Who can modify a protected tag
|
||||
|
||||
Protected tags prevent anyone from updating or deleting the tag, and prevent
|
||||
creation of matching tags based on the permissions you have selected. By default,
|
||||
anyone without Maintainer [permissions](../permissions.md) is prevented from creating tags.
|
||||
By default:
|
||||
|
||||
- To create tags, you must have the [Maintainer role](../permissions.md).
|
||||
- No one can update or delete tags.
|
||||
|
||||
## Configuring protected tags
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ type: reference, howto
|
|||
NOTE:
|
||||
Project access tokens are supported for self-managed instances on Free and above. They are also supported on GitLab SaaS Premium and above (excluding [trial licenses](https://about.gitlab.com/free-trial/)).
|
||||
|
||||
> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/2587) in GitLab 13.0.
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/210181) in GitLab 13.0.
|
||||
> - [Became available on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/issues/235765) in GitLab 13.5 for paid groups only.
|
||||
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/235765) in GitLab 13.5.
|
||||
|
||||
|
@ -36,6 +36,9 @@ For examples of how you can use a project access token to authenticate with the
|
|||
|
||||
## Project bot users
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/210181) in GitLab 13.0.
|
||||
> - [Excluded from license seat use](https://gitlab.com/gitlab-org/gitlab/-/issues/223695) in GitLab 13.5.
|
||||
|
||||
Project bot users are [GitLab-created service accounts](../../../subscriptions/self_managed/index.md#billable-users) and do not count as licensed seats.
|
||||
|
||||
For each project access token created, a bot user is created and added to the project with
|
||||
|
|
|
@ -7,8 +7,21 @@ module Gitlab
|
|||
JobReplicaNotUpToDate = Class.new(StandardError)
|
||||
|
||||
def call(worker, job, _queue)
|
||||
if requires_primary?(worker.class, job)
|
||||
worker_class = worker.class
|
||||
strategy = select_load_balancing_strategy(worker_class, job)
|
||||
|
||||
# This is consumed by ServerMetrics and StructuredLogger to emit metrics so we only
|
||||
# make this available when load-balancing is actually utilized.
|
||||
job['load_balancing_strategy'] = strategy.to_s if load_balancing_available?(worker_class)
|
||||
|
||||
case strategy
|
||||
when :primary, :retry_primary
|
||||
Session.current.use_primary!
|
||||
when :retry_replica
|
||||
raise JobReplicaNotUpToDate, "Sidekiq job #{worker_class} JID-#{job['jid']} couldn't use the replica."\
|
||||
" Replica was not up to date."
|
||||
when :replica
|
||||
# this means we selected an up-to-date replica, but there is nothing to do in this case.
|
||||
end
|
||||
|
||||
yield
|
||||
|
@ -23,31 +36,27 @@ module Gitlab
|
|||
Session.clear_session
|
||||
end
|
||||
|
||||
def requires_primary?(worker_class, job)
|
||||
return true unless worker_class.include?(::ApplicationWorker)
|
||||
return true unless worker_class.utilizes_load_balancing_capabilities?
|
||||
return true unless worker_class.get_data_consistency_feature_flag_enabled?
|
||||
def select_load_balancing_strategy(worker_class, job)
|
||||
return :primary unless load_balancing_available?(worker_class)
|
||||
|
||||
location = job['database_write_location'] || job['database_replica_location']
|
||||
|
||||
return true unless location
|
||||
|
||||
job_data_consistency = worker_class.get_data_consistency
|
||||
job[:data_consistency] = job_data_consistency.to_s
|
||||
return :primary unless location
|
||||
|
||||
if replica_caught_up?(location)
|
||||
job[:database_chosen] = 'replica'
|
||||
false
|
||||
elsif job_data_consistency == :delayed && not_yet_retried?(job)
|
||||
job[:database_chosen] = 'retry'
|
||||
raise JobReplicaNotUpToDate, "Sidekiq job #{worker_class} JID-#{job['jid']} couldn't use the replica."\
|
||||
" Replica was not up to date."
|
||||
:replica
|
||||
elsif worker_class.get_data_consistency == :delayed
|
||||
not_yet_retried?(job) ? :retry_replica : :retry_primary
|
||||
else
|
||||
job[:database_chosen] = 'primary'
|
||||
true
|
||||
:primary
|
||||
end
|
||||
end
|
||||
|
||||
def load_balancing_available?(worker_class)
|
||||
worker_class.include?(::ApplicationWorker) &&
|
||||
worker_class.utilizes_load_balancing_capabilities? &&
|
||||
worker_class.get_data_consistency_feature_flag_enabled?
|
||||
end
|
||||
|
||||
def not_yet_retried?(job)
|
||||
# if `retry_count` is `nil` it indicates that this job was never retried
|
||||
# the `0` indicates that this is a first retry
|
||||
|
|
|
@ -22,6 +22,10 @@ module Gitlab
|
|||
:pull_requests_comments
|
||||
end
|
||||
|
||||
def object_type
|
||||
:diff_note
|
||||
end
|
||||
|
||||
def id_for_already_imported_cache(note)
|
||||
note.id
|
||||
end
|
||||
|
|
|
@ -18,6 +18,10 @@ module Gitlab
|
|||
ImportIssueWorker
|
||||
end
|
||||
|
||||
def object_type
|
||||
:issue
|
||||
end
|
||||
|
||||
def collection_method
|
||||
:issues
|
||||
end
|
||||
|
|
|
@ -18,6 +18,10 @@ module Gitlab
|
|||
ImportLfsObjectWorker
|
||||
end
|
||||
|
||||
def object_type
|
||||
:lfs_object
|
||||
end
|
||||
|
||||
def collection_method
|
||||
:lfs_objects
|
||||
end
|
||||
|
@ -26,6 +30,8 @@ module Gitlab
|
|||
lfs_objects = Projects::LfsPointers::LfsObjectDownloadListService.new(project).execute
|
||||
|
||||
lfs_objects.each do |object|
|
||||
Gitlab::GithubImport::ObjectCounter.increment(project, object_type, :fetched)
|
||||
|
||||
yield object
|
||||
end
|
||||
rescue StandardError => e
|
||||
|
|
|
@ -18,6 +18,10 @@ module Gitlab
|
|||
ImportNoteWorker
|
||||
end
|
||||
|
||||
def object_type
|
||||
:note
|
||||
end
|
||||
|
||||
def collection_method
|
||||
:issues_comments
|
||||
end
|
||||
|
|
|
@ -22,6 +22,10 @@ module Gitlab
|
|||
pr.number
|
||||
end
|
||||
|
||||
def object_type
|
||||
:pull_request
|
||||
end
|
||||
|
||||
def each_object_to_import
|
||||
super do |pr|
|
||||
update_repository if update_repository?(pr)
|
||||
|
|
|
@ -22,6 +22,10 @@ module Gitlab
|
|||
:pull_requests_merged_by
|
||||
end
|
||||
|
||||
def object_type
|
||||
:pull_request_merged_by
|
||||
end
|
||||
|
||||
def id_for_already_imported_cache(merge_request)
|
||||
merge_request.id
|
||||
end
|
||||
|
@ -30,6 +34,8 @@ module Gitlab
|
|||
project.merge_requests.with_state(:merged).find_each do |merge_request|
|
||||
next if already_imported?(merge_request)
|
||||
|
||||
Gitlab::GithubImport::ObjectCounter.increment(project, object_type, :fetched)
|
||||
|
||||
pull_request = client.pull_request(project.import_source, merge_request.iid)
|
||||
yield(pull_request)
|
||||
|
||||
|
|
|
@ -29,6 +29,10 @@ module Gitlab
|
|||
:pull_request_reviews
|
||||
end
|
||||
|
||||
def object_type
|
||||
:pull_request_review
|
||||
end
|
||||
|
||||
def id_for_already_imported_cache(review)
|
||||
review.id
|
||||
end
|
||||
|
@ -57,6 +61,8 @@ module Gitlab
|
|||
project.merge_requests.find_each do |merge_request|
|
||||
next if already_imported?(merge_request)
|
||||
|
||||
Gitlab::GithubImport::ObjectCounter.increment(project, object_type, :fetched)
|
||||
|
||||
client
|
||||
.pull_request_reviews(project.import_source, merge_request.iid)
|
||||
.each do |review|
|
||||
|
@ -81,6 +87,8 @@ module Gitlab
|
|||
page.objects.each do |review|
|
||||
next if already_imported?(review)
|
||||
|
||||
Gitlab::GithubImport::ObjectCounter.increment(project, object_type, :fetched)
|
||||
|
||||
review.merge_request_id = merge_request.id
|
||||
yield(review)
|
||||
|
||||
|
|
56
lib/gitlab/github_import/object_counter.rb
Normal file
56
lib/gitlab/github_import/object_counter.rb
Normal file
|
@ -0,0 +1,56 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# Count objects fetched or imported from Github in the context of the
|
||||
# project being imported.
|
||||
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}'
|
||||
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)
|
||||
end
|
||||
|
||||
def summary(project)
|
||||
OPERATIONS.each_with_object({}) do |operation, result|
|
||||
result[operation] = {}
|
||||
|
||||
CACHING
|
||||
.values_from_set(counter_list_key(project, operation))
|
||||
.sort
|
||||
.each do |counter|
|
||||
object_type = counter.split('/').last
|
||||
result[operation][object_type] = CACHING.read_integer(counter)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
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 }
|
||||
end
|
||||
|
||||
def validate_operation!(operation)
|
||||
unless operation.to_s.presence_in(OPERATIONS)
|
||||
raise ArgumentError, "Operation must be #{OPERATIONS.join(' or ')}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -103,6 +103,8 @@ module Gitlab
|
|||
page.objects.each do |object|
|
||||
next if already_imported?(object)
|
||||
|
||||
Gitlab::GithubImport::ObjectCounter.increment(project, object_type, :fetched)
|
||||
|
||||
yield object
|
||||
|
||||
# We mark the object as imported immediately so we don't end up
|
||||
|
@ -129,6 +131,10 @@ module Gitlab
|
|||
Gitlab::Cache::Import::Caching.set_add(already_imported_cache_key, id)
|
||||
end
|
||||
|
||||
def object_type
|
||||
raise NotImplementedError
|
||||
end
|
||||
|
||||
# Returns the ID to use for the cache used for checking if an object has
|
||||
# already been imported or not.
|
||||
#
|
||||
|
|
|
@ -68,7 +68,7 @@ module Gitlab
|
|||
|
||||
message = base_message(payload)
|
||||
|
||||
payload['database_chosen'] = job[:database_chosen] if job[:database_chosen]
|
||||
payload['load_balancing_strategy'] = job['load_balancing_strategy'] if job['load_balancing_strategy']
|
||||
|
||||
if job_exception
|
||||
payload['message'] = "#{message}: fail: #{payload['duration_s']} sec"
|
||||
|
|
|
@ -74,10 +74,10 @@ module Gitlab
|
|||
@metrics[:sidekiq_elasticsearch_requests_total].increment(labels, get_elasticsearch_calls(instrumentation))
|
||||
@metrics[:sidekiq_elasticsearch_requests_duration_seconds].observe(labels, get_elasticsearch_time(instrumentation))
|
||||
|
||||
if ::Gitlab::Database::LoadBalancing.enable? && job[:database_chosen]
|
||||
with_load_balancing_settings(job) do |settings|
|
||||
load_balancing_labels = {
|
||||
database_chosen: job[:database_chosen],
|
||||
data_consistency: job[:data_consistency]
|
||||
load_balancing_strategy: settings['load_balancing_strategy'],
|
||||
data_consistency: settings['worker_data_consistency']
|
||||
}
|
||||
|
||||
@metrics[:sidekiq_load_balancing_count].increment(labels.merge(load_balancing_labels), 1)
|
||||
|
@ -105,6 +105,15 @@ module Gitlab
|
|||
|
||||
private
|
||||
|
||||
def with_load_balancing_settings(job)
|
||||
return unless ::Gitlab::Database::LoadBalancing.enable?
|
||||
|
||||
keys = %w[load_balancing_strategy worker_data_consistency]
|
||||
return unless keys.all? { |k| job.key?(k) }
|
||||
|
||||
yield job.slice(*keys)
|
||||
end
|
||||
|
||||
def get_thread_cputime
|
||||
defined?(Process::CLOCK_THREAD_CPUTIME_ID) ? Process.clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID) : 0
|
||||
end
|
||||
|
|
|
@ -1984,6 +1984,9 @@ msgstr ""
|
|||
msgid "Add commit messages as comments to Asana tasks. %{docs_link}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Add commit messages as comments to Pivotal Tracker stories. %{docs_link}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Add deploy freeze"
|
||||
msgstr ""
|
||||
|
||||
|
@ -24239,13 +24242,13 @@ msgstr ""
|
|||
msgid "Pipeline|with stages"
|
||||
msgstr ""
|
||||
|
||||
msgid "PivotalTrackerService|Add commit messages as comments to PivotalTracker stories."
|
||||
msgid "PivotalTrackerService|Add commit messages as comments to Pivotal Tracker stories."
|
||||
msgstr ""
|
||||
|
||||
msgid "PivotalTrackerService|Comma-separated list of branches which will be automatically inspected. Leave blank to include all branches."
|
||||
msgid "PivotalTrackerService|Comma-separated list of branches to automatically inspect. Leave blank to include all branches."
|
||||
msgstr ""
|
||||
|
||||
msgid "PivotalTrackerService|Pivotal Tracker API token."
|
||||
msgid "PivotalTrackerService|Pivotal Tracker API token. User must have access to the story. All comments are attributed to this user."
|
||||
msgstr ""
|
||||
|
||||
msgid "Plain diff"
|
||||
|
@ -26339,12 +26342,21 @@ msgstr ""
|
|||
msgid "ProtectedBranch|Branch:"
|
||||
msgstr ""
|
||||
|
||||
msgid "ProtectedBranch|By default, protected branches restrict who can modify the branch."
|
||||
msgstr ""
|
||||
|
||||
msgid "ProtectedBranch|Code owner approval"
|
||||
msgstr ""
|
||||
|
||||
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
|
||||
msgstr ""
|
||||
|
||||
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
|
||||
msgstr ""
|
||||
|
||||
msgid "ProtectedBranch|Learn more."
|
||||
msgstr ""
|
||||
|
||||
msgid "ProtectedBranch|Protect"
|
||||
msgstr ""
|
||||
|
||||
|
@ -26354,6 +26366,9 @@ msgstr ""
|
|||
msgid "ProtectedBranch|Protected branch (%{protected_branches_count})"
|
||||
msgstr ""
|
||||
|
||||
msgid "ProtectedBranch|Protected branches"
|
||||
msgstr ""
|
||||
|
||||
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
|
||||
msgstr ""
|
||||
|
||||
|
@ -26369,6 +26384,9 @@ msgstr ""
|
|||
msgid "ProtectedBranch|Toggle code owner approval"
|
||||
msgstr ""
|
||||
|
||||
msgid "ProtectedBranch|What are protected branches?"
|
||||
msgstr ""
|
||||
|
||||
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
|
||||
msgstr ""
|
||||
|
||||
|
@ -26414,6 +26432,21 @@ msgstr ""
|
|||
msgid "ProtectedEnvironment|Your environment has been unprotected"
|
||||
msgstr ""
|
||||
|
||||
msgid "ProtectedTag|By default, protected branches restrict who can modify the tag."
|
||||
msgstr ""
|
||||
|
||||
msgid "ProtectedTag|Learn more."
|
||||
msgstr ""
|
||||
|
||||
msgid "ProtectedTag|Limit access to creating and updating tags."
|
||||
msgstr ""
|
||||
|
||||
msgid "ProtectedTag|Protected tags"
|
||||
msgstr ""
|
||||
|
||||
msgid "ProtectedTag|What are protected tags?"
|
||||
msgstr ""
|
||||
|
||||
msgid "Protip: %{linkStart}Auto DevOps%{linkEnd} uses Kubernetes clusters to deploy your code!"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -68,8 +68,8 @@ then
|
|||
fi
|
||||
|
||||
# Do not use 'README.md', instead use 'index.md'
|
||||
# Number of 'README.md's as of 2020-10-13
|
||||
NUMBER_READMES=28
|
||||
# Number of 'README.md's as of 2021-06-21
|
||||
NUMBER_READMES=15
|
||||
FIND_READMES=$(find doc/ -name "README.md" | wc -l)
|
||||
echo '=> Checking for new README.md files...'
|
||||
echo
|
||||
|
|
|
@ -10,11 +10,11 @@ RSpec.describe 'User activates PivotalTracker' do
|
|||
end
|
||||
|
||||
it 'activates service', :js do
|
||||
visit_project_integration('PivotalTracker')
|
||||
visit_project_integration('Pivotal Tracker')
|
||||
fill_in('Token', with: 'verySecret')
|
||||
|
||||
click_test_then_save_integration(expect_test_to_fail: false)
|
||||
|
||||
expect(page).to have_content('PivotalTracker settings saved and active.')
|
||||
expect(page).to have_content('Pivotal Tracker settings saved and active.')
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import createFlash, {
|
||||
deprecatedCreateFlash,
|
||||
createFlashEl,
|
||||
createAction,
|
||||
hideFlash,
|
||||
|
@ -125,120 +124,6 @@ describe('Flash', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('deprecatedCreateFlash', () => {
|
||||
const message = 'test';
|
||||
const type = 'alert';
|
||||
const parent = document;
|
||||
const actionConfig = null;
|
||||
const fadeTransition = false;
|
||||
const addBodyClass = true;
|
||||
const defaultParams = [message, type, parent, actionConfig, fadeTransition, addBodyClass];
|
||||
|
||||
describe('no flash-container', () => {
|
||||
it('does not add to the DOM', () => {
|
||||
const flashEl = deprecatedCreateFlash(message);
|
||||
|
||||
expect(flashEl).toBeNull();
|
||||
|
||||
expect(document.querySelector('.flash-alert')).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('with flash-container', () => {
|
||||
beforeEach(() => {
|
||||
setFixtures(
|
||||
'<div class="content-wrapper js-content-wrapper"><div class="flash-container"></div></div>',
|
||||
);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
document.querySelector('.js-content-wrapper').remove();
|
||||
});
|
||||
|
||||
it('adds flash element into container', () => {
|
||||
deprecatedCreateFlash(...defaultParams);
|
||||
|
||||
expect(document.querySelector('.flash-alert')).not.toBeNull();
|
||||
|
||||
expect(document.body.className).toContain('flash-shown');
|
||||
});
|
||||
|
||||
it('adds flash into specified parent', () => {
|
||||
deprecatedCreateFlash(
|
||||
message,
|
||||
type,
|
||||
document.querySelector('.content-wrapper'),
|
||||
actionConfig,
|
||||
fadeTransition,
|
||||
addBodyClass,
|
||||
);
|
||||
|
||||
expect(document.querySelector('.content-wrapper .flash-alert')).not.toBeNull();
|
||||
expect(document.querySelector('.content-wrapper').innerText.trim()).toEqual(message);
|
||||
});
|
||||
|
||||
it('adds container classes when inside content-wrapper', () => {
|
||||
deprecatedCreateFlash(...defaultParams);
|
||||
|
||||
expect(document.querySelector('.flash-text').className).toBe('flash-text');
|
||||
expect(document.querySelector('.content-wrapper').innerText.trim()).toEqual(message);
|
||||
});
|
||||
|
||||
it('does not add container when outside of content-wrapper', () => {
|
||||
document.querySelector('.content-wrapper').className = 'js-content-wrapper';
|
||||
deprecatedCreateFlash(...defaultParams);
|
||||
|
||||
expect(document.querySelector('.flash-text').className.trim()).toContain('flash-text');
|
||||
});
|
||||
|
||||
it('removes element after clicking', () => {
|
||||
deprecatedCreateFlash(...defaultParams);
|
||||
|
||||
document.querySelector('.flash-alert .js-close-icon').click();
|
||||
|
||||
expect(document.querySelector('.flash-alert')).toBeNull();
|
||||
|
||||
expect(document.body.className).not.toContain('flash-shown');
|
||||
});
|
||||
|
||||
describe('with actionConfig', () => {
|
||||
it('adds action link', () => {
|
||||
const newActionConfig = { title: 'test' };
|
||||
deprecatedCreateFlash(
|
||||
message,
|
||||
type,
|
||||
parent,
|
||||
newActionConfig,
|
||||
fadeTransition,
|
||||
addBodyClass,
|
||||
);
|
||||
|
||||
expect(document.querySelector('.flash-action')).not.toBeNull();
|
||||
});
|
||||
|
||||
it('calls actionConfig clickHandler on click', () => {
|
||||
const newActionConfig = {
|
||||
title: 'test',
|
||||
clickHandler: jest.fn(),
|
||||
};
|
||||
|
||||
deprecatedCreateFlash(
|
||||
message,
|
||||
type,
|
||||
parent,
|
||||
newActionConfig,
|
||||
fadeTransition,
|
||||
addBodyClass,
|
||||
);
|
||||
|
||||
document.querySelector('.flash-action').click();
|
||||
|
||||
expect(newActionConfig.clickHandler).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('createFlash', () => {
|
||||
const message = 'test';
|
||||
const type = 'alert';
|
||||
|
|
|
@ -26,42 +26,6 @@ describe('common_utils', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('urlParamsToArray', () => {
|
||||
it('returns empty array for empty querystring', () => {
|
||||
expect(commonUtils.urlParamsToArray('')).toEqual([]);
|
||||
});
|
||||
|
||||
it('should decode params', () => {
|
||||
expect(commonUtils.urlParamsToArray('?label_name%5B%5D=test')[0]).toBe('label_name[]=test');
|
||||
});
|
||||
|
||||
it('should remove the question mark from the search params', () => {
|
||||
const paramsArray = commonUtils.urlParamsToArray('?test=thing');
|
||||
|
||||
expect(paramsArray[0][0]).not.toBe('?');
|
||||
});
|
||||
});
|
||||
|
||||
describe('urlParamsToObject', () => {
|
||||
it('parses path for label with trailing +', () => {
|
||||
expect(commonUtils.urlParamsToObject('label_name[]=label%2B', {})).toEqual({
|
||||
label_name: ['label+'],
|
||||
});
|
||||
});
|
||||
|
||||
it('parses path for milestone with trailing +', () => {
|
||||
expect(commonUtils.urlParamsToObject('milestone_title=A%2B', {})).toEqual({
|
||||
milestone_title: 'A+',
|
||||
});
|
||||
});
|
||||
|
||||
it('parses path for search terms with spaces', () => {
|
||||
expect(commonUtils.urlParamsToObject('search=two+words', {})).toEqual({
|
||||
search: 'two words',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('handleLocationHash', () => {
|
||||
beforeEach(() => {
|
||||
jest.spyOn(window.document, 'getElementById');
|
||||
|
|
|
@ -650,6 +650,45 @@ describe('URL utility', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('urlParamsToArray', () => {
|
||||
it('returns empty array for empty querystring', () => {
|
||||
expect(urlUtils.urlParamsToArray('')).toEqual([]);
|
||||
});
|
||||
|
||||
it('should decode params', () => {
|
||||
expect(urlUtils.urlParamsToArray('?label_name%5B%5D=test')[0]).toBe('label_name[]=test');
|
||||
});
|
||||
|
||||
it('should remove the question mark from the search params', () => {
|
||||
const paramsArray = urlUtils.urlParamsToArray('?test=thing');
|
||||
|
||||
expect(paramsArray[0][0]).not.toBe('?');
|
||||
});
|
||||
});
|
||||
|
||||
describe('urlParamsToObject', () => {
|
||||
it('parses path for label with trailing +', () => {
|
||||
// eslint-disable-next-line import/no-deprecated
|
||||
expect(urlUtils.urlParamsToObject('label_name[]=label%2B', {})).toEqual({
|
||||
label_name: ['label+'],
|
||||
});
|
||||
});
|
||||
|
||||
it('parses path for milestone with trailing +', () => {
|
||||
// eslint-disable-next-line import/no-deprecated
|
||||
expect(urlUtils.urlParamsToObject('milestone_title=A%2B', {})).toEqual({
|
||||
milestone_title: 'A+',
|
||||
});
|
||||
});
|
||||
|
||||
it('parses path for search terms with spaces', () => {
|
||||
// eslint-disable-next-line import/no-deprecated
|
||||
expect(urlUtils.urlParamsToObject('search=two+words', {})).toEqual({
|
||||
search: 'two words',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('queryToObject', () => {
|
||||
it.each`
|
||||
case | query | options | result
|
||||
|
|
|
@ -5,6 +5,14 @@ require 'spec_helper'
|
|||
RSpec.describe Gitlab::Database::LoadBalancing::SidekiqServerMiddleware do
|
||||
let(:middleware) { described_class.new }
|
||||
|
||||
let(:load_balancer) { double.as_null_object }
|
||||
let(:has_replication_lag) { false }
|
||||
|
||||
before do
|
||||
allow(::Gitlab::Database::LoadBalancing).to receive_message_chain(:proxy, :load_balancer).and_return(load_balancer)
|
||||
allow(load_balancer).to receive(:select_up_to_date_host).and_return(!has_replication_lag)
|
||||
end
|
||||
|
||||
after do
|
||||
Gitlab::Database::LoadBalancing::Session.clear_session
|
||||
end
|
||||
|
@ -39,7 +47,7 @@ RSpec.describe Gitlab::Database::LoadBalancing::SidekiqServerMiddleware do
|
|||
end
|
||||
end
|
||||
|
||||
shared_examples_for 'replica is up to date' do |location, data_consistency|
|
||||
shared_examples_for 'replica is up to date' do |location|
|
||||
it 'does not stick to the primary', :aggregate_failures do
|
||||
expect(middleware).to receive(:replica_caught_up?).with(location).and_return(true)
|
||||
|
||||
|
@ -47,13 +55,7 @@ RSpec.describe Gitlab::Database::LoadBalancing::SidekiqServerMiddleware do
|
|||
expect(Gitlab::Database::LoadBalancing::Session.current.use_primary?).not_to be_truthy
|
||||
end
|
||||
|
||||
expect(job[:database_chosen]).to eq('replica')
|
||||
end
|
||||
|
||||
it "updates job hash with data_consistency :#{data_consistency}" do
|
||||
middleware.call(worker, job, double(:queue)) do
|
||||
expect(job).to include(data_consistency: data_consistency.to_s)
|
||||
end
|
||||
expect(job['load_balancing_strategy']).to eq('replica')
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -75,7 +77,7 @@ RSpec.describe Gitlab::Database::LoadBalancing::SidekiqServerMiddleware do
|
|||
allow(middleware).to receive(:replica_caught_up?).and_return(true)
|
||||
end
|
||||
|
||||
it_behaves_like 'replica is up to date', '0/D525E3A8', data_consistency
|
||||
it_behaves_like 'replica is up to date', '0/D525E3A8'
|
||||
end
|
||||
|
||||
context 'when database primary location is set' do
|
||||
|
@ -85,13 +87,13 @@ RSpec.describe Gitlab::Database::LoadBalancing::SidekiqServerMiddleware do
|
|||
allow(middleware).to receive(:replica_caught_up?).and_return(true)
|
||||
end
|
||||
|
||||
it_behaves_like 'replica is up to date', '0/D525E3A8', data_consistency
|
||||
it_behaves_like 'replica is up to date', '0/D525E3A8'
|
||||
end
|
||||
|
||||
context 'when database location is not set' do
|
||||
let(:job) { { 'job_id' => 'a180b47c-3fd6-41b8-81e9-34da61c3400e' } }
|
||||
|
||||
it_behaves_like 'stick to the primary', nil
|
||||
it_behaves_like 'stick to the primary'
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -124,10 +126,7 @@ RSpec.describe Gitlab::Database::LoadBalancing::SidekiqServerMiddleware do
|
|||
include_examples 'sticks based on data consistency', :delayed
|
||||
|
||||
context 'when replica is not up to date' do
|
||||
before do
|
||||
allow(::Gitlab::Database::LoadBalancing).to receive_message_chain(:proxy, :load_balancer, :release_host)
|
||||
allow(::Gitlab::Database::LoadBalancing).to receive_message_chain(:proxy, :load_balancer, :select_up_to_date_host).and_return(false)
|
||||
end
|
||||
let(:has_replication_lag) { true }
|
||||
|
||||
around do |example|
|
||||
with_sidekiq_server_middleware do |chain|
|
||||
|
@ -143,7 +142,7 @@ RSpec.describe Gitlab::Database::LoadBalancing::SidekiqServerMiddleware do
|
|||
end.to raise_error(Sidekiq::JobRetry::Skip)
|
||||
|
||||
expect(job['error_class']).to eq('Gitlab::Database::LoadBalancing::SidekiqServerMiddleware::JobReplicaNotUpToDate')
|
||||
expect(job[:database_chosen]).to eq('retry')
|
||||
expect(job['load_balancing_strategy']).to eq('retry_replica')
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -154,7 +153,7 @@ RSpec.describe Gitlab::Database::LoadBalancing::SidekiqServerMiddleware do
|
|||
end.to raise_error(Sidekiq::JobRetry::Skip)
|
||||
|
||||
process_job(job)
|
||||
expect(job[:database_chosen]).to eq('primary')
|
||||
expect(job['load_balancing_strategy']).to eq('retry_primary')
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -163,7 +162,7 @@ RSpec.describe Gitlab::Database::LoadBalancing::SidekiqServerMiddleware do
|
|||
stub_feature_flags(sidekiq_load_balancing_rotate_up_to_date_replica: false)
|
||||
end
|
||||
|
||||
it 'uses different implmentation' do
|
||||
it 'uses different implementation' do
|
||||
expect(::Gitlab::Database::LoadBalancing).to receive_message_chain(:proxy, :load_balancer, :host, :caught_up?).and_return(false)
|
||||
|
||||
expect do
|
||||
|
@ -185,9 +184,9 @@ RSpec.describe Gitlab::Database::LoadBalancing::SidekiqServerMiddleware do
|
|||
include_examples 'stick to the primary'
|
||||
|
||||
it 'updates job hash with primary database chosen', :aggregate_failures do
|
||||
expect { |b| middleware.call(worker, job, double(:queue), &b) }.to yield_control
|
||||
|
||||
expect(job[:database_chosen]).to eq('primary')
|
||||
middleware.call(worker, job, double(:queue)) do
|
||||
expect(job['load_balancing_strategy']).to eq('primary')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
24
spec/lib/gitlab/github_import/object_counter_spec.rb
Normal file
24
spec/lib/gitlab/github_import/object_counter_spec.rb
Normal file
|
@ -0,0 +1,24 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::GithubImport::ObjectCounter, :clean_gitlab_redis_cache do
|
||||
let_it_be(:project) { create(:project) }
|
||||
|
||||
it 'validates the operation being incremented' do
|
||||
expect { described_class.increment(project, :issue, :unknown) }
|
||||
.to raise_error(ArgumentError, 'Operation must be fetched or imported')
|
||||
end
|
||||
|
||||
it 'increments the counter and saves the key to be listed in the summary later' do
|
||||
described_class.increment(project, :issue, :fetched)
|
||||
described_class.increment(project, :issue, :fetched)
|
||||
described_class.increment(project, :issue, :imported)
|
||||
described_class.increment(project, :issue, :imported)
|
||||
|
||||
expect(described_class.summary(project)).to eq({
|
||||
'fetched' => { 'issue' => 2 },
|
||||
'imported' => { 'issue' => 2 }
|
||||
})
|
||||
end
|
||||
end
|
|
@ -11,6 +11,10 @@ RSpec.describe Gitlab::GithubImport::ParallelScheduling do
|
|||
Class
|
||||
end
|
||||
|
||||
def object_type
|
||||
:dummy
|
||||
end
|
||||
|
||||
def collection_method
|
||||
:issues
|
||||
end
|
||||
|
|
|
@ -4,7 +4,7 @@ require 'spec_helper'
|
|||
|
||||
RSpec.describe Gitlab::GithubImport do
|
||||
context 'github.com' do
|
||||
let(:project) { double(:project, import_url: 'http://t0ken@github.com/user/repo.git') }
|
||||
let(:project) { double(:project, import_url: 'http://t0ken@github.com/user/repo.git', id: 1) }
|
||||
|
||||
it 'returns a new Client with a custom token' do
|
||||
expect(described_class::Client)
|
||||
|
|
|
@ -342,7 +342,7 @@ RSpec.describe Gitlab::SidekiqLogging::StructuredLogger do
|
|||
end
|
||||
|
||||
context 'when the job uses load balancing capabilities' do
|
||||
let(:expected_payload) { { 'database_chosen' => 'retry' } }
|
||||
let(:expected_payload) { { 'load_balancing_strategy' => 'retry' } }
|
||||
|
||||
before do
|
||||
allow(Time).to receive(:now).and_return(timestamp)
|
||||
|
@ -354,7 +354,7 @@ RSpec.describe Gitlab::SidekiqLogging::StructuredLogger do
|
|||
expect(logger).to receive(:info).with(include(expected_payload)).ordered
|
||||
|
||||
call_subject(job, 'test_queue') do
|
||||
job[:database_chosen] = 'retry'
|
||||
job['load_balancing_strategy'] = 'retry'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -109,22 +109,20 @@ RSpec.describe Gitlab::SidekiqMiddleware::ServerMetrics do
|
|||
end
|
||||
|
||||
context 'DB load balancing' do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
subject { described_class.new }
|
||||
|
||||
let(:queue) { :test }
|
||||
let(:worker_class) { worker.class }
|
||||
let(:job) { {} }
|
||||
let(:job_status) { :done }
|
||||
let(:labels_with_job_status) { default_labels.merge(job_status: job_status.to_s) }
|
||||
let(:default_labels) do
|
||||
{ queue: queue.to_s,
|
||||
worker: worker_class.to_s,
|
||||
boundary: "",
|
||||
external_dependencies: "no",
|
||||
feature_category: "",
|
||||
urgency: "low" }
|
||||
let(:worker) { TestWorker.new }
|
||||
let(:client_middleware) { Gitlab::Database::LoadBalancing::SidekiqClientMiddleware.new }
|
||||
let(:load_balancer) { double.as_null_object }
|
||||
let(:load_balancing_metric) { double('load balancing metric') }
|
||||
let(:job) { { "retry" => 3, "job_id" => "a180b47c-3fd6-41b8-81e9-34da61c3400e" } }
|
||||
|
||||
def process_job
|
||||
client_middleware.call(worker_class, job, queue, double) do
|
||||
worker_class.process_job(job)
|
||||
end
|
||||
end
|
||||
|
||||
before do
|
||||
|
@ -132,84 +130,93 @@ RSpec.describe Gitlab::SidekiqMiddleware::ServerMetrics do
|
|||
TestWorker.class_eval do
|
||||
include Sidekiq::Worker
|
||||
include WorkerAttributes
|
||||
|
||||
def perform(*args)
|
||||
end
|
||||
end
|
||||
|
||||
allow(::Gitlab::Database::LoadBalancing).to receive_message_chain(:proxy, :load_balancer).and_return(load_balancer)
|
||||
allow(load_balancing_metric).to receive(:increment)
|
||||
allow(Gitlab::Metrics).to receive(:counter).with(:sidekiq_load_balancing_count, anything).and_return(load_balancing_metric)
|
||||
end
|
||||
|
||||
around do |example|
|
||||
with_sidekiq_server_middleware do |chain|
|
||||
chain.add Gitlab::Database::LoadBalancing::SidekiqServerMiddleware
|
||||
chain.add described_class
|
||||
Sidekiq::Testing.inline! { example.run }
|
||||
end
|
||||
end
|
||||
|
||||
let(:worker) { TestWorker.new }
|
||||
|
||||
include_context 'server metrics with mocked prometheus'
|
||||
include_context 'server metrics call'
|
||||
include_context 'clear DB Load Balancing configuration'
|
||||
|
||||
context 'when load_balancing is enabled' do
|
||||
let(:load_balancing_metric) { double('load balancing metric') }
|
||||
|
||||
include_context 'clear DB Load Balancing configuration'
|
||||
shared_context 'worker declaring data consistency' do
|
||||
let(:worker_class) { LBTestWorker }
|
||||
|
||||
before do
|
||||
allow(::Gitlab::Database::LoadBalancing).to receive(:enable?).and_return(true)
|
||||
allow(Gitlab::Metrics).to receive(:counter).with(:sidekiq_load_balancing_count, anything).and_return(load_balancing_metric)
|
||||
end
|
||||
stub_const('LBTestWorker', Class.new(TestWorker))
|
||||
LBTestWorker.class_eval do
|
||||
include ApplicationWorker
|
||||
|
||||
describe '#initialize' do
|
||||
it 'sets load_balancing metrics' do
|
||||
expect(Gitlab::Metrics).to receive(:counter).with(:sidekiq_load_balancing_count, anything).and_return(load_balancing_metric)
|
||||
|
||||
subject
|
||||
data_consistency :delayed
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when load_balancing is enabled' do
|
||||
before do
|
||||
allow(::Gitlab::Database::LoadBalancing).to receive(:enable?).and_return(true)
|
||||
end
|
||||
|
||||
describe '#call' do
|
||||
include_context 'server metrics call'
|
||||
context 'when worker declares data consistency' do
|
||||
include_context 'worker declaring data consistency'
|
||||
|
||||
context 'when :database_chosen is provided' do
|
||||
where(:database_chosen) do
|
||||
%w[primary retry replica]
|
||||
end
|
||||
it 'increments load balancing counter' do
|
||||
process_job
|
||||
|
||||
with_them do
|
||||
context "when #{params[:database_chosen]} is used" do
|
||||
let(:labels_with_load_balancing) do
|
||||
labels_with_job_status.merge(database_chosen: database_chosen, data_consistency: 'delayed')
|
||||
end
|
||||
|
||||
before do
|
||||
job[:database_chosen] = database_chosen
|
||||
job[:data_consistency] = 'delayed'
|
||||
allow(load_balancing_metric).to receive(:increment)
|
||||
end
|
||||
|
||||
it 'increment sidekiq_load_balancing_count' do
|
||||
expect(load_balancing_metric).to receive(:increment).with(labels_with_load_balancing, 1)
|
||||
|
||||
described_class.new.call(worker, job, :test) { nil }
|
||||
end
|
||||
end
|
||||
expect(load_balancing_metric).to have_received(:increment).with(
|
||||
a_hash_including(
|
||||
data_consistency: :delayed,
|
||||
load_balancing_strategy: 'replica'
|
||||
), 1)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when :database_chosen is not provided' do
|
||||
it 'does not increment sidekiq_load_balancing_count' do
|
||||
expect(load_balancing_metric).not_to receive(:increment)
|
||||
context 'when worker does not declare data consistency' do
|
||||
it 'does not increment load balancing counter' do
|
||||
process_job
|
||||
|
||||
described_class.new.call(worker, job, :test) { nil }
|
||||
expect(load_balancing_metric).not_to have_received(:increment)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when load_balancing is disabled' do
|
||||
include_context 'clear DB Load Balancing configuration'
|
||||
include_context 'worker declaring data consistency'
|
||||
|
||||
before do
|
||||
allow(::Gitlab::Database::LoadBalancing).to receive(:enable?).and_return(false)
|
||||
end
|
||||
|
||||
describe '#initialize' do
|
||||
it 'doesnt set load_balancing metrics' do
|
||||
it 'does not set load_balancing metrics' do
|
||||
expect(Gitlab::Metrics).not_to receive(:counter).with(:sidekiq_load_balancing_count, anything)
|
||||
|
||||
subject
|
||||
end
|
||||
end
|
||||
|
||||
describe '#call' do
|
||||
it 'does not increment load balancing counter' do
|
||||
process_job
|
||||
|
||||
expect(load_balancing_metric).not_to have_received(:increment)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -29,6 +29,10 @@ RSpec.describe ReplaceUniqueIndexOnCycleAnalyticsStages, :migration, schema: 202
|
|||
stage_record
|
||||
end
|
||||
|
||||
after do
|
||||
described_class.new.up
|
||||
end
|
||||
|
||||
it 'removes duplicated stage records' do
|
||||
subject
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue