Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
9c191c0b94
commit
d551c55bb0
73 changed files with 1063 additions and 328 deletions
56
.gitlab/issue_templates/InfraDev.md
Normal file
56
.gitlab/issue_templates/InfraDev.md
Normal file
|
@ -0,0 +1,56 @@
|
|||
<!--
|
||||
Triage of infradev Issues is desired to occur asynchronously.
|
||||
For maximum efficiency, please ensure the following, so that your infradev issues can gain maximum traction.
|
||||
|
||||
https://about.gitlab.com/handbook/engineering/workflow/#a-guide-to-creating-effective-infradev-issues
|
||||
-->
|
||||
|
||||
## Summary
|
||||
<!--
|
||||
Clearly state the scope of the problem, and how it affects GitLab.com
|
||||
-->
|
||||
|
||||
|
||||
## Impact
|
||||
<!--
|
||||
- Quantify the effect of the problem to help ensure that correct prioritization occurs.
|
||||
- Include costs to availability. The Incident Budget Explorer dashboard can help here.
|
||||
- Include the number of times alerts have fired owing to the problem, how much time was spent dealing with the problem, and how many people were involved.
|
||||
- Link to affected incidents, and cross-reference them as related issues.
|
||||
- Include screenshots of visualization from Grafana or Kibana.
|
||||
- Always include a permalink to the source of the screenshot so that others can investigate further.
|
||||
-->
|
||||
|
||||
|
||||
## Recommendation
|
||||
<!--
|
||||
Provide a clear, unambiguous, self-contained solution to the problem.
|
||||
-->
|
||||
|
||||
|
||||
## Verification
|
||||
<!--
|
||||
Provide a method for validating that the original issue still exists.
|
||||
|
||||
Having a way of checking validity can save on a great deal of back-and-forth discussion between Infradev Triage participants including Engineering Managers, Directors and Product Managers and make space for other non-resolved issues to get scheduled sooner.
|
||||
|
||||
Ideally, provide a link to a Thanos query or an ELK query and clear instructions on how to interpret the results to determine whether the problem is still occurring.
|
||||
-->
|
||||
|
||||
|
||||
<!--
|
||||
Workflow and other relevant labels
|
||||
|
||||
/label ~"severity::"
|
||||
/label ~"priority::"
|
||||
/label ~"group::"
|
||||
/label ~"devops::"
|
||||
|
||||
See also:
|
||||
- https://about.gitlab.com/handbook/engineering/quality/issue-triage/#availability
|
||||
- https://about.gitlab.com/handbook/product/categories/
|
||||
- https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/data/stages.yml
|
||||
-->
|
||||
|
||||
/label ~"infradev"
|
||||
/label ~"bug"
|
|
@ -23,28 +23,6 @@ Graphql/Descriptions:
|
|||
- 'ee/app/graphql/types/vulnerability_severity_enum.rb'
|
||||
- 'ee/app/graphql/types/vulnerability_state_enum.rb'
|
||||
- 'ee/app/graphql/types/vulnerability_confidence_enum.rb'
|
||||
- 'ee/app/graphql/mutations/app_sec/fuzzing/api/ci_configuration/create.rb'
|
||||
- 'ee/app/graphql/mutations/boards/epic_boards/create.rb'
|
||||
- 'ee/app/graphql/mutations/boards/epic_boards/epic_move_list.rb'
|
||||
- 'ee/app/graphql/mutations/boards/epic_boards/update.rb'
|
||||
- 'ee/app/graphql/mutations/boards/epic_lists/destroy.rb'
|
||||
- 'ee/app/graphql/mutations/boards/lists/update_limit_metrics.rb'
|
||||
- 'ee/app/graphql/mutations/boards/update_epic_user_preferences.rb'
|
||||
- 'ee/app/graphql/mutations/compliance_management/frameworks/create.rb'
|
||||
- 'ee/app/graphql/mutations/compliance_management/frameworks/destroy.rb'
|
||||
- 'ee/app/graphql/mutations/compliance_management/frameworks/update.rb'
|
||||
- 'ee/app/graphql/mutations/concerns/mutations/shared_epic_arguments.rb'
|
||||
- 'ee/app/graphql/mutations/dast/profiles/create.rb'
|
||||
- 'ee/app/graphql/mutations/dast/profiles/update.rb'
|
||||
- 'ee/app/graphql/mutations/dast_on_demand_scans/create.rb'
|
||||
- 'ee/app/graphql/mutations/dast_scanner_profiles/create.rb'
|
||||
- 'ee/app/graphql/mutations/dast_scanner_profiles/update.rb'
|
||||
- 'ee/app/graphql/mutations/dast_site_profiles/create.rb'
|
||||
- 'ee/app/graphql/mutations/dast_site_profiles/delete.rb'
|
||||
- 'ee/app/graphql/mutations/dast_site_profiles/update.rb'
|
||||
- 'ee/app/graphql/mutations/dast_site_tokens/create.rb'
|
||||
- 'ee/app/graphql/mutations/dast_site_validations/create.rb'
|
||||
- 'ee/app/graphql/mutations/dast_site_validations/revoke.rb'
|
||||
- 'ee/app/graphql/mutations/epic_tree/reorder.rb'
|
||||
- 'ee/app/graphql/mutations/epics/add_issue.rb'
|
||||
- 'ee/app/graphql/mutations/epics/base.rb'
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
import { Node, mergeAttributes } from '@tiptap/core';
|
||||
|
||||
export default Node.create({
|
||||
name: 'descriptionItem',
|
||||
content: 'block+',
|
||||
defining: true,
|
||||
|
||||
addAttributes() {
|
||||
return {
|
||||
isTerm: {
|
||||
default: true,
|
||||
parseHTML: (element) => ({
|
||||
isTerm: element.tagName.toLowerCase() === 'dt',
|
||||
}),
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
parseHTML() {
|
||||
return [{ tag: 'dt' }, { tag: 'dd' }];
|
||||
},
|
||||
|
||||
renderHTML({ HTMLAttributes: { isTerm, ...HTMLAttributes } }) {
|
||||
return [
|
||||
'li',
|
||||
mergeAttributes(HTMLAttributes, { class: isTerm ? 'dl-term' : 'dl-description' }),
|
||||
0,
|
||||
];
|
||||
},
|
||||
|
||||
addKeyboardShortcuts() {
|
||||
return {
|
||||
Enter: () => {
|
||||
return this.editor.commands.splitListItem('descriptionItem');
|
||||
},
|
||||
Tab: () => {
|
||||
const { isTerm } = this.editor.getAttributes('descriptionItem');
|
||||
if (isTerm)
|
||||
return this.editor.commands.updateAttributes('descriptionItem', { isTerm: !isTerm });
|
||||
|
||||
return false;
|
||||
},
|
||||
'Shift-Tab': () => {
|
||||
const { isTerm } = this.editor.getAttributes('descriptionItem');
|
||||
if (isTerm) return this.editor.commands.liftListItem('descriptionItem');
|
||||
|
||||
return this.editor.commands.updateAttributes('descriptionItem', { isTerm: true });
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
|
@ -0,0 +1,23 @@
|
|||
import { Node, mergeAttributes } from '@tiptap/core';
|
||||
import { wrappingInputRule } from 'prosemirror-inputrules';
|
||||
|
||||
export const inputRegex = /^\s*(<dl>)$/;
|
||||
|
||||
export default Node.create({
|
||||
name: 'descriptionList',
|
||||
// eslint-disable-next-line @gitlab/require-i18n-strings
|
||||
group: 'block list',
|
||||
content: 'descriptionItem+',
|
||||
|
||||
parseHTML() {
|
||||
return [{ tag: 'dl' }];
|
||||
},
|
||||
|
||||
renderHTML({ HTMLAttributes }) {
|
||||
return ['ul', mergeAttributes(HTMLAttributes, { class: 'dl-content' }), 0];
|
||||
},
|
||||
|
||||
addInputRules() {
|
||||
return [wrappingInputRule(inputRegex, this.type)];
|
||||
},
|
||||
});
|
|
@ -8,6 +8,8 @@ import Bold from '../extensions/bold';
|
|||
import BulletList from '../extensions/bullet_list';
|
||||
import Code from '../extensions/code';
|
||||
import CodeBlockHighlight from '../extensions/code_block_highlight';
|
||||
import DescriptionItem from '../extensions/description_item';
|
||||
import DescriptionList from '../extensions/description_list';
|
||||
import Division from '../extensions/division';
|
||||
import Document from '../extensions/document';
|
||||
import Dropcursor from '../extensions/dropcursor';
|
||||
|
@ -74,6 +76,8 @@ export const createContentEditor = ({
|
|||
BulletList,
|
||||
Code,
|
||||
CodeBlockHighlight,
|
||||
DescriptionItem,
|
||||
DescriptionList,
|
||||
Document,
|
||||
Division,
|
||||
Dropcursor,
|
||||
|
|
|
@ -9,6 +9,8 @@ import Bold from '../extensions/bold';
|
|||
import BulletList from '../extensions/bullet_list';
|
||||
import Code from '../extensions/code';
|
||||
import CodeBlockHighlight from '../extensions/code_block_highlight';
|
||||
import DescriptionItem from '../extensions/description_item';
|
||||
import DescriptionList from '../extensions/description_list';
|
||||
import Division from '../extensions/division';
|
||||
import Emoji from '../extensions/emoji';
|
||||
import Figure from '../extensions/figure';
|
||||
|
@ -122,6 +124,12 @@ const defaultSerializerConfig = {
|
|||
state.closeBlock(node);
|
||||
},
|
||||
[Division.name]: renderHTMLNode('div'),
|
||||
[DescriptionList.name]: renderHTMLNode('dl', true),
|
||||
[DescriptionItem.name]: (state, node, parent, index) => {
|
||||
if (index === 1) state.ensureNewLine();
|
||||
renderHTMLNode(node.attrs.isTerm ? 'dt' : 'dd')(state, node);
|
||||
if (index === parent.childCount - 1) state.ensureNewLine();
|
||||
},
|
||||
[Emoji.name]: (state, node) => {
|
||||
const { name } = node.attrs;
|
||||
|
||||
|
|
|
@ -6,6 +6,11 @@ const defaultAttrs = {
|
|||
th: { colspan: 1, rowspan: 1, colwidth: null },
|
||||
};
|
||||
|
||||
const ignoreAttrs = {
|
||||
dd: ['isTerm'],
|
||||
dt: ['isTerm'],
|
||||
};
|
||||
|
||||
const tableMap = new WeakMap();
|
||||
|
||||
// Source taken from
|
||||
|
@ -118,7 +123,8 @@ export function openTag(tagName, attrs) {
|
|||
|
||||
str += Object.entries(attrs || {})
|
||||
.map(([key, value]) => {
|
||||
if (defaultAttrs[tagName]?.[key] === value) return '';
|
||||
if ((ignoreAttrs[tagName] || []).includes(key) || defaultAttrs[tagName]?.[key] === value)
|
||||
return '';
|
||||
|
||||
return ` ${key}="${htmlEncode(value?.toString())}"`;
|
||||
})
|
||||
|
|
|
@ -3,7 +3,6 @@ import { GlLoadingIcon, GlPagination, GlSprintf } from '@gitlab/ui';
|
|||
import { GlBreakpointInstance as bp } from '@gitlab/ui/dist/utils';
|
||||
import Mousetrap from 'mousetrap';
|
||||
import { mapState, mapGetters, mapActions } from 'vuex';
|
||||
import { DynamicScroller, DynamicScrollerItem } from 'vendor/vue-virtual-scroller';
|
||||
import api from '~/api';
|
||||
import {
|
||||
keysFor,
|
||||
|
@ -55,13 +54,18 @@ import CompareVersions from './compare_versions.vue';
|
|||
import DiffFile from './diff_file.vue';
|
||||
import HiddenFilesWarning from './hidden_files_warning.vue';
|
||||
import NoChanges from './no_changes.vue';
|
||||
import PreRenderer from './pre_renderer.vue';
|
||||
import TreeList from './tree_list.vue';
|
||||
import VirtualScrollerScrollSync from './virtual_scroller_scroll_sync';
|
||||
|
||||
export default {
|
||||
name: 'DiffsApp',
|
||||
components: {
|
||||
DynamicScroller: () =>
|
||||
import('vendor/vue-virtual-scroller').then(({ DynamicScroller }) => DynamicScroller),
|
||||
DynamicScrollerItem: () =>
|
||||
import('vendor/vue-virtual-scroller').then(({ DynamicScrollerItem }) => DynamicScrollerItem),
|
||||
PreRenderer: () => import('./pre_renderer.vue').then((PreRenderer) => PreRenderer),
|
||||
VirtualScrollerScrollSync: () =>
|
||||
import('./virtual_scroller_scroll_sync').then((VSSSync) => VSSSync),
|
||||
CompareVersions,
|
||||
DiffFile,
|
||||
NoChanges,
|
||||
|
@ -73,10 +77,6 @@ export default {
|
|||
PanelResizer,
|
||||
GlPagination,
|
||||
GlSprintf,
|
||||
DynamicScroller,
|
||||
DynamicScrollerItem,
|
||||
PreRenderer,
|
||||
VirtualScrollerScrollSync,
|
||||
MrWidgetHowToMergeModal,
|
||||
},
|
||||
alerts: {
|
||||
|
@ -189,25 +189,25 @@ export default {
|
|||
treeWidth,
|
||||
diffFilesLength: 0,
|
||||
virtualScrollCurrentIndex: -1,
|
||||
subscribedToVirtualScrollingEvents: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
isLoading: (state) => state.diffs.isLoading,
|
||||
isBatchLoading: (state) => state.diffs.isBatchLoading,
|
||||
diffFiles: (state) => state.diffs.diffFiles,
|
||||
diffViewType: (state) => state.diffs.diffViewType,
|
||||
commit: (state) => state.diffs.commit,
|
||||
renderOverflowWarning: (state) => state.diffs.renderOverflowWarning,
|
||||
numTotalFiles: (state) => state.diffs.realSize,
|
||||
numVisibleFiles: (state) => state.diffs.size,
|
||||
plainDiffPath: (state) => state.diffs.plainDiffPath,
|
||||
emailPatchPath: (state) => state.diffs.emailPatchPath,
|
||||
retrievingBatches: (state) => state.diffs.retrievingBatches,
|
||||
...mapState('diffs', {
|
||||
numTotalFiles: 'realSize',
|
||||
numVisibleFiles: 'size',
|
||||
}),
|
||||
...mapState('diffs', [
|
||||
'showTreeList',
|
||||
'isLoading',
|
||||
'isBatchLoading',
|
||||
'diffFiles',
|
||||
'diffViewType',
|
||||
'commit',
|
||||
'renderOverflowWarning',
|
||||
'plainDiffPath',
|
||||
'emailPatchPath',
|
||||
'retrievingBatches',
|
||||
'startVersion',
|
||||
'latestDiff',
|
||||
'currentDiffFileId',
|
||||
|
@ -316,6 +316,7 @@ export default {
|
|||
}
|
||||
|
||||
this.adjustView();
|
||||
this.subscribeToVirtualScrollingEvents();
|
||||
},
|
||||
isLoading: 'adjustView',
|
||||
renderFileTree: 'adjustView',
|
||||
|
@ -349,11 +350,6 @@ export default {
|
|||
this.setHighlightedRow(id.split('diff-content').pop().slice(1));
|
||||
}
|
||||
|
||||
if (window.gon?.features?.diffsVirtualScrolling) {
|
||||
diffsEventHub.$on('scrollToFileHash', this.scrollVirtualScrollerToFileHash);
|
||||
diffsEventHub.$on('scrollToIndex', this.scrollVirtualScrollerToIndex);
|
||||
}
|
||||
|
||||
if (window.gon?.features?.diffSettingsUsageData) {
|
||||
const events = [];
|
||||
|
||||
|
@ -383,6 +379,8 @@ export default {
|
|||
|
||||
queueRedisHllEvents(events);
|
||||
}
|
||||
|
||||
this.subscribeToVirtualScrollingEvents();
|
||||
},
|
||||
beforeCreate() {
|
||||
diffsApp.instrument();
|
||||
|
@ -611,6 +609,18 @@ export default {
|
|||
}
|
||||
}
|
||||
},
|
||||
subscribeToVirtualScrollingEvents() {
|
||||
if (
|
||||
window.gon?.features?.diffsVirtualScrolling &&
|
||||
this.shouldShow &&
|
||||
!this.subscribedToVirtualScrollingEvents
|
||||
) {
|
||||
diffsEventHub.$on('scrollToFileHash', this.scrollVirtualScrollerToFileHash);
|
||||
diffsEventHub.$on('scrollToIndex', this.scrollVirtualScrollerToIndex);
|
||||
|
||||
this.subscribedToVirtualScrollingEvents = true;
|
||||
}
|
||||
},
|
||||
},
|
||||
minTreeWidth: MIN_TREE_WIDTH,
|
||||
maxTreeWidth: MAX_TREE_WIDTH,
|
||||
|
@ -672,7 +682,6 @@ export default {
|
|||
<template v-else-if="renderDiffFiles">
|
||||
<dynamic-scroller
|
||||
v-if="isVirtualScrollingEnabled"
|
||||
ref="virtualScroller"
|
||||
:items="diffs"
|
||||
:min-item-size="70"
|
||||
:buffer="1000"
|
||||
|
|
|
@ -24,8 +24,13 @@ export default {
|
|||
return isScrollable ? scrollableStyles : null;
|
||||
},
|
||||
},
|
||||
userColorScheme: window.gon.user_color_scheme,
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<pre class="code-block rounded" :style="styleObject"><code class="d-block">{{ code }}</code></pre>
|
||||
<pre
|
||||
class="code-block rounded code"
|
||||
:class="$options.userColorScheme"
|
||||
:style="styleObject"
|
||||
><code class="d-block">{{ code }}</code></pre>
|
||||
</template>
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
.ProseMirror {
|
||||
td,
|
||||
th,
|
||||
li {
|
||||
li,
|
||||
dd,
|
||||
dt {
|
||||
:first-child {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
@ -34,6 +36,20 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dl-content {
|
||||
width: 100%;
|
||||
|
||||
> li {
|
||||
list-style-type: none;
|
||||
margin-left: $gl-spacing-scale-5;
|
||||
|
||||
&.dl-term {
|
||||
margin: 0;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.table-creator-grid-item {
|
||||
|
|
|
@ -337,8 +337,6 @@
|
|||
}
|
||||
|
||||
.code-block {
|
||||
background: $black;
|
||||
color: $gray-darkest;
|
||||
white-space: pre;
|
||||
overflow-x: auto;
|
||||
font-size: 12px;
|
||||
|
|
|
@ -96,15 +96,10 @@
|
|||
}
|
||||
|
||||
form {
|
||||
width: 48%;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
background: none;
|
||||
margin-bottom: $gl-padding;
|
||||
|
||||
@include media-breakpoint-down(md) {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.omniauth-btn {
|
||||
|
|
|
@ -634,17 +634,11 @@ svg {
|
|||
margin: 0;
|
||||
}
|
||||
.login-page .omniauth-container form {
|
||||
width: 48%;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
background: none;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
@media (max-width: 991.98px) {
|
||||
.login-page .omniauth-container form {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
.login-page .omniauth-container .omniauth-btn {
|
||||
width: 100%;
|
||||
}
|
||||
|
|
|
@ -311,6 +311,9 @@ module ApplicationSettingsHelper
|
|||
:throttle_authenticated_api_enabled,
|
||||
:throttle_authenticated_api_period_in_seconds,
|
||||
:throttle_authenticated_api_requests_per_period,
|
||||
:throttle_authenticated_git_lfs_enabled,
|
||||
:throttle_authenticated_git_lfs_period_in_seconds,
|
||||
:throttle_authenticated_git_lfs_requests_per_period,
|
||||
:throttle_authenticated_web_enabled,
|
||||
:throttle_authenticated_web_period_in_seconds,
|
||||
:throttle_authenticated_web_requests_per_period,
|
||||
|
|
|
@ -497,6 +497,14 @@ class ApplicationSetting < ApplicationRecord
|
|||
presence: true,
|
||||
numericality: { only_integer: true, greater_than: 0 }
|
||||
|
||||
validates :throttle_authenticated_git_lfs_requests_per_period,
|
||||
presence: true,
|
||||
numericality: { only_integer: true, greater_than: 0 }
|
||||
|
||||
validates :throttle_authenticated_git_lfs_period_in_seconds,
|
||||
presence: true,
|
||||
numericality: { only_integer: true, greater_than: 0 }
|
||||
|
||||
validates :throttle_authenticated_web_requests_per_period,
|
||||
presence: true,
|
||||
numericality: { only_integer: true, greater_than: 0 }
|
||||
|
|
|
@ -163,6 +163,9 @@ module ApplicationSettingImplementation
|
|||
throttle_authenticated_api_enabled: false,
|
||||
throttle_authenticated_api_period_in_seconds: 3600,
|
||||
throttle_authenticated_api_requests_per_period: 7200,
|
||||
throttle_authenticated_git_lfs_enabled: false,
|
||||
throttle_authenticated_git_lfs_period_in_seconds: 60,
|
||||
throttle_authenticated_git_lfs_requests_per_period: 1000,
|
||||
throttle_authenticated_web_enabled: false,
|
||||
throttle_authenticated_web_period_in_seconds: 3600,
|
||||
throttle_authenticated_web_requests_per_period: 7200,
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
= form_for @application_setting, url: network_admin_application_settings_path(anchor: 'js-git-lfs-limits-settings'), html: { class: 'fieldset-form' } do |f|
|
||||
= form_errors(@application_setting)
|
||||
|
||||
%fieldset
|
||||
%h5
|
||||
= _('Authenticated Git LFS request rate limit')
|
||||
.form-group
|
||||
.form-check
|
||||
= f.check_box :throttle_authenticated_git_lfs_enabled, class: 'form-check-input', data: { qa_selector: 'throttle_authenticated_git_lfs_checkbox' }
|
||||
= f.label :throttle_authenticated_git_lfs_enabled, class: 'form-check-label gl-font-weight-bold' do
|
||||
= _('Enable authenticated Git LFS request rate limit')
|
||||
%span.form-text.gl-text-gray-600
|
||||
= _('Helps reduce request volume (for example, from crawlers or abusive bots)')
|
||||
.form-group
|
||||
= f.label :throttle_authenticated_git_lfs_requests_per_period, _('Max authenticated Git LFS requests per period per user'), class: 'gl-font-weight-bold'
|
||||
= f.number_field :throttle_authenticated_git_lfs_requests_per_period, class: 'form-control gl-form-input'
|
||||
.form-group
|
||||
= f.label :throttle_authenticated_git_lfs_period_in_seconds, _('Authenticated Git LFS rate limit period in seconds'), class: 'gl-font-weight-bold'
|
||||
= f.number_field :throttle_authenticated_git_lfs_period_in_seconds, class: 'form-control gl-form-input'
|
||||
|
||||
= f.submit _('Save changes'), class: "gl-button btn btn-confirm", data: { qa_selector: 'save_changes_button' }
|
|
@ -35,6 +35,18 @@
|
|||
.settings-content
|
||||
= render 'package_registry_limits'
|
||||
|
||||
%section.settings.as-git-lfs-limits.no-animate#js-git-lfs-limits-settings{ class: ('expanded' if expanded_by_default?), data: { qa_selector: 'git_lfs_limits_content' } }
|
||||
.settings-header
|
||||
%h4
|
||||
= _('Git LFS Rate Limits')
|
||||
%button.btn.gl-button.btn-default.js-settings-toggle{ type: 'button' }
|
||||
= expanded_by_default? ? _('Collapse') : _('Expand')
|
||||
%p
|
||||
= _('Configure specific limits for Git LFS requests that supersede the general user and IP rate limits.')
|
||||
= link_to _('Learn more.'), help_page_path('user/admin_area/settings/git_lfs_rate_limits.md'), target: '_blank', rel: 'noopener noreferrer'
|
||||
.settings-content
|
||||
= render 'git_lfs_limits'
|
||||
|
||||
%section.settings.as-outbound.no-animate#js-outbound-settings{ class: ('expanded' if expanded_by_default?), data: { qa_selector: 'outbound_requests_content' } }
|
||||
.settings-header
|
||||
%h4
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
.d-flex.justify-content-between.flex-wrap
|
||||
- providers.each do |provider|
|
||||
- has_icon = provider_has_icon?(provider)
|
||||
= button_to omniauth_authorize_path(:user, provider), id: "oauth-login-#{provider}", class: "btn gl-button btn-default omniauth-btn oauth-login #{qa_class_for_provider(provider)}" do
|
||||
= button_to omniauth_authorize_path(:user, provider), id: "oauth-login-#{provider}", class: "btn gl-button btn-default omniauth-btn oauth-login #{qa_class_for_provider(provider)}", form: { class: 'gl-w-full' } do
|
||||
- if has_icon
|
||||
= provider_image_tag(provider)
|
||||
%span
|
||||
%span.gl-button-text
|
||||
= label_for_provider(provider)
|
||||
- unless hide_remember_me
|
||||
%fieldset.remember-me
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddThrottleAuthenticatedGitLfsColumns < ActiveRecord::Migration[6.1]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
with_lock_retries do
|
||||
add_column :application_settings, :throttle_authenticated_git_lfs_requests_per_period, :integer, default: 1000, null: false
|
||||
add_column :application_settings, :throttle_authenticated_git_lfs_period_in_seconds, :integer, default: 60, null: false
|
||||
add_column :application_settings, :throttle_authenticated_git_lfs_enabled, :boolean, default: false, null: false
|
||||
end
|
||||
end
|
||||
|
||||
def down
|
||||
with_lock_retries do
|
||||
remove_column :application_settings, :throttle_authenticated_git_lfs_requests_per_period
|
||||
remove_column :application_settings, :throttle_authenticated_git_lfs_period_in_seconds
|
||||
remove_column :application_settings, :throttle_authenticated_git_lfs_enabled, :boolean
|
||||
end
|
||||
end
|
||||
end
|
1
db/schema_migrations/20210830085837
Normal file
1
db/schema_migrations/20210830085837
Normal file
|
@ -0,0 +1 @@
|
|||
cf1a51194961500cb63d848afb1d5ebbf2ef77f54d60957e92c9dd6a667913ea
|
|
@ -9614,6 +9614,9 @@ CREATE TABLE application_settings (
|
|||
throttle_authenticated_files_api_period_in_seconds integer DEFAULT 15 NOT NULL,
|
||||
throttle_unauthenticated_files_api_enabled boolean DEFAULT false NOT NULL,
|
||||
throttle_authenticated_files_api_enabled boolean DEFAULT false NOT NULL,
|
||||
throttle_authenticated_git_lfs_requests_per_period integer DEFAULT 1000 NOT NULL,
|
||||
throttle_authenticated_git_lfs_period_in_seconds integer DEFAULT 60 NOT NULL,
|
||||
throttle_authenticated_git_lfs_enabled boolean DEFAULT false NOT NULL,
|
||||
CONSTRAINT app_settings_container_reg_cleanup_tags_max_list_size_positive CHECK ((container_registry_cleanup_tags_service_max_list_size >= 0)),
|
||||
CONSTRAINT app_settings_ext_pipeline_validation_service_url_text_limit CHECK ((char_length(external_pipeline_validation_service_url) <= 255)),
|
||||
CONSTRAINT app_settings_registry_exp_policies_worker_capacity_positive CHECK ((container_registry_expiration_policies_worker_capacity >= 0)),
|
||||
|
|
|
@ -78,6 +78,16 @@ This setting limits the request rate on the Packages API per user or IP. For mor
|
|||
|
||||
- **Default rate limit**: Disabled by default.
|
||||
|
||||
### Git LFS
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/68642) in GitLab 14.3.
|
||||
|
||||
This setting limits the request rate on the [Git LFS](../topics/git/lfs/index.md)
|
||||
requests per user. For more information, read
|
||||
[GitLab Git Large File Storage (LFS) Administration](../administration/lfs/index.md).
|
||||
|
||||
- **Default rate limit**: Disabled by default.
|
||||
|
||||
### Import/Export
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/35728) in GitLab 13.2.
|
||||
|
|
|
@ -631,7 +631,7 @@ Input type: `ApiFuzzingCiConfigurationCreateInput`
|
|||
| <a id="mutationapifuzzingciconfigurationcreateauthusername"></a>`authUsername` | [`String`](#string) | CI variable containing the username for authenticating with the target API. |
|
||||
| <a id="mutationapifuzzingciconfigurationcreateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
|
||||
| <a id="mutationapifuzzingciconfigurationcreateprojectpath"></a>`projectPath` | [`ID!`](#id) | Full path of the project. |
|
||||
| <a id="mutationapifuzzingciconfigurationcreatescanmode"></a>`scanMode` | [`ApiFuzzingScanMode!`](#apifuzzingscanmode) | The mode for API fuzzing scans. |
|
||||
| <a id="mutationapifuzzingciconfigurationcreatescanmode"></a>`scanMode` | [`ApiFuzzingScanMode!`](#apifuzzingscanmode) | Mode for API fuzzing scans. |
|
||||
| <a id="mutationapifuzzingciconfigurationcreatescanprofile"></a>`scanProfile` | [`String`](#string) | Name of a default profile to use for scanning. Ex: Quick-10. |
|
||||
| <a id="mutationapifuzzingciconfigurationcreatetarget"></a>`target` | [`String!`](#string) | URL for the target of API fuzzing scans. |
|
||||
|
||||
|
@ -642,7 +642,7 @@ Input type: `ApiFuzzingCiConfigurationCreateInput`
|
|||
| <a id="mutationapifuzzingciconfigurationcreateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
|
||||
| <a id="mutationapifuzzingciconfigurationcreateconfigurationyaml"></a>`configurationYaml` | [`String`](#string) | A YAML snippet that can be inserted into the project's `.gitlab-ci.yml` to set up API fuzzing scans. |
|
||||
| <a id="mutationapifuzzingciconfigurationcreateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
|
||||
| <a id="mutationapifuzzingciconfigurationcreategitlabciyamleditpath"></a>`gitlabCiYamlEditPath` | [`String`](#string) | The location at which the project's `.gitlab-ci.yml` file can be edited in the browser. |
|
||||
| <a id="mutationapifuzzingciconfigurationcreategitlabciyamleditpath"></a>`gitlabCiYamlEditPath` | [`String`](#string) | Location at which the project's `.gitlab-ci.yml` file can be edited in the browser. |
|
||||
|
||||
### `Mutation.awardEmojiAdd`
|
||||
|
||||
|
@ -760,10 +760,10 @@ Input type: `BoardListUpdateLimitMetricsInput`
|
|||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="mutationboardlistupdatelimitmetricsclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
|
||||
| <a id="mutationboardlistupdatelimitmetricslimitmetric"></a>`limitMetric` | [`ListLimitMetric`](#listlimitmetric) | The new limit metric type for the list. |
|
||||
| <a id="mutationboardlistupdatelimitmetricslistid"></a>`listId` | [`ListID!`](#listid) | The global ID of the list. |
|
||||
| <a id="mutationboardlistupdatelimitmetricsmaxissuecount"></a>`maxIssueCount` | [`Int`](#int) | The new maximum issue count limit. |
|
||||
| <a id="mutationboardlistupdatelimitmetricsmaxissueweight"></a>`maxIssueWeight` | [`Int`](#int) | The new maximum issue weight limit. |
|
||||
| <a id="mutationboardlistupdatelimitmetricslimitmetric"></a>`limitMetric` | [`ListLimitMetric`](#listlimitmetric) | New limit metric type for the list. |
|
||||
| <a id="mutationboardlistupdatelimitmetricslistid"></a>`listId` | [`ListID!`](#listid) | Global ID of the list. |
|
||||
| <a id="mutationboardlistupdatelimitmetricsmaxissuecount"></a>`maxIssueCount` | [`Int`](#int) | New maximum issue count limit. |
|
||||
| <a id="mutationboardlistupdatelimitmetricsmaxissueweight"></a>`maxIssueWeight` | [`Int`](#int) | New maximum issue weight limit. |
|
||||
|
||||
#### Fields
|
||||
|
||||
|
@ -771,7 +771,7 @@ Input type: `BoardListUpdateLimitMetricsInput`
|
|||
| ---- | ---- | ----------- |
|
||||
| <a id="mutationboardlistupdatelimitmetricsclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
|
||||
| <a id="mutationboardlistupdatelimitmetricserrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
|
||||
| <a id="mutationboardlistupdatelimitmetricslist"></a>`list` | [`BoardList`](#boardlist) | The updated list. |
|
||||
| <a id="mutationboardlistupdatelimitmetricslist"></a>`list` | [`BoardList`](#boardlist) | Updated list. |
|
||||
|
||||
### `Mutation.bulkEnableDevopsAdoptionNamespaces`
|
||||
|
||||
|
@ -1149,7 +1149,7 @@ Input type: `CreateComplianceFrameworkInput`
|
|||
| ---- | ---- | ----------- |
|
||||
| <a id="mutationcreatecomplianceframeworkclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
|
||||
| <a id="mutationcreatecomplianceframeworkerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
|
||||
| <a id="mutationcreatecomplianceframeworkframework"></a>`framework` | [`ComplianceFramework`](#complianceframework) | The created compliance framework. |
|
||||
| <a id="mutationcreatecomplianceframeworkframework"></a>`framework` | [`ComplianceFramework`](#complianceframework) | Created compliance framework. |
|
||||
|
||||
### `Mutation.createCustomEmoji`
|
||||
|
||||
|
@ -1204,17 +1204,17 @@ Input type: `CreateEpicInput`
|
|||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="mutationcreateepicaddlabelids"></a>`addLabelIds` | [`[ID!]`](#id) | The IDs of labels to be added to the epic. |
|
||||
| <a id="mutationcreateepicaddlabelids"></a>`addLabelIds` | [`[ID!]`](#id) | IDs of labels to be added to the epic. |
|
||||
| <a id="mutationcreateepicclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
|
||||
| <a id="mutationcreateepicconfidential"></a>`confidential` | [`Boolean`](#boolean) | Indicates if the epic is confidential. |
|
||||
| <a id="mutationcreateepicdescription"></a>`description` | [`String`](#string) | The description of the epic. |
|
||||
| <a id="mutationcreateepicduedatefixed"></a>`dueDateFixed` | [`String`](#string) | The end date of the epic. |
|
||||
| <a id="mutationcreateepicdescription"></a>`description` | [`String`](#string) | Description of the epic. |
|
||||
| <a id="mutationcreateepicduedatefixed"></a>`dueDateFixed` | [`String`](#string) | End date of the epic. |
|
||||
| <a id="mutationcreateepicduedateisfixed"></a>`dueDateIsFixed` | [`Boolean`](#boolean) | Indicates end date should be sourced from due_date_fixed field not the issue milestones. |
|
||||
| <a id="mutationcreateepicgrouppath"></a>`groupPath` | [`ID!`](#id) | The group the epic to mutate is in. |
|
||||
| <a id="mutationcreateepicremovelabelids"></a>`removeLabelIds` | [`[ID!]`](#id) | The IDs of labels to be removed from the epic. |
|
||||
| <a id="mutationcreateepicstartdatefixed"></a>`startDateFixed` | [`String`](#string) | The start date of the epic. |
|
||||
| <a id="mutationcreateepicgrouppath"></a>`groupPath` | [`ID!`](#id) | Group the epic to mutate is in. |
|
||||
| <a id="mutationcreateepicremovelabelids"></a>`removeLabelIds` | [`[ID!]`](#id) | IDs of labels to be removed from the epic. |
|
||||
| <a id="mutationcreateepicstartdatefixed"></a>`startDateFixed` | [`String`](#string) | Start date of the epic. |
|
||||
| <a id="mutationcreateepicstartdateisfixed"></a>`startDateIsFixed` | [`Boolean`](#boolean) | Indicates start date should be sourced from start_date_fixed field not the issue milestones. |
|
||||
| <a id="mutationcreateepictitle"></a>`title` | [`String`](#string) | The title of the epic. |
|
||||
| <a id="mutationcreateepictitle"></a>`title` | [`String`](#string) | Title of the epic. |
|
||||
|
||||
#### Fields
|
||||
|
||||
|
@ -1417,7 +1417,7 @@ Input type: `DastOnDemandScanCreateInput`
|
|||
| <a id="mutationdastondemandscancreateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
|
||||
| <a id="mutationdastondemandscancreatedastscannerprofileid"></a>`dastScannerProfileId` | [`DastScannerProfileID`](#dastscannerprofileid) | ID of the scanner profile to be used for the scan. |
|
||||
| <a id="mutationdastondemandscancreatedastsiteprofileid"></a>`dastSiteProfileId` | [`DastSiteProfileID!`](#dastsiteprofileid) | ID of the site profile to be used for the scan. |
|
||||
| <a id="mutationdastondemandscancreatefullpath"></a>`fullPath` | [`ID!`](#id) | The project the site profile belongs to. |
|
||||
| <a id="mutationdastondemandscancreatefullpath"></a>`fullPath` | [`ID!`](#id) | Project the site profile belongs to. |
|
||||
|
||||
#### Fields
|
||||
|
||||
|
@ -1435,13 +1435,13 @@ Input type: `DastProfileCreateInput`
|
|||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="mutationdastprofilecreatebranchname"></a>`branchName` | [`String`](#string) | The associated branch. |
|
||||
| <a id="mutationdastprofilecreatebranchname"></a>`branchName` | [`String`](#string) | Associated branch. |
|
||||
| <a id="mutationdastprofilecreateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
|
||||
| <a id="mutationdastprofilecreatedastscannerprofileid"></a>`dastScannerProfileId` | [`DastScannerProfileID!`](#dastscannerprofileid) | ID of the scanner profile to be associated. |
|
||||
| <a id="mutationdastprofilecreatedastsiteprofileid"></a>`dastSiteProfileId` | [`DastSiteProfileID!`](#dastsiteprofileid) | ID of the site profile to be associated. |
|
||||
| <a id="mutationdastprofilecreatedescription"></a>`description` | [`String`](#string) | The description of the profile. Defaults to an empty string. |
|
||||
| <a id="mutationdastprofilecreatefullpath"></a>`fullPath` | [`ID!`](#id) | The project the profile belongs to. |
|
||||
| <a id="mutationdastprofilecreatename"></a>`name` | [`String!`](#string) | The name of the profile. |
|
||||
| <a id="mutationdastprofilecreatedescription"></a>`description` | [`String`](#string) | Description of the profile. Defaults to an empty string. |
|
||||
| <a id="mutationdastprofilecreatefullpath"></a>`fullPath` | [`ID!`](#id) | Project the profile belongs to. |
|
||||
| <a id="mutationdastprofilecreatename"></a>`name` | [`String!`](#string) | Name of the profile. |
|
||||
| <a id="mutationdastprofilecreaterunaftercreate"></a>`runAfterCreate` | [`Boolean`](#boolean) | Run scan using profile after creation. Defaults to false. |
|
||||
|
||||
#### Fields
|
||||
|
@ -1449,9 +1449,9 @@ Input type: `DastProfileCreateInput`
|
|||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="mutationdastprofilecreateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
|
||||
| <a id="mutationdastprofilecreatedastprofile"></a>`dastProfile` | [`DastProfile`](#dastprofile) | The created profile. |
|
||||
| <a id="mutationdastprofilecreatedastprofile"></a>`dastProfile` | [`DastProfile`](#dastprofile) | Created profile. |
|
||||
| <a id="mutationdastprofilecreateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
|
||||
| <a id="mutationdastprofilecreatepipelineurl"></a>`pipelineUrl` | [`String`](#string) | The URL of the pipeline that was created. Requires `runAfterCreate` to be set to `true`. |
|
||||
| <a id="mutationdastprofilecreatepipelineurl"></a>`pipelineUrl` | [`String`](#string) | URL of the pipeline that was created. Requires `runAfterCreate` to be set to `true`. |
|
||||
|
||||
### `Mutation.dastProfileDelete`
|
||||
|
||||
|
@ -1499,14 +1499,14 @@ Input type: `DastProfileUpdateInput`
|
|||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="mutationdastprofileupdatebranchname"></a>`branchName` | [`String`](#string) | The associated branch. |
|
||||
| <a id="mutationdastprofileupdatebranchname"></a>`branchName` | [`String`](#string) | Associated branch. |
|
||||
| <a id="mutationdastprofileupdateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
|
||||
| <a id="mutationdastprofileupdatedastscannerprofileid"></a>`dastScannerProfileId` | [`DastScannerProfileID`](#dastscannerprofileid) | ID of the scanner profile to be associated. |
|
||||
| <a id="mutationdastprofileupdatedastsiteprofileid"></a>`dastSiteProfileId` | [`DastSiteProfileID`](#dastsiteprofileid) | ID of the site profile to be associated. |
|
||||
| <a id="mutationdastprofileupdatedescription"></a>`description` | [`String`](#string) | The description of the profile. Defaults to an empty string. |
|
||||
| <a id="mutationdastprofileupdatefullpath"></a>`fullPath` | [`ID!`](#id) | The project the profile belongs to. |
|
||||
| <a id="mutationdastprofileupdatedescription"></a>`description` | [`String`](#string) | Description of the profile. Defaults to an empty string. |
|
||||
| <a id="mutationdastprofileupdatefullpath"></a>`fullPath` | [`ID!`](#id) | Project the profile belongs to. |
|
||||
| <a id="mutationdastprofileupdateid"></a>`id` | [`DastProfileID!`](#dastprofileid) | ID of the profile to be deleted. |
|
||||
| <a id="mutationdastprofileupdatename"></a>`name` | [`String`](#string) | The name of the profile. |
|
||||
| <a id="mutationdastprofileupdatename"></a>`name` | [`String`](#string) | Name of the profile. |
|
||||
| <a id="mutationdastprofileupdaterunafterupdate"></a>`runAfterUpdate` | [`Boolean`](#boolean) | Run scan using profile after update. Defaults to false. |
|
||||
|
||||
#### Fields
|
||||
|
@ -1514,7 +1514,7 @@ Input type: `DastProfileUpdateInput`
|
|||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="mutationdastprofileupdateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
|
||||
| <a id="mutationdastprofileupdatedastprofile"></a>`dastProfile` | [`DastProfile`](#dastprofile) | The updated profile. |
|
||||
| <a id="mutationdastprofileupdatedastprofile"></a>`dastProfile` | [`DastProfile`](#dastprofile) | Updated profile. |
|
||||
| <a id="mutationdastprofileupdateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
|
||||
| <a id="mutationdastprofileupdatepipelineurl"></a>`pipelineUrl` | [`String`](#string) | The URL of the pipeline that was created. Requires the input argument `runAfterUpdate` to be set to `true` when calling the mutation, otherwise no pipeline will be created. |
|
||||
|
||||
|
@ -1527,12 +1527,12 @@ Input type: `DastScannerProfileCreateInput`
|
|||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="mutationdastscannerprofilecreateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
|
||||
| <a id="mutationdastscannerprofilecreatefullpath"></a>`fullPath` | [`ID!`](#id) | The project the scanner profile belongs to. |
|
||||
| <a id="mutationdastscannerprofilecreateprofilename"></a>`profileName` | [`String!`](#string) | The name of the scanner profile. |
|
||||
| <a id="mutationdastscannerprofilecreatefullpath"></a>`fullPath` | [`ID!`](#id) | Project the scanner profile belongs to. |
|
||||
| <a id="mutationdastscannerprofilecreateprofilename"></a>`profileName` | [`String!`](#string) | Name of the scanner profile. |
|
||||
| <a id="mutationdastscannerprofilecreatescantype"></a>`scanType` | [`DastScanTypeEnum`](#dastscantypeenum) | Indicates the type of DAST scan that will run. Either a Passive Scan or an Active Scan. |
|
||||
| <a id="mutationdastscannerprofilecreateshowdebugmessages"></a>`showDebugMessages` | [`Boolean`](#boolean) | Indicates if debug messages should be included in DAST console output. True to include the debug messages. |
|
||||
| <a id="mutationdastscannerprofilecreatespidertimeout"></a>`spiderTimeout` | [`Int`](#int) | The maximum number of minutes allowed for the spider to traverse the site. |
|
||||
| <a id="mutationdastscannerprofilecreatetargettimeout"></a>`targetTimeout` | [`Int`](#int) | The maximum number of seconds allowed for the site under test to respond to a request. |
|
||||
| <a id="mutationdastscannerprofilecreatespidertimeout"></a>`spiderTimeout` | [`Int`](#int) | Maximum number of minutes allowed for the spider to traverse the site. |
|
||||
| <a id="mutationdastscannerprofilecreatetargettimeout"></a>`targetTimeout` | [`Int`](#int) | Maximum number of seconds allowed for the site under test to respond to a request. |
|
||||
| <a id="mutationdastscannerprofilecreateuseajaxspider"></a>`useAjaxSpider` | [`Boolean`](#boolean) | Indicates if the AJAX spider should be used to crawl the target site. True to run the AJAX spider in addition to the traditional spider, and false to run only the traditional spider. |
|
||||
|
||||
#### Fields
|
||||
|
@ -1571,13 +1571,13 @@ Input type: `DastScannerProfileUpdateInput`
|
|||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="mutationdastscannerprofileupdateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
|
||||
| <a id="mutationdastscannerprofileupdatefullpath"></a>`fullPath` | [`ID!`](#id) | The project the scanner profile belongs to. |
|
||||
| <a id="mutationdastscannerprofileupdatefullpath"></a>`fullPath` | [`ID!`](#id) | Project the scanner profile belongs to. |
|
||||
| <a id="mutationdastscannerprofileupdateid"></a>`id` | [`DastScannerProfileID!`](#dastscannerprofileid) | ID of the scanner profile to be updated. |
|
||||
| <a id="mutationdastscannerprofileupdateprofilename"></a>`profileName` | [`String!`](#string) | The name of the scanner profile. |
|
||||
| <a id="mutationdastscannerprofileupdateprofilename"></a>`profileName` | [`String!`](#string) | Name of the scanner profile. |
|
||||
| <a id="mutationdastscannerprofileupdatescantype"></a>`scanType` | [`DastScanTypeEnum`](#dastscantypeenum) | Indicates the type of DAST scan that will run. Either a Passive Scan or an Active Scan. |
|
||||
| <a id="mutationdastscannerprofileupdateshowdebugmessages"></a>`showDebugMessages` | [`Boolean`](#boolean) | Indicates if debug messages should be included in DAST console output. True to include the debug messages. |
|
||||
| <a id="mutationdastscannerprofileupdatespidertimeout"></a>`spiderTimeout` | [`Int!`](#int) | The maximum number of minutes allowed for the spider to traverse the site. |
|
||||
| <a id="mutationdastscannerprofileupdatetargettimeout"></a>`targetTimeout` | [`Int!`](#int) | The maximum number of seconds allowed for the site under test to respond to a request. |
|
||||
| <a id="mutationdastscannerprofileupdatespidertimeout"></a>`spiderTimeout` | [`Int!`](#int) | Maximum number of minutes allowed for the spider to traverse the site. |
|
||||
| <a id="mutationdastscannerprofileupdatetargettimeout"></a>`targetTimeout` | [`Int!`](#int) | Maximum number of seconds allowed for the site under test to respond to a request. |
|
||||
| <a id="mutationdastscannerprofileupdateuseajaxspider"></a>`useAjaxSpider` | [`Boolean`](#boolean) | Indicates if the AJAX spider should be used to crawl the target site. True to run the AJAX spider in addition to the traditional spider, and false to run only the traditional spider. |
|
||||
|
||||
#### Fields
|
||||
|
@ -1598,12 +1598,12 @@ Input type: `DastSiteProfileCreateInput`
|
|||
| ---- | ---- | ----------- |
|
||||
| <a id="mutationdastsiteprofilecreateauth"></a>`auth` | [`DastSiteProfileAuthInput`](#dastsiteprofileauthinput) | Parameters for authentication. |
|
||||
| <a id="mutationdastsiteprofilecreateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
|
||||
| <a id="mutationdastsiteprofilecreateexcludedurls"></a>`excludedUrls` | [`[String!]`](#string) | The URLs to skip during an authenticated scan. Defaults to `[]`. |
|
||||
| <a id="mutationdastsiteprofilecreatefullpath"></a>`fullPath` | [`ID!`](#id) | The project the site profile belongs to. |
|
||||
| <a id="mutationdastsiteprofilecreateprofilename"></a>`profileName` | [`String!`](#string) | The name of the site profile. |
|
||||
| <a id="mutationdastsiteprofilecreateexcludedurls"></a>`excludedUrls` | [`[String!]`](#string) | URLs to skip during an authenticated scan. Defaults to `[]`. |
|
||||
| <a id="mutationdastsiteprofilecreatefullpath"></a>`fullPath` | [`ID!`](#id) | Project the site profile belongs to. |
|
||||
| <a id="mutationdastsiteprofilecreateprofilename"></a>`profileName` | [`String!`](#string) | Name of the site profile. |
|
||||
| <a id="mutationdastsiteprofilecreaterequestheaders"></a>`requestHeaders` | [`String`](#string) | Comma-separated list of request header names and values to be added to every request made by DAST. |
|
||||
| <a id="mutationdastsiteprofilecreatetargettype"></a>`targetType` | [`DastTargetTypeEnum`](#dasttargettypeenum) | The type of target to be scanned. |
|
||||
| <a id="mutationdastsiteprofilecreatetargeturl"></a>`targetUrl` | [`String`](#string) | The URL of the target to be scanned. |
|
||||
| <a id="mutationdastsiteprofilecreatetargettype"></a>`targetType` | [`DastTargetTypeEnum`](#dasttargettypeenum) | Type of target to be scanned. |
|
||||
| <a id="mutationdastsiteprofilecreatetargeturl"></a>`targetUrl` | [`String`](#string) | URL of the target to be scanned. |
|
||||
|
||||
#### Fields
|
||||
|
||||
|
@ -1622,7 +1622,7 @@ Input type: `DastSiteProfileDeleteInput`
|
|||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="mutationdastsiteprofiledeleteclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
|
||||
| <a id="mutationdastsiteprofiledeletefullpath"></a>`fullPath` | [`ID!`](#id) | The project the site profile belongs to. |
|
||||
| <a id="mutationdastsiteprofiledeletefullpath"></a>`fullPath` | [`ID!`](#id) | Project the site profile belongs to. |
|
||||
| <a id="mutationdastsiteprofiledeleteid"></a>`id` | [`DastSiteProfileID!`](#dastsiteprofileid) | ID of the site profile to be deleted. |
|
||||
|
||||
#### Fields
|
||||
|
@ -1642,13 +1642,13 @@ Input type: `DastSiteProfileUpdateInput`
|
|||
| ---- | ---- | ----------- |
|
||||
| <a id="mutationdastsiteprofileupdateauth"></a>`auth` | [`DastSiteProfileAuthInput`](#dastsiteprofileauthinput) | Parameters for authentication. |
|
||||
| <a id="mutationdastsiteprofileupdateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
|
||||
| <a id="mutationdastsiteprofileupdateexcludedurls"></a>`excludedUrls` | [`[String!]`](#string) | The URLs to skip during an authenticated scan. |
|
||||
| <a id="mutationdastsiteprofileupdatefullpath"></a>`fullPath` | [`ID!`](#id) | The project the site profile belongs to. |
|
||||
| <a id="mutationdastsiteprofileupdateexcludedurls"></a>`excludedUrls` | [`[String!]`](#string) | URLs to skip during an authenticated scan. |
|
||||
| <a id="mutationdastsiteprofileupdatefullpath"></a>`fullPath` | [`ID!`](#id) | Project the site profile belongs to. |
|
||||
| <a id="mutationdastsiteprofileupdateid"></a>`id` | [`DastSiteProfileID!`](#dastsiteprofileid) | ID of the site profile to be updated. |
|
||||
| <a id="mutationdastsiteprofileupdateprofilename"></a>`profileName` | [`String!`](#string) | The name of the site profile. |
|
||||
| <a id="mutationdastsiteprofileupdateprofilename"></a>`profileName` | [`String!`](#string) | Name of the site profile. |
|
||||
| <a id="mutationdastsiteprofileupdaterequestheaders"></a>`requestHeaders` | [`String`](#string) | Comma-separated list of request header names and values to be added to every request made by DAST. |
|
||||
| <a id="mutationdastsiteprofileupdatetargettype"></a>`targetType` | [`DastTargetTypeEnum`](#dasttargettypeenum) | The type of target to be scanned. |
|
||||
| <a id="mutationdastsiteprofileupdatetargeturl"></a>`targetUrl` | [`String`](#string) | The URL of the target to be scanned. |
|
||||
| <a id="mutationdastsiteprofileupdatetargettype"></a>`targetType` | [`DastTargetTypeEnum`](#dasttargettypeenum) | Type of target to be scanned. |
|
||||
| <a id="mutationdastsiteprofileupdatetargeturl"></a>`targetUrl` | [`String`](#string) | URL of the target to be scanned. |
|
||||
|
||||
#### Fields
|
||||
|
||||
|
@ -1667,8 +1667,8 @@ Input type: `DastSiteTokenCreateInput`
|
|||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="mutationdastsitetokencreateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
|
||||
| <a id="mutationdastsitetokencreatefullpath"></a>`fullPath` | [`ID!`](#id) | The project the site token belongs to. |
|
||||
| <a id="mutationdastsitetokencreatetargeturl"></a>`targetUrl` | [`String`](#string) | The URL of the target to be validated. |
|
||||
| <a id="mutationdastsitetokencreatefullpath"></a>`fullPath` | [`ID!`](#id) | Project the site token belongs to. |
|
||||
| <a id="mutationdastsitetokencreatetargeturl"></a>`targetUrl` | [`String`](#string) | URL of the target to be validated. |
|
||||
|
||||
#### Fields
|
||||
|
||||
|
@ -1677,7 +1677,7 @@ Input type: `DastSiteTokenCreateInput`
|
|||
| <a id="mutationdastsitetokencreateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
|
||||
| <a id="mutationdastsitetokencreateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
|
||||
| <a id="mutationdastsitetokencreateid"></a>`id` | [`DastSiteTokenID`](#dastsitetokenid) | ID of the site token. |
|
||||
| <a id="mutationdastsitetokencreatestatus"></a>`status` | [`DastSiteProfileValidationStatusEnum`](#dastsiteprofilevalidationstatusenum) | The current validation status of the target. |
|
||||
| <a id="mutationdastsitetokencreatestatus"></a>`status` | [`DastSiteProfileValidationStatusEnum`](#dastsiteprofilevalidationstatusenum) | Current validation status of the target. |
|
||||
| <a id="mutationdastsitetokencreatetoken"></a>`token` | [`String`](#string) | Token string. |
|
||||
|
||||
### `Mutation.dastSiteValidationCreate`
|
||||
|
@ -1690,9 +1690,9 @@ Input type: `DastSiteValidationCreateInput`
|
|||
| ---- | ---- | ----------- |
|
||||
| <a id="mutationdastsitevalidationcreateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
|
||||
| <a id="mutationdastsitevalidationcreatedastsitetokenid"></a>`dastSiteTokenId` | [`DastSiteTokenID!`](#dastsitetokenid) | ID of the site token. |
|
||||
| <a id="mutationdastsitevalidationcreatefullpath"></a>`fullPath` | [`ID!`](#id) | The project the site profile belongs to. |
|
||||
| <a id="mutationdastsitevalidationcreatestrategy"></a>`strategy` | [`DastSiteValidationStrategyEnum`](#dastsitevalidationstrategyenum) | The validation strategy to be used. |
|
||||
| <a id="mutationdastsitevalidationcreatevalidationpath"></a>`validationPath` | [`String!`](#string) | The path to be requested during validation. |
|
||||
| <a id="mutationdastsitevalidationcreatefullpath"></a>`fullPath` | [`ID!`](#id) | Project the site profile belongs to. |
|
||||
| <a id="mutationdastsitevalidationcreatestrategy"></a>`strategy` | [`DastSiteValidationStrategyEnum`](#dastsitevalidationstrategyenum) | Validation strategy to be used. |
|
||||
| <a id="mutationdastsitevalidationcreatevalidationpath"></a>`validationPath` | [`String!`](#string) | Path to be requested during validation. |
|
||||
|
||||
#### Fields
|
||||
|
||||
|
@ -1701,7 +1701,7 @@ Input type: `DastSiteValidationCreateInput`
|
|||
| <a id="mutationdastsitevalidationcreateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
|
||||
| <a id="mutationdastsitevalidationcreateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
|
||||
| <a id="mutationdastsitevalidationcreateid"></a>`id` | [`DastSiteValidationID`](#dastsitevalidationid) | ID of the site validation. |
|
||||
| <a id="mutationdastsitevalidationcreatestatus"></a>`status` | [`DastSiteProfileValidationStatusEnum`](#dastsiteprofilevalidationstatusenum) | The current validation status. |
|
||||
| <a id="mutationdastsitevalidationcreatestatus"></a>`status` | [`DastSiteProfileValidationStatusEnum`](#dastsiteprofilevalidationstatusenum) | Current validation status. |
|
||||
|
||||
### `Mutation.dastSiteValidationRevoke`
|
||||
|
||||
|
@ -1712,7 +1712,7 @@ Input type: `DastSiteValidationRevokeInput`
|
|||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="mutationdastsitevalidationrevokeclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
|
||||
| <a id="mutationdastsitevalidationrevokefullpath"></a>`fullPath` | [`ID!`](#id) | The project the site validation belongs to. |
|
||||
| <a id="mutationdastsitevalidationrevokefullpath"></a>`fullPath` | [`ID!`](#id) | Project the site validation belongs to. |
|
||||
| <a id="mutationdastsitevalidationrevokenormalizedtargeturl"></a>`normalizedTargetUrl` | [`String!`](#string) | Normalized URL of the target to be revoked. |
|
||||
|
||||
#### Fields
|
||||
|
@ -1851,7 +1851,7 @@ Input type: `DestroyComplianceFrameworkInput`
|
|||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="mutationdestroycomplianceframeworkclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
|
||||
| <a id="mutationdestroycomplianceframeworkid"></a>`id` | [`ComplianceManagementFrameworkID!`](#compliancemanagementframeworkid) | The global ID of the compliance framework to destroy. |
|
||||
| <a id="mutationdestroycomplianceframeworkid"></a>`id` | [`ComplianceManagementFrameworkID!`](#compliancemanagementframeworkid) | Global ID of the compliance framework to destroy. |
|
||||
|
||||
#### Fields
|
||||
|
||||
|
@ -2144,7 +2144,7 @@ Input type: `EpicBoardCreateInput`
|
|||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="mutationepicboardcreateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
|
||||
| <a id="mutationepicboardcreateepicboard"></a>`epicBoard` | [`EpicBoard`](#epicboard) | The created epic board. |
|
||||
| <a id="mutationepicboardcreateepicboard"></a>`epicBoard` | [`EpicBoard`](#epicboard) | Created epic board. |
|
||||
| <a id="mutationepicboardcreateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
|
||||
|
||||
### `Mutation.epicBoardListCreate`
|
||||
|
@ -2187,7 +2187,7 @@ Input type: `EpicBoardListDestroyInput`
|
|||
| ---- | ---- | ----------- |
|
||||
| <a id="mutationepicboardlistdestroyclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
|
||||
| <a id="mutationepicboardlistdestroyerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
|
||||
| <a id="mutationepicboardlistdestroylist"></a>`list` | [`EpicList`](#epiclist) | The epic board list. `null` if the board was destroyed successfully. |
|
||||
| <a id="mutationepicboardlistdestroylist"></a>`list` | [`EpicList`](#epiclist) | Epic board list. `null` if the board was destroyed successfully. |
|
||||
|
||||
### `Mutation.epicBoardUpdate`
|
||||
|
||||
|
@ -2200,7 +2200,7 @@ Input type: `EpicBoardUpdateInput`
|
|||
| <a id="mutationepicboardupdateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
|
||||
| <a id="mutationepicboardupdatehidebackloglist"></a>`hideBacklogList` | [`Boolean`](#boolean) | Whether or not backlog list is hidden. |
|
||||
| <a id="mutationepicboardupdatehideclosedlist"></a>`hideClosedList` | [`Boolean`](#boolean) | Whether or not closed list is hidden. |
|
||||
| <a id="mutationepicboardupdateid"></a>`id` | [`BoardsEpicBoardID!`](#boardsepicboardid) | The epic board global ID. |
|
||||
| <a id="mutationepicboardupdateid"></a>`id` | [`BoardsEpicBoardID!`](#boardsepicboardid) | Epic board global ID. |
|
||||
| <a id="mutationepicboardupdatelabelids"></a>`labelIds` | [`[LabelID!]`](#labelid) | IDs of labels to be added to the board. |
|
||||
| <a id="mutationepicboardupdatelabels"></a>`labels` | [`[String!]`](#string) | Labels of the issue. |
|
||||
| <a id="mutationepicboardupdatename"></a>`name` | [`String`](#string) | Board name. |
|
||||
|
@ -2210,7 +2210,7 @@ Input type: `EpicBoardUpdateInput`
|
|||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="mutationepicboardupdateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
|
||||
| <a id="mutationepicboardupdateepicboard"></a>`epicBoard` | [`EpicBoard`](#epicboard) | The updated epic board. |
|
||||
| <a id="mutationepicboardupdateepicboard"></a>`epicBoard` | [`EpicBoard`](#epicboard) | Updated epic board. |
|
||||
| <a id="mutationepicboardupdateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
|
||||
|
||||
### `Mutation.epicMoveList`
|
||||
|
@ -2234,7 +2234,7 @@ Input type: `EpicMoveListInput`
|
|||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="mutationepicmovelistclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
|
||||
| <a id="mutationepicmovelistepic"></a>`epic` | [`Epic`](#epic) | The epic after mutation. |
|
||||
| <a id="mutationepicmovelistepic"></a>`epic` | [`Epic`](#epic) | Epic after mutation. |
|
||||
| <a id="mutationepicmovelisterrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
|
||||
|
||||
### `Mutation.epicSetSubscription`
|
||||
|
@ -4099,7 +4099,7 @@ Input type: `UpdateBoardEpicUserPreferencesInput`
|
|||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="mutationupdateboardepicuserpreferencesboardid"></a>`boardId` | [`BoardID!`](#boardid) | The board global ID. |
|
||||
| <a id="mutationupdateboardepicuserpreferencesboardid"></a>`boardId` | [`BoardID!`](#boardid) | Board global ID. |
|
||||
| <a id="mutationupdateboardepicuserpreferencesclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
|
||||
| <a id="mutationupdateboardepicuserpreferencescollapsed"></a>`collapsed` | [`Boolean!`](#boolean) | Whether the epic should be collapsed in the board. |
|
||||
| <a id="mutationupdateboardepicuserpreferencesepicid"></a>`epicId` | [`EpicID!`](#epicid) | ID of an epic to set preferences for. |
|
||||
|
@ -4142,7 +4142,7 @@ Input type: `UpdateComplianceFrameworkInput`
|
|||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="mutationupdatecomplianceframeworkclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
|
||||
| <a id="mutationupdatecomplianceframeworkid"></a>`id` | [`ComplianceManagementFrameworkID!`](#compliancemanagementframeworkid) | The global ID of the compliance framework to update. |
|
||||
| <a id="mutationupdatecomplianceframeworkid"></a>`id` | [`ComplianceManagementFrameworkID!`](#compliancemanagementframeworkid) | Global ID of the compliance framework to update. |
|
||||
| <a id="mutationupdatecomplianceframeworkparams"></a>`params` | [`ComplianceFrameworkInput!`](#complianceframeworkinput) | Parameters to update the compliance framework with. |
|
||||
|
||||
#### Fields
|
||||
|
@ -4150,7 +4150,7 @@ Input type: `UpdateComplianceFrameworkInput`
|
|||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="mutationupdatecomplianceframeworkclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
|
||||
| <a id="mutationupdatecomplianceframeworkcomplianceframework"></a>`complianceFramework` | [`ComplianceFramework`](#complianceframework) | The compliance framework after mutation. |
|
||||
| <a id="mutationupdatecomplianceframeworkcomplianceframework"></a>`complianceFramework` | [`ComplianceFramework`](#complianceframework) | Compliance framework after mutation. |
|
||||
| <a id="mutationupdatecomplianceframeworkerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
|
||||
|
||||
### `Mutation.updateContainerExpirationPolicy`
|
||||
|
@ -4186,19 +4186,19 @@ Input type: `UpdateEpicInput`
|
|||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="mutationupdateepicaddlabelids"></a>`addLabelIds` | [`[ID!]`](#id) | The IDs of labels to be added to the epic. |
|
||||
| <a id="mutationupdateepicaddlabelids"></a>`addLabelIds` | [`[ID!]`](#id) | IDs of labels to be added to the epic. |
|
||||
| <a id="mutationupdateepicclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
|
||||
| <a id="mutationupdateepicconfidential"></a>`confidential` | [`Boolean`](#boolean) | Indicates if the epic is confidential. |
|
||||
| <a id="mutationupdateepicdescription"></a>`description` | [`String`](#string) | The description of the epic. |
|
||||
| <a id="mutationupdateepicduedatefixed"></a>`dueDateFixed` | [`String`](#string) | The end date of the epic. |
|
||||
| <a id="mutationupdateepicdescription"></a>`description` | [`String`](#string) | Description of the epic. |
|
||||
| <a id="mutationupdateepicduedatefixed"></a>`dueDateFixed` | [`String`](#string) | End date of the epic. |
|
||||
| <a id="mutationupdateepicduedateisfixed"></a>`dueDateIsFixed` | [`Boolean`](#boolean) | Indicates end date should be sourced from due_date_fixed field not the issue milestones. |
|
||||
| <a id="mutationupdateepicgrouppath"></a>`groupPath` | [`ID!`](#id) | The group the epic to mutate is in. |
|
||||
| <a id="mutationupdateepicgrouppath"></a>`groupPath` | [`ID!`](#id) | Group the epic to mutate is in. |
|
||||
| <a id="mutationupdateepiciid"></a>`iid` | [`ID!`](#id) | The IID of the epic to mutate. |
|
||||
| <a id="mutationupdateepicremovelabelids"></a>`removeLabelIds` | [`[ID!]`](#id) | The IDs of labels to be removed from the epic. |
|
||||
| <a id="mutationupdateepicstartdatefixed"></a>`startDateFixed` | [`String`](#string) | The start date of the epic. |
|
||||
| <a id="mutationupdateepicremovelabelids"></a>`removeLabelIds` | [`[ID!]`](#id) | IDs of labels to be removed from the epic. |
|
||||
| <a id="mutationupdateepicstartdatefixed"></a>`startDateFixed` | [`String`](#string) | Start date of the epic. |
|
||||
| <a id="mutationupdateepicstartdateisfixed"></a>`startDateIsFixed` | [`Boolean`](#boolean) | Indicates start date should be sourced from start_date_fixed field not the issue milestones. |
|
||||
| <a id="mutationupdateepicstateevent"></a>`stateEvent` | [`EpicStateEvent`](#epicstateevent) | State event for the epic. |
|
||||
| <a id="mutationupdateepictitle"></a>`title` | [`String`](#string) | The title of the epic. |
|
||||
| <a id="mutationupdateepictitle"></a>`title` | [`String`](#string) | Title of the epic. |
|
||||
|
||||
#### Fields
|
||||
|
||||
|
|
|
@ -552,7 +552,7 @@ Example response:
|
|||
"state": "active",
|
||||
"avatar_url": "https://www.gravatar.com/avatar/c2525a7f58ae3776070e44c106c48e15?s=80&d=identicon",
|
||||
"web_url": "http://192.168.1.8:3000/root",
|
||||
"expires_at": "2012-10-22T14:13:35Z",
|
||||
"expires_at": "2012-10-22",
|
||||
"access_level": 40,
|
||||
"email": "john@example.com",
|
||||
"override": false
|
||||
|
|
|
@ -77,12 +77,12 @@ The single entrypoint for the registry is the [HTTP API](https://gitlab.com/gitl
|
|||
|
||||
| Operation | UI | Background | Observations |
|
||||
| ------------------------------------------------------------ | ------------------ | ------------------------ | ------------------------------------------------------------ |
|
||||
| [Check API version](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#api-version-check) | :heavy_check_mark: | :heavy_check_mark: | Used globally to ensure that the registry supports the Docker Distribution V2 API, as well as for identifying whether GitLab Rails is talking to the GitLab Container Registry or a third-party one (used to toggle features only available in the former). |
|
||||
| [List repository tags](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#listing-image-tags) | :heavy_check_mark: | :heavy_check_mark: | Used to list and show tags in the UI. Used to list tags in the background for [cleanup policies](../../../user/packages/container_registry/#cleanup-policy) and [Geo replication](../../../administration/geo/replication/docker_registry.md). |
|
||||
| [Check if manifest exists](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#existing-manifests) | :heavy_check_mark: | :heavy_multiplication_x: | Used to get the digest of a manifest by tag. This is then used to pull the manifest and show the tag details in the UI. |
|
||||
| [Pull manifest](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#pulling-an-image-manifest) | :heavy_check_mark: | :heavy_multiplication_x: | Used to show the image size and the manifest digest in the tag details UI. |
|
||||
| [Pull blob](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#pulling-a-layer) | :heavy_check_mark: | :heavy_multiplication_x: | Used to show the configuration digest and the creation date in the tag details UI. |
|
||||
| [Delete tag](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#deleting-a-tag) | :heavy_check_mark: | :heavy_check_mark: | Used to delete a tag from the UI and in background (cleanup policies). |
|
||||
| [Check API version](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#api-version-check) | **{check-circle}** Yes | **{check-circle}** Yes | Used globally to ensure that the registry supports the Docker Distribution V2 API, as well as for identifying whether GitLab Rails is talking to the GitLab Container Registry or a third-party one (used to toggle features only available in the former). |
|
||||
| [List repository tags](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#listing-image-tags) | **{check-circle}** Yes | **{check-circle}** Yes | Used to list and show tags in the UI. Used to list tags in the background for [cleanup policies](../../../user/packages/container_registry/#cleanup-policy) and [Geo replication](../../../administration/geo/replication/docker_registry.md). |
|
||||
| [Check if manifest exists](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#existing-manifests) | **{check-circle}** Yes | **{dotted-circle}** No | Used to get the digest of a manifest by tag. This is then used to pull the manifest and show the tag details in the UI. |
|
||||
| [Pull manifest](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#pulling-an-image-manifest) | **{check-circle}** Yes | **{dotted-circle}** No | Used to show the image size and the manifest digest in the tag details UI. |
|
||||
| [Pull blob](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#pulling-a-layer) | **{check-circle}** Yes | **{dotted-circle}** No | Used to show the configuration digest and the creation date in the tag details UI. |
|
||||
| [Delete tag](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#deleting-a-tag) | **{check-circle}** Yes | **{check-circle}** Yes | Used to delete a tag from the UI and in background (cleanup policies). |
|
||||
|
||||
A valid authentication token is generated in GitLab Rails and embedded in all these requests before sending them to the registry.
|
||||
|
||||
|
@ -211,22 +211,22 @@ This is a list of all the registry HTTP API operations and how they depend on th
|
|||
|
||||
| Operation | Method | Path | Requires Database | Requires Storage | Used by GitLab Rails * |
|
||||
|--------------------------------------------------------------------------------------------------------------------------------|----------|-----------------------------------------|-------------------|------------------|------------------------|
|
||||
| [Check API version](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#api-version-check) | `GET` | `/v2/` | ✖ | ✖ | ✔ |
|
||||
| [List repositories](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#listing-repositories) | `GET` | `/v2/_catalog` | ✔ | ✖ | ✖ |
|
||||
| [List repository tags](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#listing-image-tags) | `GET` | `/v2/<name>/tags/list` | ✔ | ✖ | ✔ |
|
||||
| [Delete tag](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#deleting-a-tag) | `DELETE` | `/v2/<name>/tags/reference/<reference>` | ✔ | ✖ | ✔ |
|
||||
| [Check if manifest exists](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#existing-manifests) | `HEAD` | `/v2/<name>/manifests/<reference>` | ✔ | ✖ | ✔ |
|
||||
| [Pull manifest](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#pulling-an-image-manifest) | `GET` | `/v2/<name>/manifests/<reference>` | ✔ | ✖ | ✔ |
|
||||
| [Push manifest](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#pushing-an-image-manifest) | `PUT` | `/v2/<name>/manifests/<reference>` | ✔ | ✖ | ✖ |
|
||||
| [Delete manifest](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#deleting-an-image) | `DELETE` | `/v2/<name>/manifests/<reference>` | ✔ | ✖ | ✖ |
|
||||
| [Check if blob exists](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#existing-layers) | `HEAD` | `/v2/<name>/blobs/<digest>` | ✔ | ✖ | ✖ |
|
||||
| [Pull blob](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#fetch-blob) | `GET` | `/v2/<name>/blobs/<digest>` | ✔ | ✔ | ✔ |
|
||||
| [Delete blob](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#delete-blob) | `DELETE` | `/v2/<name>/blobs/<digest>` | ✔ | ✖ | ✖ |
|
||||
| [Start blob upload](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#starting-an-upload) | `POST` | `/v2/<name>/blobs/uploads/` | ✔ | ✔ | ✖ |
|
||||
| [Check blob upload status](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#get-blob-upload) | `GET` | `/v2/<name>/blobs/uploads/<uuid>` | ✔ | ✔ | ✖ |
|
||||
| [Push blob chunk](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#chunked-upload-1) | `PATCH` | `/v2/<name>/blobs/uploads/<uuid>` | ✔ | ✔ | ✖ |
|
||||
| [Complete blob upload](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#put-blob-upload) | `PUT` | `/v2/<name>/blobs/uploads/<uuid>` | ✔ | ✔ | ✖ |
|
||||
| [Cancel blob upload](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#canceling-an-upload) | `DELETE` | `/v2/<name>/blobs/uploads/<uuid>` | ✔ | ✔ | ✖ |
|
||||
| [Check API version](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#api-version-check) | `GET` | `/v2/` | **{dotted-circle}** No | **{dotted-circle}** No | **{check-circle}** Yes |
|
||||
| [List repositories](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#listing-repositories) | `GET` | `/v2/_catalog` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No |
|
||||
| [List repository tags](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#listing-image-tags) | `GET` | `/v2/<name>/tags/list` | **{check-circle}** Yes | **{dotted-circle}** No | **{check-circle}** Yes |
|
||||
| [Delete tag](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#deleting-a-tag) | `DELETE` | `/v2/<name>/tags/reference/<reference>` | **{check-circle}** Yes | **{dotted-circle}** No | **{check-circle}** Yes |
|
||||
| [Check if manifest exists](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#existing-manifests) | `HEAD` | `/v2/<name>/manifests/<reference>` | **{check-circle}** Yes | **{dotted-circle}** No | **{check-circle}** Yes |
|
||||
| [Pull manifest](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#pulling-an-image-manifest) | `GET` | `/v2/<name>/manifests/<reference>` | **{check-circle}** Yes | **{dotted-circle}** No | **{check-circle}** Yes |
|
||||
| [Push manifest](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#pushing-an-image-manifest) | `PUT` | `/v2/<name>/manifests/<reference>` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No |
|
||||
| [Delete manifest](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#deleting-an-image) | `DELETE` | `/v2/<name>/manifests/<reference>` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No |
|
||||
| [Check if blob exists](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#existing-layers) | `HEAD` | `/v2/<name>/blobs/<digest>` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No |
|
||||
| [Pull blob](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#fetch-blob) | `GET` | `/v2/<name>/blobs/<digest>` | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes |
|
||||
| [Delete blob](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#delete-blob) | `DELETE` | `/v2/<name>/blobs/<digest>` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No |
|
||||
| [Start blob upload](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#starting-an-upload) | `POST` | `/v2/<name>/blobs/uploads/` | **{check-circle}** Yes | **{check-circle}** Yes | **{dotted-circle}** No |
|
||||
| [Check blob upload status](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#get-blob-upload) | `GET` | `/v2/<name>/blobs/uploads/<uuid>` | **{check-circle}** Yes | **{check-circle}** Yes | **{dotted-circle}** No |
|
||||
| [Push blob chunk](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#chunked-upload-1) | `PATCH` | `/v2/<name>/blobs/uploads/<uuid>` | **{check-circle}** Yes | **{check-circle}** Yes | **{dotted-circle}** No |
|
||||
| [Complete blob upload](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#put-blob-upload) | `PUT` | `/v2/<name>/blobs/uploads/<uuid>` | **{check-circle}** Yes | **{check-circle}** Yes | **{dotted-circle}** No |
|
||||
| [Cancel blob upload](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/api.md#canceling-an-upload) | `DELETE` | `/v2/<name>/blobs/uploads/<uuid>` | **{check-circle}** Yes | **{check-circle}** Yes | **{dotted-circle}** No |
|
||||
|
||||
`*` Please refer to the [list of interactions between registry and Rails](#from-gitlab-rails-to-registry) to know why and how.
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ read the [Introduction to CI/CD with GitLab](introduction/index.md).
|
|||
<iframe src="https://www.youtube.com/embed/1iXFbchozdY" frameborder="0" allowfullscreen="true"> </iframe>
|
||||
</figure>
|
||||
|
||||
## Concepts
|
||||
## GitLab CI/CD concepts
|
||||
|
||||
GitLab CI/CD uses a number of concepts to describe and run your build and deploy.
|
||||
|
||||
|
@ -53,7 +53,7 @@ GitLab CI/CD uses a number of concepts to describe and run your build and deploy
|
|||
| [Pipeline efficiency](pipelines/pipeline_efficiency.md) | Configure your pipelines to run quickly and efficiently. |
|
||||
| [Test cases](test_cases/index.md) | Create testing scenarios. |
|
||||
|
||||
## Configuration
|
||||
## GitLab CI/CD configuration
|
||||
|
||||
GitLab CI/CD supports numerous configuration options:
|
||||
|
||||
|
@ -72,7 +72,7 @@ GitLab CI/CD supports numerous configuration options:
|
|||
Certain operations can only be performed according to the
|
||||
[user](../user/permissions.md#gitlab-cicd-permissions) and [job](../user/permissions.md#job-permissions) permissions.
|
||||
|
||||
## Features
|
||||
## GitLab CI/CD features
|
||||
|
||||
GitLab CI/CD features, grouped by DevOps stage, include:
|
||||
|
||||
|
@ -109,7 +109,7 @@ GitLab CI/CD features, grouped by DevOps stage, include:
|
|||
| [License Compliance](../user/compliance/license_compliance/index.md) **(ULTIMATE)** | Search your project dependencies for their licenses. |
|
||||
| [Security Test reports](../user/application_security/index.md) **(ULTIMATE)** | Check for app vulnerabilities. |
|
||||
|
||||
## Examples
|
||||
## GitLab CI/CD examples
|
||||
|
||||
See the [CI/CD examples](examples/README.md) page for example project code and tutorials for
|
||||
using GitLab CI/CD with various:
|
||||
|
@ -118,7 +118,7 @@ using GitLab CI/CD with various:
|
|||
- Languages
|
||||
- Platforms
|
||||
|
||||
## Administration
|
||||
## GitLab CI/CD Administration
|
||||
|
||||
You can change the default behavior of GitLab CI/CD for:
|
||||
|
||||
|
|
|
@ -199,7 +199,7 @@ GitLab takes advantage of our connected ecosystem to automatically pull these ki
|
|||
your Merge Requests, pipeline details pages, and other locations. You may find that you actually don't
|
||||
need to configure anything to have these appear.
|
||||
|
||||
If they aren't working as expected, or if you'd like to see what's available, our [CI feature index](../index.md#features) has the full list
|
||||
If they aren't working as expected, or if you'd like to see what's available, our [CI feature index](../index.md#gitlab-cicd-features) has the full list
|
||||
of bundled features and links to the documentation for each.
|
||||
|
||||
### Templates
|
||||
|
|
|
@ -40,9 +40,7 @@ It's recommended to create two separate migration script files.
|
|||
desired limit using `create_or_update_plan_limit` migration helper, such as:
|
||||
|
||||
```ruby
|
||||
class InsertProjectHooksPlanLimits < ActiveRecord::Migration[5.2]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
class InsertProjectHooksPlanLimits < Gitlab::Database::Migration[1.0]
|
||||
def up
|
||||
create_or_update_plan_limit('project_hooks', 'default', 0)
|
||||
create_or_update_plan_limit('project_hooks', 'free', 10)
|
||||
|
|
|
@ -95,9 +95,7 @@ renaming. For example
|
|||
|
||||
```ruby
|
||||
# A regular migration in db/migrate
|
||||
class RenameUsersUpdatedAtToUpdatedAtTimestamp < ActiveRecord::Migration[4.2]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
class RenameUsersUpdatedAtToUpdatedAtTimestamp < Gitlab::Database::Migration[1.0]
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
|
@ -125,9 +123,7 @@ We can perform this cleanup using
|
|||
|
||||
```ruby
|
||||
# A post-deployment migration in db/post_migrate
|
||||
class CleanupUsersUpdatedAtRename < ActiveRecord::Migration[4.2]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
class CleanupUsersUpdatedAtRename < Gitlab::Database::Migration[1.0]
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
|
@ -174,9 +170,7 @@ as follows:
|
|||
|
||||
```ruby
|
||||
# A regular migration in db/migrate
|
||||
class ChangeUsersUsernameStringToText < ActiveRecord::Migration[4.2]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
class ChangeUsersUsernameStringToText < Gitlab::Database::Migration[1.0]
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
|
@ -195,9 +189,7 @@ Next we need to clean up our changes using a post-deployment migration:
|
|||
|
||||
```ruby
|
||||
# A post-deployment migration in db/post_migrate
|
||||
class ChangeUsersUsernameStringToTextCleanup < ActiveRecord::Migration[4.2]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
class ChangeUsersUsernameStringToTextCleanup < Gitlab::Database::Migration[1.0]
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
|
@ -245,9 +237,7 @@ the work / load over a longer time period, without slowing down deployments.
|
|||
For example, to change the column type using a background migration:
|
||||
|
||||
```ruby
|
||||
class ExampleMigration < ActiveRecord::Migration[4.2]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
class ExampleMigration < Gitlab::Database::Migration[1.0]
|
||||
disable_ddl_transaction!
|
||||
|
||||
class Issue < ActiveRecord::Base
|
||||
|
@ -289,9 +279,7 @@ release) by a cleanup migration, which should steal from the queue and handle
|
|||
any remaining rows. For example:
|
||||
|
||||
```ruby
|
||||
class MigrateRemainingIssuesClosedAt < ActiveRecord::Migration[4.2]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
class MigrateRemainingIssuesClosedAt < Gitlab::Database::Migration[1.0]
|
||||
disable_ddl_transaction!
|
||||
|
||||
class Issue < ActiveRecord::Base
|
||||
|
|
|
@ -254,7 +254,7 @@ existing data. Since we're dealing with a lot of rows we'll schedule jobs in
|
|||
batches instead of doing this one by one:
|
||||
|
||||
```ruby
|
||||
class ScheduleExtractServicesUrl < ActiveRecord::Migration[4.2]
|
||||
class ScheduleExtractServicesUrl < Gitlab::Database::Migration[1.0]
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
|
@ -281,7 +281,7 @@ jobs and manually run on any un-migrated rows. Such a migration would look like
|
|||
this:
|
||||
|
||||
```ruby
|
||||
class ConsumeRemainingExtractServicesUrlJobs < ActiveRecord::Migration[4.2]
|
||||
class ConsumeRemainingExtractServicesUrlJobs < Gitlab::Database::Migration[1.0]
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
|
@ -463,8 +463,6 @@ end
|
|||
|
||||
```ruby
|
||||
# Post deployment migration
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
MIGRATION = 'YourBackgroundMigrationName'
|
||||
DELAY_INTERVAL = 2.minutes.to_i # can be different
|
||||
BATCH_SIZE = 10_000 # can be different
|
||||
|
@ -494,8 +492,6 @@ You can reschedule pending migrations from the `background_migration_jobs` table
|
|||
|
||||
```ruby
|
||||
# Post deployment migration
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
MIGRATION = 'YourBackgroundMigrationName'
|
||||
DELAY_INTERVAL = 2.minutes
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ Settings are not cascading by default. To define a cascading setting, take the f
|
|||
`application_settings`.
|
||||
|
||||
```ruby
|
||||
class AddDelayedProjectRemovalCascadingSetting < ActiveRecord::Migration[6.0]
|
||||
class AddDelayedProjectRemovalCascadingSetting < Gitlab::Database::Migration[1.0]
|
||||
include Gitlab::Database::MigrationHelpers::CascadingNamespaceSettings
|
||||
|
||||
def up
|
||||
|
|
|
@ -66,9 +66,7 @@ In the example above, you'd be still able to update records in the `emails` tabl
|
|||
Migration file for adding `NOT VALID` foreign key:
|
||||
|
||||
```ruby
|
||||
class AddNotValidForeignKeyToEmailsUser < ActiveRecord::Migration[5.2]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
class AddNotValidForeignKeyToEmailsUser < Gitlab::Database::Migration[1.0]
|
||||
def up
|
||||
# safe to use: it requires short lock on the table since we don't validate the foreign key
|
||||
add_foreign_key :emails, :users, on_delete: :cascade, validate: false
|
||||
|
@ -92,9 +90,7 @@ In case the data volume is higher (>1000 records), it's better to create a backg
|
|||
Example for cleaning up records in the `emails` table within a database migration:
|
||||
|
||||
```ruby
|
||||
class RemoveRecordsWithoutUserFromEmailsTable < ActiveRecord::Migration[5.2]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
class RemoveRecordsWithoutUserFromEmailsTable < Gitlab::Database::Migration[1.0]
|
||||
disable_ddl_transaction!
|
||||
|
||||
class Email < ActiveRecord::Base
|
||||
|
@ -126,9 +122,7 @@ Migration file for validating the foreign key:
|
|||
```ruby
|
||||
# frozen_string_literal: true
|
||||
|
||||
class ValidateForeignKeyOnEmailUsers < ActiveRecord::Migration[5.2]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
class ValidateForeignKeyOnEmailUsers < Gitlab::Database::Migration[1.0]
|
||||
def up
|
||||
validate_foreign_key :emails, :user_id
|
||||
end
|
||||
|
|
|
@ -25,7 +25,7 @@ For example, consider a migration that creates a table with two `NOT NULL` colum
|
|||
`db/migrate/20200401000001_create_db_guides.rb`:
|
||||
|
||||
```ruby
|
||||
class CreateDbGuides < ActiveRecord::Migration[6.0]
|
||||
class CreateDbGuides < Gitlab::Database::Migration[1.0]
|
||||
def change
|
||||
create_table :db_guides do |t|
|
||||
t.bigint :stars, default: 0, null: false
|
||||
|
@ -44,7 +44,7 @@ For example, consider a migration that adds a new `NOT NULL` column `active` to
|
|||
`db/migrate/20200501000001_add_active_to_db_guides.rb`:
|
||||
|
||||
```ruby
|
||||
class AddExtendedTitleToSprints < ActiveRecord::Migration[6.0]
|
||||
class AddExtendedTitleToSprints < Gitlab::Database::Migration[1.0]
|
||||
def change
|
||||
add_column :db_guides, :active, :boolean, default: true, null: false
|
||||
end
|
||||
|
@ -111,9 +111,7 @@ with `validate: false` in a post-deployment migration,
|
|||
`db/post_migrate/20200501000001_add_not_null_constraint_to_epics_description.rb`:
|
||||
|
||||
```ruby
|
||||
class AddNotNullConstraintToEpicsDescription < ActiveRecord::Migration[6.0]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
class AddNotNullConstraintToEpicsDescription < Gitlab::Database::Migration[1.0]
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
|
@ -144,9 +142,7 @@ so we are going to add a post-deployment migration for the 13.0 milestone (curre
|
|||
`db/post_migrate/20200501000002_cleanup_epics_with_null_description.rb`:
|
||||
|
||||
```ruby
|
||||
class CleanupEpicsWithNullDescription < ActiveRecord::Migration[6.0]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
class CleanupEpicsWithNullDescription < Gitlab::Database::Migration[1.0]
|
||||
# With BATCH_SIZE=1000 and epics.count=29500 on GitLab.com
|
||||
# - 30 iterations will be run
|
||||
# - each requires on average ~150ms
|
||||
|
@ -184,9 +180,7 @@ migration helper in a final post-deployment migration,
|
|||
`db/post_migrate/20200601000001_validate_not_null_constraint_on_epics_description.rb`:
|
||||
|
||||
```ruby
|
||||
class ValidateNotNullConstraintOnEpicsDescription < ActiveRecord::Migration[6.0]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
class ValidateNotNullConstraintOnEpicsDescription < Gitlab::Database::Migration[1.0]
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
|
|
|
@ -60,8 +60,6 @@ Consider the next release as "Release N.M".
|
|||
Execute a standard migration (not a post-migration):
|
||||
|
||||
```ruby
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
def up
|
||||
rename_table_safely(:issues, :tickets)
|
||||
end
|
||||
|
@ -96,8 +94,6 @@ At this point, we don't have applications using the old database table name in t
|
|||
1. Remove the database view through a post-migration:
|
||||
|
||||
```ruby
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
def up
|
||||
finalize_table_rename(:issues, :tickets)
|
||||
end
|
||||
|
|
|
@ -47,9 +47,7 @@ For example, consider a migration that creates a table with two text columns,
|
|||
`db/migrate/20200401000001_create_db_guides.rb`:
|
||||
|
||||
```ruby
|
||||
class CreateDbGuides < ActiveRecord::Migration[6.0]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
class CreateDbGuides < Gitlab::Database::Migration[1.0]
|
||||
def up
|
||||
create_table_with_constraints :db_guides do |t|
|
||||
t.bigint :stars, default: 0, null: false
|
||||
|
@ -84,7 +82,7 @@ For example, consider a migration that adds a new text column `extended_title` t
|
|||
`db/migrate/20200501000001_add_extended_title_to_sprints.rb`:
|
||||
|
||||
```ruby
|
||||
class AddExtendedTitleToSprints < ActiveRecord::Migration[6.0]
|
||||
class AddExtendedTitleToSprints < Gitlab::Database::Migration[1.0]
|
||||
|
||||
# rubocop:disable Migration/AddLimitToTextColumns
|
||||
# limit is added in 20200501000002_add_text_limit_to_sprints_extended_title
|
||||
|
@ -99,8 +97,7 @@ A second migration should follow the first one with a limit added to `extended_t
|
|||
`db/migrate/20200501000002_add_text_limit_to_sprints_extended_title.rb`:
|
||||
|
||||
```ruby
|
||||
class AddTextLimitToSprintsExtendedTitle < ActiveRecord::Migration[6.0]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
class AddTextLimitToSprintsExtendedTitle < Gitlab::Database::Migration[1.0]
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
|
@ -175,9 +172,7 @@ in a post-deployment migration,
|
|||
`db/post_migrate/20200501000001_add_text_limit_migration.rb`:
|
||||
|
||||
```ruby
|
||||
class AddTextLimitMigration < ActiveRecord::Migration[6.0]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
class AddTextLimitMigration < Gitlab::Database::Migration[1.0]
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
|
@ -208,9 +203,7 @@ to add a background migration for the 13.0 milestone (current),
|
|||
`db/post_migrate/20200501000002_schedule_cap_title_length_on_issues.rb`:
|
||||
|
||||
```ruby
|
||||
class ScheduleCapTitleLengthOnIssues < ActiveRecord::Migration[6.0]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
class ScheduleCapTitleLengthOnIssues < Gitlab::Database::Migration[1.0]
|
||||
# Info on how many records will be affected on GitLab.com
|
||||
# time each batch needs to run on average, etc ...
|
||||
BATCH_SIZE = 5000
|
||||
|
@ -255,9 +248,7 @@ helper in a final post-deployment migration,
|
|||
`db/post_migrate/20200601000001_validate_text_limit_migration.rb`:
|
||||
|
||||
```ruby
|
||||
class ValidateTextLimitMigration < ActiveRecord::Migration[6.0]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
class ValidateTextLimitMigration < Gitlab::Database::Migration[1.0]
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
|
|
|
@ -173,7 +173,7 @@ An example migration of partitioning the `audit_events` table by its
|
|||
`created_at` column would look like:
|
||||
|
||||
```ruby
|
||||
class PartitionAuditEvents < ActiveRecord::Migration[6.0]
|
||||
class PartitionAuditEvents < Gitlab::Database::Migration[1.0]
|
||||
include Gitlab::Database::PartitioningMigrationHelpers
|
||||
|
||||
def up
|
||||
|
@ -200,7 +200,7 @@ into the partitioned copy.
|
|||
Continuing the above example, the migration would look like:
|
||||
|
||||
```ruby
|
||||
class BackfillPartitionAuditEvents < ActiveRecord::Migration[6.0]
|
||||
class BackfillPartitionAuditEvents < Gitlab::Database::Migration[1.0]
|
||||
include Gitlab::Database::PartitioningMigrationHelpers
|
||||
|
||||
def up
|
||||
|
@ -233,7 +233,7 @@ failed jobs.
|
|||
Once again, continuing the example, this migration would look like:
|
||||
|
||||
```ruby
|
||||
class CleanupPartitionedAuditEventsBackfill < ActiveRecord::Migration[6.0]
|
||||
class CleanupPartitionedAuditEventsBackfill < Gitlab::Database::Migration[1.0]
|
||||
include Gitlab::Database::PartitioningMigrationHelpers
|
||||
|
||||
def up
|
||||
|
|
|
@ -171,6 +171,45 @@ If you need to translate strings in the Vue component's JavaScript, you can impo
|
|||
|
||||
To test Vue translations, learn about [manually testing translations from the UI](#manually-test-translations-from-the-ui).
|
||||
|
||||
### Test files
|
||||
|
||||
Test expectations against externalized contents should not be hard coded,
|
||||
because we may need to run the tests with non-default locale, and tests with
|
||||
hard coded contents will fail.
|
||||
|
||||
This means any expectations against externalized contents should call the
|
||||
same externalizing method to match the translation.
|
||||
|
||||
Bad:
|
||||
|
||||
```ruby
|
||||
click_button 'Submit review'
|
||||
|
||||
expect(rendered).to have_content('Thank you for your feedback!')
|
||||
```
|
||||
|
||||
Good:
|
||||
|
||||
```ruby
|
||||
click_button _('Submit review')
|
||||
|
||||
expect(rendered).to have_content(_('Thank you for your feedback!'))
|
||||
```
|
||||
|
||||
This includes JavaScript tests:
|
||||
|
||||
Bad:
|
||||
|
||||
```javascript
|
||||
expect(findUpdateIgnoreStatusButton().text()).toBe('Ignore');
|
||||
```
|
||||
|
||||
Good:
|
||||
|
||||
```javascript
|
||||
expect(findUpdateIgnoreStatusButton().text()).toBe(__('Ignore'));
|
||||
```
|
||||
|
||||
#### Recommendations
|
||||
|
||||
If strings are reused throughout a component, it can be useful to define these strings as variables. We recommend defining an `i18n` property on the component's `$options` object. If there is a mixture of many-use and single-use strings in the component, consider using this approach to create a local [Single Source of Truth](https://about.gitlab.com/handbook/values/#single-source-of-truth) for externalized strings.
|
||||
|
|
|
@ -70,7 +70,7 @@ graph LR
|
|||
|
||||
H -->|Yes| E[Regular migration]
|
||||
H -->|No| I[Post-deploy migration<br/>+ feature flag]
|
||||
|
||||
|
||||
D -->|Yes| F[Post-deploy migration]
|
||||
D -->|No| G[Background migration]
|
||||
```
|
||||
|
@ -217,6 +217,39 @@ In case you need to insert, update, or delete a significant amount of data, you:
|
|||
- Must disable the single transaction with `disable_ddl_transaction!`.
|
||||
- Should consider doing it in a [Background Migration](background_migrations.md).
|
||||
|
||||
## Migration helpers and versioning
|
||||
|
||||
Various helper methods are available for many common patterns in database migrations. Those
|
||||
helpers can be found in `Gitlab::Database::MigrationHelpers` and related modules.
|
||||
|
||||
In order to allow changing a helper's behavior over time, we implement a versioning scheme
|
||||
for migration helpers. This allows us to maintain the behavior of a helper for already
|
||||
existing migrations but change the behavior for any new migrations.
|
||||
|
||||
For that purpose, all database migrations should inherit from `Gitlab::Database::Migration`,
|
||||
which is a "versioned" class. For new migrations, the latest version should be used (which
|
||||
can be looked up in `Gitlab::Database::Migration::MIGRATION_CLASSES`) to use the latest version
|
||||
of migration helpers.
|
||||
|
||||
In this example, we use version 1.0 of the migration class:
|
||||
|
||||
```ruby
|
||||
class TestMigration < Gitlab::Database::Migration[1.0]
|
||||
def change
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
NOTE:
|
||||
It is discouraged to include `Gitlab::Database::MigrationHelpers` directly into a
|
||||
migration. Instead, the latest version of `Gitlab::Database::Migration` will expose the latest
|
||||
version of migration helpers automatically.
|
||||
|
||||
NOTE:
|
||||
Migration helpers and versioning are available starting from [14.3](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/68986).
|
||||
For merge requests targeting previous stable branches, the old format needs to be used and we continue
|
||||
to inherit from `ActiveRecord::Migration[6.1]` instead of `Gitlab::Database::Migration[1.0]` for those.
|
||||
|
||||
## Retry mechanism when acquiring database locks
|
||||
|
||||
When changing the database schema, we use helper methods to invoke DDL (Data Definition
|
||||
|
@ -256,8 +289,6 @@ lock allow the database to process other statements.
|
|||
**Removing a column:**
|
||||
|
||||
```ruby
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
def up
|
||||
with_lock_retries do
|
||||
remove_column :users, :full_name
|
||||
|
@ -278,8 +309,6 @@ you should do as much as possible inside the transaction rather than trying to g
|
|||
Be careful about running long database statements within the block. The acquired locks are kept until the transaction (block) finishes and depending on the lock type, it might block other database operations.
|
||||
|
||||
```ruby
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
def up
|
||||
with_lock_retries do
|
||||
add_column :users, :full_name, :string
|
||||
|
@ -298,8 +327,6 @@ end
|
|||
**Removing a foreign key:**
|
||||
|
||||
```ruby
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
def up
|
||||
with_lock_retries do
|
||||
remove_foreign_key :issues, :projects
|
||||
|
@ -316,8 +343,6 @@ end
|
|||
**Changing default value for a column:**
|
||||
|
||||
```ruby
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
def up
|
||||
with_lock_retries do
|
||||
change_column_default :merge_requests, :lock_version, from: nil, to: 0
|
||||
|
@ -387,8 +412,6 @@ We can use the `add_concurrent_foreign_key` method in this case, as this helper
|
|||
has the lock retries built into it.
|
||||
|
||||
```ruby
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
|
@ -405,8 +428,6 @@ end
|
|||
Adding foreign key to `users`:
|
||||
|
||||
```ruby
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
|
@ -498,11 +519,11 @@ by calling the method `disable_ddl_transaction!` in the body of your migration
|
|||
class like so:
|
||||
|
||||
```ruby
|
||||
class MyMigration < ActiveRecord::Migration[6.0]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
class MyMigration < Gitlab::Database::Migration[1.0]
|
||||
disable_ddl_transaction!
|
||||
|
||||
INDEX_NAME = 'index_name'
|
||||
|
||||
def up
|
||||
remove_concurrent_index :table_name, :column_name, name: INDEX_NAME
|
||||
end
|
||||
|
@ -549,7 +570,7 @@ by calling the method `disable_ddl_transaction!` in the body of your migration
|
|||
class like so:
|
||||
|
||||
```ruby
|
||||
class MyMigration < ActiveRecord::Migration[6.0]
|
||||
class MyMigration < Gitlab::Database::Migration[1.0]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
@ -594,7 +615,7 @@ The easiest way to test for existence of an index by name is to use the
|
|||
be used with a name option. For example:
|
||||
|
||||
```ruby
|
||||
class MyMigration < ActiveRecord::Migration[6.0]
|
||||
class MyMigration < Gitlab::Database::Migration[1.0]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
INDEX_NAME = 'index_name'
|
||||
|
@ -631,7 +652,7 @@ Here's an example where we add a new column with a foreign key
|
|||
constraint. Note it includes `index: true` to create an index for it.
|
||||
|
||||
```ruby
|
||||
class Migration < ActiveRecord::Migration[6.0]
|
||||
class Migration < Gitlab::Database::Migration[1.0]
|
||||
|
||||
def change
|
||||
add_reference :model, :other_model, index: true, foreign_key: { on_delete: :cascade }
|
||||
|
@ -677,7 +698,7 @@ expensive and disruptive operation for larger tables, but in reality it's not.
|
|||
Take the following migration as an example:
|
||||
|
||||
```ruby
|
||||
class DefaultRequestAccessGroups < ActiveRecord::Migration[5.2]
|
||||
class DefaultRequestAccessGroups < Gitlab::Database::Migration[1.0]
|
||||
def change
|
||||
change_column_default(:namespaces, :request_access_enabled, from: false, to: true)
|
||||
end
|
||||
|
@ -884,7 +905,7 @@ The Rails 5 natively supports `JSONB` (binary JSON) column type.
|
|||
Example migration adding this column:
|
||||
|
||||
```ruby
|
||||
class AddOptionsToBuildMetadata < ActiveRecord::Migration[5.0]
|
||||
class AddOptionsToBuildMetadata < Gitlab::Database::Migration[1.0]
|
||||
def change
|
||||
add_column :ci_builds_metadata, :config_options, :jsonb
|
||||
end
|
||||
|
@ -916,7 +937,7 @@ Do not store `attr_encrypted` attributes as `:text` in the database; use
|
|||
efficient:
|
||||
|
||||
```ruby
|
||||
class AddSecretToSomething < ActiveRecord::Migration[5.0]
|
||||
class AddSecretToSomething < Gitlab::Database::Migration[1.0]
|
||||
def change
|
||||
add_column :something, :encrypted_secret, :binary
|
||||
add_column :something, :encrypted_secret_iv, :binary
|
||||
|
@ -974,7 +995,7 @@ If you need more complex logic, you can define and use models local to a
|
|||
migration. For example:
|
||||
|
||||
```ruby
|
||||
class MyMigration < ActiveRecord::Migration[6.0]
|
||||
class MyMigration < Gitlab::Database::Migration[1.0]
|
||||
class Project < ActiveRecord::Base
|
||||
self.table_name = 'projects'
|
||||
end
|
||||
|
@ -1073,7 +1094,7 @@ in a previous migration.
|
|||
It is important not to leave out the `User.reset_column_information` command, in order to ensure that the old schema is dropped from the cache and ActiveRecord loads the updated schema information.
|
||||
|
||||
```ruby
|
||||
class AddAndSeedMyColumn < ActiveRecord::Migration[6.0]
|
||||
class AddAndSeedMyColumn < Gitlab::Database::Migration[1.0]
|
||||
class User < ActiveRecord::Base
|
||||
self.table_name = 'users'
|
||||
end
|
||||
|
|
|
@ -36,9 +36,7 @@ After you add or change an existing common metric, you must [re-run the import s
|
|||
Or, you can create a database migration:
|
||||
|
||||
```ruby
|
||||
class ImportCommonMetrics < ActiveRecord::Migration[4.2]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
class ImportCommonMetrics < Gitlab::Database::Migration[1.0]
|
||||
def up
|
||||
::Gitlab::DatabaseImporters::CommonMetrics::Importer.new.execute
|
||||
end
|
||||
|
|
|
@ -1002,9 +1002,7 @@ When renaming queues, use the `sidekiq_queue_migrate` helper migration method
|
|||
in a **post-deployment migration**:
|
||||
|
||||
```ruby
|
||||
class MigrateTheRenamedSidekiqQueue < ActiveRecord::Migration[5.0]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
class MigrateTheRenamedSidekiqQueue < Gitlab::Database::Migration[1.0]
|
||||
def up
|
||||
sidekiq_queue_migrate 'old_queue_name', to: 'new_queue_name'
|
||||
end
|
||||
|
|
|
@ -31,7 +31,7 @@ could result in loading unexpected code or associations which may cause unintend
|
|||
side effects or failures during upgrades.
|
||||
|
||||
```ruby
|
||||
class SomeMigration < ActiveRecord::Migration[6.0]
|
||||
class SomeMigration < Gitlab::Database::Migration[1.0]
|
||||
class Services < ActiveRecord::Base
|
||||
self.table_name = 'services'
|
||||
self.inheritance_column = :_type_disabled
|
||||
|
@ -47,7 +47,7 @@ This ensures that the migration loads the columns for the migration in isolation
|
|||
and the helper disables STI by default.
|
||||
|
||||
```ruby
|
||||
class EnqueueSomeBackgroundMigration < ActiveRecord::Migration[6.0]
|
||||
class EnqueueSomeBackgroundMigration < Gitlab::Database::Migration[1.0]
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
|
|
|
@ -102,7 +102,7 @@ transaction. Transactions for migrations can be disabled using the following
|
|||
pattern:
|
||||
|
||||
```ruby
|
||||
class MigrationName < ActiveRecord::Migration[4.2]
|
||||
class MigrationName < Gitlab::Database::Migration[1.0]
|
||||
disable_ddl_transaction!
|
||||
end
|
||||
```
|
||||
|
@ -110,7 +110,7 @@ end
|
|||
For example:
|
||||
|
||||
```ruby
|
||||
class AddUsersLowerUsernameEmailIndexes < ActiveRecord::Migration[4.2]
|
||||
class AddUsersLowerUsernameEmailIndexes < Gitlab::Database::Migration[1.0]
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
|
|
|
@ -367,26 +367,34 @@ If needed, you can scope interactions within a specific area of the page by usin
|
|||
As you will likely be scoping to an element such as a `div`, which typically does not have a label,
|
||||
you may use a `data-testid` selector in this case.
|
||||
|
||||
##### Externalized contents
|
||||
|
||||
Test expectations against externalized contents should call the same
|
||||
externalizing method to match the translation. For example, you should use the `_`
|
||||
method in Ruby and `__` method in JavaScript.
|
||||
|
||||
See [Internationalization for GitLab - Test files](../i18n/externalization.md#test-files) for details.
|
||||
|
||||
##### Actions
|
||||
|
||||
Where possible, use more specific [actions](https://rubydoc.info/github/teamcapybara/capybara/master/Capybara/Node/Actions), such as the ones below.
|
||||
|
||||
```ruby
|
||||
# good
|
||||
click_button 'Submit review'
|
||||
click_button _('Submit review')
|
||||
|
||||
click_link 'UI testing docs'
|
||||
click_link _('UI testing docs')
|
||||
|
||||
fill_in 'Search projects', with: 'gitlab' # fill in text input with text
|
||||
fill_in _('Search projects'), with: 'gitlab' # fill in text input with text
|
||||
|
||||
select 'Last updated', from: 'Sort by' # select an option from a select input
|
||||
select _('Last updated'), from: 'Sort by' # select an option from a select input
|
||||
|
||||
check 'Checkbox label'
|
||||
uncheck 'Checkbox label'
|
||||
check _('Checkbox label')
|
||||
uncheck _('Checkbox label')
|
||||
|
||||
choose 'Radio input label'
|
||||
choose _('Radio input label')
|
||||
|
||||
attach_file('Attach a file', '/path/to/file.png')
|
||||
attach_file(_('Attach a file'), '/path/to/file.png')
|
||||
|
||||
# bad - interactive elements must have accessible names, so
|
||||
# we should be able to use one of the specific actions above
|
||||
|
@ -403,17 +411,17 @@ Where possible, use more specific [finders](https://rubydoc.info/github/teamcapy
|
|||
|
||||
```ruby
|
||||
# good
|
||||
find_button 'Submit review'
|
||||
find_button 'Submit review', disabled: true
|
||||
find_button _('Submit review')
|
||||
find_button _('Submit review'), disabled: true
|
||||
|
||||
find_link 'UI testing docs'
|
||||
find_link 'UI testing docs', href: docs_url
|
||||
find_link _('UI testing docs')
|
||||
find_link _('UI testing docs'), href: docs_url
|
||||
|
||||
find_field 'Search projects'
|
||||
find_field 'Search projects', with: 'gitlab' # find the input field with text
|
||||
find_field 'Search projects', disabled: true
|
||||
find_field 'Checkbox label', checked: true
|
||||
find_field 'Checkbox label', unchecked: true
|
||||
find_field _('Search projects')
|
||||
find_field _('Search projects'), with: 'gitlab' # find the input field with text
|
||||
find_field _('Search projects'), disabled: true
|
||||
find_field _('Checkbox label'), checked: true
|
||||
find_field _('Checkbox label'), unchecked: true
|
||||
|
||||
# acceptable when finding a element that is not a button, link, or field
|
||||
find('[data-testid="element"]')
|
||||
|
@ -425,31 +433,31 @@ Where possible, use more specific [matchers](https://rubydoc.info/github/teamcap
|
|||
|
||||
```ruby
|
||||
# good
|
||||
expect(page).to have_button 'Submit review'
|
||||
expect(page).to have_button 'Submit review', disabled: true
|
||||
expect(page).to have_button 'Notifications', class: 'is-checked' # assert the "Notifications" GlToggle is checked
|
||||
expect(page).to have_button _('Submit review')
|
||||
expect(page).to have_button _('Submit review'), disabled: true
|
||||
expect(page).to have_button _('Notifications'), class: 'is-checked' # assert the "Notifications" GlToggle is checked
|
||||
|
||||
expect(page).to have_link 'UI testing docs'
|
||||
expect(page).to have_link 'UI testing docs', href: docs_url # assert the link has an href
|
||||
expect(page).to have_link _('UI testing docs')
|
||||
expect(page).to have_link _('UI testing docs'), href: docs_url # assert the link has an href
|
||||
|
||||
expect(page).to have_field 'Search projects'
|
||||
expect(page).to have_field 'Search projects', disabled: true
|
||||
expect(page).to have_field 'Search projects', with: 'gitlab' # assert the input field has text
|
||||
expect(page).to have_field _('Search projects')
|
||||
expect(page).to have_field _('Search projects'), disabled: true
|
||||
expect(page).to have_field _('Search projects'), with: 'gitlab' # assert the input field has text
|
||||
|
||||
expect(page).to have_checked_field 'Checkbox label'
|
||||
expect(page).to have_unchecked_field 'Radio input label'
|
||||
expect(page).to have_checked_field _('Checkbox label')
|
||||
expect(page).to have_unchecked_field _('Radio input label')
|
||||
|
||||
expect(page).to have_select 'Sort by'
|
||||
expect(page).to have_select 'Sort by', selected: 'Last updated' # assert the option is selected
|
||||
expect(page).to have_select 'Sort by', options: ['Last updated', 'Created date', 'Due date'] # assert an exact list of options
|
||||
expect(page).to have_select 'Sort by', with_options: ['Created date', 'Due date'] # assert a partial list of options
|
||||
expect(page).to have_select _('Sort by')
|
||||
expect(page).to have_select _('Sort by'), selected: 'Last updated' # assert the option is selected
|
||||
expect(page).to have_select _('Sort by'), options: ['Last updated', 'Created date', 'Due date'] # assert an exact list of options
|
||||
expect(page).to have_select _('Sort by'), with_options: ['Created date', 'Due date'] # assert a partial list of options
|
||||
|
||||
expect(page).to have_text 'Some paragraph text.'
|
||||
expect(page).to have_text 'Some paragraph text.', exact: true # assert exact match
|
||||
expect(page).to have_text _('Some paragraph text.')
|
||||
expect(page).to have_text _('Some paragraph text.'), exact: true # assert exact match
|
||||
|
||||
expect(page).to have_current_path 'gitlab/gitlab-test/-/issues'
|
||||
|
||||
expect(page).to have_title 'Not Found'
|
||||
expect(page).to have_title _('Not Found')
|
||||
|
||||
# acceptable when a more specific matcher above is not possible
|
||||
expect(page).to have_css 'h2', text: 'Issue title'
|
||||
|
|
|
@ -34,6 +34,7 @@ These are rate limits you can set in the Admin Area of your instance:
|
|||
- [Raw endpoints rate limits](../user/admin_area/settings/rate_limits_on_raw_endpoints.md)
|
||||
- [User and IP rate limits](../user/admin_area/settings/user_and_ip_rate_limits.md)
|
||||
- [Package registry rate limits](../user/admin_area/settings/package_registry_rate_limits.md)
|
||||
- [Git LFS rate limits](../user/admin_area/settings/git_lfs_rate_limits.md)
|
||||
|
||||
## Non-configurable limits
|
||||
|
||||
|
|
35
doc/user/admin_area/settings/git_lfs_rate_limits.md
Normal file
35
doc/user/admin_area/settings/git_lfs_rate_limits.md
Normal file
|
@ -0,0 +1,35 @@
|
|||
---
|
||||
stage: Create
|
||||
group: Source Code
|
||||
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
|
||||
type: reference
|
||||
---
|
||||
|
||||
# Git LFS Rate Limits **(FREE SELF)**
|
||||
|
||||
[Git LFS (Large File Storage)](../../../topics/git/lfs/index.md) is a Git extension
|
||||
for handling large files. If you use Git LFS in your repository, common Git operations
|
||||
can generate many Git LFS requests. You can enforce
|
||||
[general user and IP rate limits](user_and_ip_rate_limits.md), but you can also
|
||||
override the general setting to enforce additional limits on Git LFS requests. This
|
||||
override can improve the security and durability of your web application. Aside from
|
||||
precedence, this configuration provides the same features as the general user and IP
|
||||
rate limits.
|
||||
|
||||
## Configure Git LFS rate limits
|
||||
|
||||
Git LFS rate limits are disabled by default. If enabled and configured, these limits
|
||||
supersede the [general user and IP rate limits](user_and_ip_rate_limits.md):
|
||||
|
||||
1. On the top bar, select **Menu >** **{admin}** **Admin**.
|
||||
1. On the left sidebar, select **Settings > Network**.
|
||||
1. Expand **Git LFS Rate Limits**.
|
||||
1. Select **Enable authenticated Git LFS request rate limit**.
|
||||
1. Enter a value for **Max authenticated Git LFS requests per period per user**.
|
||||
1. Enter a value for **Authenticated Git LFS rate limit period in seconds**.
|
||||
1. Select **Save changes**.
|
||||
|
||||
## Resources
|
||||
|
||||
- [Rate limiting](../../../security/rate_limits.md)
|
||||
- [User and IP rate limits](user_and_ip_rate_limits.md)
|
|
@ -96,6 +96,7 @@ To access the default page for Admin Area settings:
|
|||
| Performance optimization | [Write to "authorized_keys" file](../../../administration/operations/fast_ssh_key_lookup.md#setting-up-fast-lookup-via-gitlab-shell) and [Push event activities limit and bulk push events](push_event_activities_limit.md). Various settings that affect GitLab performance. |
|
||||
| [User and IP rate limits](user_and_ip_rate_limits.md) | Configure limits for web and API requests. |
|
||||
| [Package Registry Rate Limits](package_registry_rate_limits.md) | Configure specific limits for Packages API requests that supersede the user and IP rate limits. |
|
||||
| [Git LFS Rate Limits](git_lfs_rate_limits.md) | Configure specific limits for Git LFS requests that supersede the user and IP rate limits. |
|
||||
| [Outbound requests](../../../security/webhooks.md) | Allow requests to the local network from hooks and services. |
|
||||
| [Protected Paths](protected_paths.md) | Configure paths to be protected by Rack Attack. |
|
||||
| [Incident Management](../../../operations/incident_management/index.md) Limits | Limit the number of inbound alerts that can be sent to a project. |
|
||||
|
|
|
@ -136,6 +136,7 @@ The possible names are:
|
|||
- `throttle_authenticated_protected_paths_web`
|
||||
- `throttle_unauthenticated_packages_api`
|
||||
- `throttle_authenticated_packages_api`
|
||||
- `throttle_authenticated_git_lfs`
|
||||
|
||||
For example, to try out throttles for all authenticated requests to
|
||||
non-protected paths can be done by setting
|
||||
|
|
|
@ -3,10 +3,7 @@
|
|||
# See https://docs.gitlab.com/ee/development/migration_style_guide.html
|
||||
# for more information on how to write migrations for GitLab.
|
||||
|
||||
class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
|
||||
# Uncomment the following include if you require helper functions:
|
||||
# include Gitlab::Database::MigrationHelpers
|
||||
|
||||
class <%= migration_class_name %> < Gitlab::Database::Migration[<%= Gitlab::Database::Migration.current_version %>]
|
||||
# When using the methods "add_concurrent_index" or "remove_concurrent_index"
|
||||
# you must disable the use of transactions
|
||||
# as these methods can not run in an existing transaction.
|
||||
|
|
|
@ -3,10 +3,7 @@
|
|||
# See https://docs.gitlab.com/ee/development/migration_style_guide.html
|
||||
# for more information on how to write migrations for GitLab.
|
||||
|
||||
class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
|
||||
# Uncomment the following include if you require helper functions:
|
||||
# include Gitlab::Database::MigrationHelpers
|
||||
|
||||
class <%= migration_class_name %> < Gitlab::Database::Migration[<%= Gitlab::Database::Migration.current_version %>]
|
||||
# When using the methods "add_concurrent_index" or "remove_concurrent_index"
|
||||
# you must disable the use of transactions
|
||||
# as these methods can not run in an existing transaction.
|
||||
|
@ -20,6 +17,9 @@ class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Mi
|
|||
# comments:
|
||||
# disable_ddl_transaction!
|
||||
|
||||
def change
|
||||
def up
|
||||
end
|
||||
|
||||
def down
|
||||
end
|
||||
end
|
||||
|
|
|
@ -338,6 +338,10 @@ module Gitlab
|
|||
Gitlab::PathRegex.repository_git_route_regex.match?(current_request.path)
|
||||
end
|
||||
|
||||
def git_lfs_request?
|
||||
Gitlab::PathRegex.repository_git_lfs_route_regex.match?(current_request.path)
|
||||
end
|
||||
|
||||
def archive_request?
|
||||
current_request.path.include?('/-/archive/')
|
||||
end
|
||||
|
|
36
lib/gitlab/database/migration.rb
Normal file
36
lib/gitlab/database/migration.rb
Normal file
|
@ -0,0 +1,36 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Gitlab
|
||||
module Database
|
||||
class Migration
|
||||
# This implements a simple versioning scheme for migration helpers.
|
||||
#
|
||||
# We need to be able to version helpers, so we can change their behavior without
|
||||
# altering the behavior of already existing migrations in incompatible ways.
|
||||
#
|
||||
# We can continue to change the behavior of helpers without bumping the version here,
|
||||
# *if* the change is backwards-compatible.
|
||||
#
|
||||
# If not, we would typically override the helper method in a new MigrationHelpers::V[0-9]+
|
||||
# class and create a new entry with a bumped version below.
|
||||
#
|
||||
# We use major version bumps to indicate significant changes and minor version bumps
|
||||
# to indicate backwards-compatible or otherwise minor changes (e.g. a Rails version bump).
|
||||
# However, this hasn't been strictly formalized yet.
|
||||
MIGRATION_CLASSES = {
|
||||
1.0 => Class.new(ActiveRecord::Migration[6.1]) do
|
||||
include Gitlab::Database::MigrationHelpers::V2
|
||||
end
|
||||
}.freeze
|
||||
|
||||
def self.[](version)
|
||||
MIGRATION_CLASSES[version] || raise(ArgumentError, "Unknown migration version: #{version}")
|
||||
end
|
||||
|
||||
# The current version to be used in new migrations
|
||||
def self.current_version
|
||||
1.0
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -20,7 +20,8 @@ module Gitlab
|
|||
:throttle_authenticated_web,
|
||||
:throttle_authenticated_protected_paths_api,
|
||||
:throttle_authenticated_protected_paths_web,
|
||||
:throttle_authenticated_packages_api
|
||||
:throttle_authenticated_packages_api,
|
||||
:throttle_authenticated_git_lfs
|
||||
].freeze
|
||||
|
||||
PAYLOAD_KEYS = [
|
||||
|
|
|
@ -184,6 +184,10 @@ module Gitlab
|
|||
@repository_git_route_regex ||= /#{repository_route_regex}\.git/.freeze
|
||||
end
|
||||
|
||||
def repository_git_lfs_route_regex
|
||||
@repository_git_lfs_route_regex ||= %r{#{repository_git_route_regex}\/(info\/lfs|gitlab-lfs)\/}.freeze
|
||||
end
|
||||
|
||||
def repository_wiki_git_route_regex
|
||||
@repository_wiki_git_route_regex ||= /#{full_namespace_route_regex}\.*\.wiki\.git/.freeze
|
||||
end
|
||||
|
|
|
@ -139,6 +139,12 @@ module Gitlab
|
|||
end
|
||||
end
|
||||
|
||||
throttle_or_track(rack_attack, 'throttle_authenticated_git_lfs', Gitlab::Throttle.throttle_authenticated_git_lfs_options) do |req|
|
||||
if req.throttle_authenticated_git_lfs?
|
||||
req.throttled_user_id([:api])
|
||||
end
|
||||
end
|
||||
|
||||
rack_attack.safelist('throttle_bypass_header') do |req|
|
||||
Gitlab::Throttle.bypass_header.present? &&
|
||||
req.get_header(Gitlab::Throttle.bypass_header) == '1'
|
||||
|
|
|
@ -73,6 +73,7 @@ module Gitlab
|
|||
|
||||
def throttle_authenticated_web?
|
||||
web_request? &&
|
||||
!throttle_authenticated_git_lfs? &&
|
||||
Gitlab::Throttle.settings.throttle_authenticated_web_enabled
|
||||
end
|
||||
|
||||
|
@ -109,6 +110,11 @@ module Gitlab
|
|||
Gitlab::Throttle.settings.throttle_authenticated_packages_api_enabled
|
||||
end
|
||||
|
||||
def throttle_authenticated_git_lfs?
|
||||
git_lfs_path? &&
|
||||
Gitlab::Throttle.settings.throttle_authenticated_git_lfs_enabled
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def authenticated_user_id(request_formats)
|
||||
|
@ -130,6 +136,10 @@ module Gitlab
|
|||
def packages_api_path?
|
||||
path =~ ::Gitlab::Regex::Packages::API_PATH_REGEX
|
||||
end
|
||||
|
||||
def git_lfs_path?
|
||||
path =~ Gitlab::PathRegex.repository_git_lfs_route_regex
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -63,6 +63,13 @@ module Gitlab
|
|||
{ limit: limit_proc, period: period_proc }
|
||||
end
|
||||
|
||||
def self.throttle_authenticated_git_lfs_options
|
||||
limit_proc = proc { |req| settings.throttle_authenticated_git_lfs_requests_per_period }
|
||||
period_proc = proc { |req| settings.throttle_authenticated_git_lfs_period_in_seconds.seconds }
|
||||
|
||||
{ limit: limit_proc, period: period_proc }
|
||||
end
|
||||
|
||||
def self.rate_limiting_response_text
|
||||
(settings.rate_limiting_response_text.presence || DEFAULT_RATE_LIMITING_RESPONSE_TEXT) + "\n"
|
||||
end
|
||||
|
|
|
@ -4769,6 +4769,12 @@ msgstr ""
|
|||
msgid "Authenticated API requests"
|
||||
msgstr ""
|
||||
|
||||
msgid "Authenticated Git LFS rate limit period in seconds"
|
||||
msgstr ""
|
||||
|
||||
msgid "Authenticated Git LFS request rate limit"
|
||||
msgstr ""
|
||||
|
||||
msgid "Authenticated web rate limit period in seconds"
|
||||
msgstr ""
|
||||
|
||||
|
@ -8506,6 +8512,9 @@ msgstr ""
|
|||
msgid "Configure settings for Advanced Search with Elasticsearch."
|
||||
msgstr ""
|
||||
|
||||
msgid "Configure specific limits for Git LFS requests that supersede the general user and IP rate limits."
|
||||
msgstr ""
|
||||
|
||||
msgid "Configure specific limits for Packages API requests that supersede the general user and IP rate limits."
|
||||
msgstr ""
|
||||
|
||||
|
@ -12413,6 +12422,9 @@ msgstr ""
|
|||
msgid "Enable authenticated API request rate limit"
|
||||
msgstr ""
|
||||
|
||||
msgid "Enable authenticated Git LFS request rate limit"
|
||||
msgstr ""
|
||||
|
||||
msgid "Enable authentication"
|
||||
msgstr ""
|
||||
|
||||
|
@ -15203,6 +15215,9 @@ msgstr ""
|
|||
msgid "Git GC period"
|
||||
msgstr ""
|
||||
|
||||
msgid "Git LFS Rate Limits"
|
||||
msgstr ""
|
||||
|
||||
msgid "Git LFS is not enabled on this GitLab server, contact your admin."
|
||||
msgstr ""
|
||||
|
||||
|
@ -16526,6 +16541,9 @@ msgstr ""
|
|||
msgid "Helps reduce request volume (e.g. from crawlers or abusive bots)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Helps reduce request volume (for example, from crawlers or abusive bots)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Helps reduce request volume for protected paths"
|
||||
msgstr ""
|
||||
|
||||
|
@ -20604,6 +20622,9 @@ msgstr ""
|
|||
msgid "Max authenticated API requests per period per user"
|
||||
msgstr ""
|
||||
|
||||
msgid "Max authenticated Git LFS requests per period per user"
|
||||
msgstr ""
|
||||
|
||||
msgid "Max authenticated web requests per period per user"
|
||||
msgstr ""
|
||||
|
||||
|
|
55
rubocop/cop/migration/versioned_migration_class.rb
Normal file
55
rubocop/cop/migration/versioned_migration_class.rb
Normal file
|
@ -0,0 +1,55 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../../migration_helpers'
|
||||
|
||||
module RuboCop
|
||||
module Cop
|
||||
module Migration
|
||||
class VersionedMigrationClass < RuboCop::Cop::Cop
|
||||
include MigrationHelpers
|
||||
|
||||
ENFORCED_SINCE = 2021_09_02_00_00_00
|
||||
|
||||
MSG_INHERIT = 'Don\'t inherit from ActiveRecord::Migration but use Gitlab::Database::Migration[1.0] instead. See https://docs.gitlab.com/ee/development/migration_style_guide.html#migration-helpers-and-versioning.'
|
||||
MSG_INCLUDE = 'Don\'t include migration helper modules directly. Inherit from Gitlab::Database::Migration[1.0] instead. See https://docs.gitlab.com/ee/development/migration_style_guide.html#migration-helpers-and-versioning.'
|
||||
|
||||
MIGRATION_CLASS = 'Gitlab::Database::Migration'
|
||||
|
||||
def_node_search :includes_helpers?, <<~PATTERN
|
||||
(send nil? :include
|
||||
(const
|
||||
(const
|
||||
(const nil? :Gitlab) :Database) :MigrationHelpers))
|
||||
PATTERN
|
||||
|
||||
def on_class(node)
|
||||
return unless relevant_migration?(node)
|
||||
|
||||
add_offense(node, location: :expression, message: MSG_INHERIT) unless gitlab_migration_class?(node)
|
||||
end
|
||||
|
||||
def on_send(node)
|
||||
return unless relevant_migration?(node)
|
||||
|
||||
add_offense(node, location: :expression, message: MSG_INCLUDE) if includes_helpers?(node)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def relevant_migration?(node)
|
||||
in_migration?(node) && version(node) >= ENFORCED_SINCE
|
||||
end
|
||||
|
||||
def gitlab_migration_class?(node)
|
||||
superclass(node) == MIGRATION_CLASS
|
||||
end
|
||||
|
||||
def superclass(class_node)
|
||||
_, *others = class_node.descendants
|
||||
|
||||
others.find { |node| node.const_type? && node&.const_name != 'Types' }&.const_name
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -3,6 +3,8 @@ import Bold from '~/content_editor/extensions/bold';
|
|||
import BulletList from '~/content_editor/extensions/bullet_list';
|
||||
import Code from '~/content_editor/extensions/code';
|
||||
import CodeBlockHighlight from '~/content_editor/extensions/code_block_highlight';
|
||||
import DescriptionItem from '~/content_editor/extensions/description_item';
|
||||
import DescriptionList from '~/content_editor/extensions/description_list';
|
||||
import Division from '~/content_editor/extensions/division';
|
||||
import Emoji from '~/content_editor/extensions/emoji';
|
||||
import Figure from '~/content_editor/extensions/figure';
|
||||
|
@ -41,6 +43,8 @@ const tiptapEditor = createTestEditor({
|
|||
BulletList,
|
||||
Code,
|
||||
CodeBlockHighlight,
|
||||
DescriptionItem,
|
||||
DescriptionList,
|
||||
Division,
|
||||
Emoji,
|
||||
Figure,
|
||||
|
@ -75,6 +79,8 @@ const {
|
|||
code,
|
||||
codeBlock,
|
||||
division,
|
||||
descriptionItem,
|
||||
descriptionList,
|
||||
emoji,
|
||||
figure,
|
||||
figureCaption,
|
||||
|
@ -105,6 +111,8 @@ const {
|
|||
code: { markType: Code.name },
|
||||
codeBlock: { nodeType: CodeBlockHighlight.name },
|
||||
division: { nodeType: Division.name },
|
||||
descriptionItem: { nodeType: DescriptionItem.name },
|
||||
descriptionList: { nodeType: DescriptionList.name },
|
||||
emoji: { markType: Emoji.name },
|
||||
figure: { nodeType: Figure.name },
|
||||
figureCaption: { nodeType: FigureCaption.name },
|
||||
|
@ -545,6 +553,41 @@ this is not really json but just trying out whether this case works or not
|
|||
);
|
||||
});
|
||||
|
||||
it('correctly renders a description list', () => {
|
||||
expect(
|
||||
serialize(
|
||||
descriptionList(
|
||||
descriptionItem(paragraph('Beast of Bodmin')),
|
||||
descriptionItem({ isTerm: false }, paragraph('A large feline inhabiting Bodmin Moor.')),
|
||||
|
||||
descriptionItem(paragraph('Morgawr')),
|
||||
descriptionItem({ isTerm: false }, paragraph('A sea serpent.')),
|
||||
|
||||
descriptionItem(paragraph('Owlman')),
|
||||
descriptionItem(
|
||||
{ isTerm: false },
|
||||
paragraph('A giant ', italic('owl-like'), ' creature.'),
|
||||
),
|
||||
),
|
||||
),
|
||||
).toBe(
|
||||
`
|
||||
<dl>
|
||||
<dt>Beast of Bodmin</dt>
|
||||
<dd>A large feline inhabiting Bodmin Moor.</dd>
|
||||
<dt>Morgawr</dt>
|
||||
<dd>A sea serpent.</dd>
|
||||
<dt>Owlman</dt>
|
||||
<dd>
|
||||
|
||||
A giant _owl-like_ creature.
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
`.trim(),
|
||||
);
|
||||
});
|
||||
|
||||
it('correctly renders div', () => {
|
||||
expect(
|
||||
serialize(
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { secondsToHours } from '~/lib/utils/datetime_utility';
|
||||
|
||||
export const freezePeriodsFixture = getJSONFixture('/api/freeze-periods/freeze_periods.json');
|
||||
export const timezoneDataFixture = getJSONFixture('/api/freeze-periods/timezone_data.json');
|
||||
export const timezoneDataFixture = getJSONFixture('/timezones/short.json');
|
||||
|
||||
export const findTzByName = (identifier = '') =>
|
||||
timezoneDataFixture.find(({ name }) => name.toLowerCase() === identifier.toLowerCase());
|
||||
|
|
|
@ -9,6 +9,12 @@ Vue.use(Vuex);
|
|||
export default function createDiffsStore() {
|
||||
return new Vuex.Store({
|
||||
modules: {
|
||||
page: {
|
||||
namespaced: true,
|
||||
state: {
|
||||
activeTab: 'notes',
|
||||
},
|
||||
},
|
||||
diffs: diffsModule(),
|
||||
notes: notesModule(),
|
||||
batchComments: batchCommentsModule(),
|
||||
|
|
|
@ -59,6 +59,24 @@
|
|||
|
||||
</figcaption>
|
||||
</figure>
|
||||
- name: description_list
|
||||
markdown: |-
|
||||
<dl>
|
||||
<dt>Frog</dt>
|
||||
<dd>Wet green thing</dd>
|
||||
<dt>Rabbit</dt>
|
||||
<dd>Warm fluffy thing</dd>
|
||||
<dt>Punt</dt>
|
||||
<dd>Kick a ball</dd>
|
||||
<dd>Take a bet</dd>
|
||||
<dt>Color</dt>
|
||||
<dt>Colour</dt>
|
||||
<dd>
|
||||
|
||||
Any hue except _white_ or **black**
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
- name: link
|
||||
markdown: '[GitLab](https://gitlab.com)'
|
||||
- name: attachment_link
|
||||
|
|
|
@ -39,13 +39,4 @@ RSpec.describe 'Freeze Periods (JavaScript fixtures)' do
|
|||
expect(response).to be_successful
|
||||
end
|
||||
end
|
||||
|
||||
describe TimeZoneHelper, '(JavaScript fixtures)' do
|
||||
let(:response) { timezone_data.to_json }
|
||||
|
||||
it 'api/freeze-periods/timezone_data.json' do
|
||||
# Looks empty but does things
|
||||
# More info: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38525/diffs#note_391048415
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
22
spec/frontend/fixtures/timezones.rb
Normal file
22
spec/frontend/fixtures/timezones.rb
Normal file
|
@ -0,0 +1,22 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe TimeZoneHelper, '(JavaScript fixtures)' do
|
||||
include JavaScriptFixturesHelpers
|
||||
include TimeZoneHelper
|
||||
|
||||
let(:response) { @timezones.sort_by! { |tz| tz[:name] }.to_json }
|
||||
|
||||
before(:all) do
|
||||
clean_frontend_fixtures('timezones/')
|
||||
end
|
||||
|
||||
it 'timezones/short.json' do
|
||||
@timezones = timezone_data(format: :short)
|
||||
end
|
||||
|
||||
it 'timezones/full.json' do
|
||||
@timezones = timezone_data(format: :full)
|
||||
end
|
||||
end
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
exports[`Code Block with default props renders correctly 1`] = `
|
||||
<pre
|
||||
class="code-block rounded"
|
||||
class="code-block rounded code"
|
||||
>
|
||||
<code
|
||||
class="d-block"
|
||||
|
@ -14,7 +14,7 @@ exports[`Code Block with default props renders correctly 1`] = `
|
|||
|
||||
exports[`Code Block with maxHeight set to "200px" renders correctly 1`] = `
|
||||
<pre
|
||||
class="code-block rounded"
|
||||
class="code-block rounded code"
|
||||
style="max-height: 200px; overflow-y: auto;"
|
||||
>
|
||||
<code
|
||||
|
|
34
spec/lib/gitlab/database/migration_spec.rb
Normal file
34
spec/lib/gitlab/database/migration_spec.rb
Normal file
|
@ -0,0 +1,34 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::Database::Migration do
|
||||
describe '.[]' do
|
||||
context 'version: 1.0' do
|
||||
subject { described_class[1.0] }
|
||||
|
||||
it 'inherits from ActiveRecord::Migration[6.1]' do
|
||||
expect(subject.superclass).to eq(ActiveRecord::Migration[6.1])
|
||||
end
|
||||
|
||||
it 'includes migration helpers version 2' do
|
||||
expect(subject.included_modules).to include(Gitlab::Database::MigrationHelpers::V2)
|
||||
end
|
||||
end
|
||||
|
||||
context 'unknown version' do
|
||||
it 'raises an error' do
|
||||
expect { described_class[0] }.to raise_error(ArgumentError, /Unknown migration version/)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '.current_version' do
|
||||
it 'includes current ActiveRecord migration class' do
|
||||
# This breaks upon Rails upgrade. In that case, we'll add a new version in Gitlab::Database::Migration::MIGRATION_CLASSES,
|
||||
# bump .current_version and leave existing migrations and already defined versions of Gitlab::Database::Migration
|
||||
# untouched.
|
||||
expect(described_class[described_class.current_version].superclass).to eq(ActiveRecord::Migration::Current)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -468,6 +468,7 @@ RSpec.describe Gitlab::PathRegex do
|
|||
end
|
||||
|
||||
let_it_be(:git_paths) { container_paths.map { |path| path + '.git' } }
|
||||
let_it_be(:git_lfs_paths) { git_paths.flat_map { |path| [path + '/info/lfs/', path + '/gitlab-lfs/'] } }
|
||||
let_it_be(:snippet_paths) { container_paths.grep(%r{snippets/\d}) }
|
||||
let_it_be(:wiki_git_paths) { (container_paths - snippet_paths).map { |path| path + '.wiki.git' } }
|
||||
let_it_be(:invalid_git_paths) { invalid_paths.map { |path| path + '.git' } }
|
||||
|
@ -498,6 +499,15 @@ RSpec.describe Gitlab::PathRegex do
|
|||
end
|
||||
end
|
||||
|
||||
describe '.repository_git_lfs_route_regex' do
|
||||
subject { %r{\A#{described_class.repository_git_lfs_route_regex}\z} }
|
||||
|
||||
it 'matches the expected paths' do
|
||||
expect_route_match(git_lfs_paths)
|
||||
expect_no_route_match(container_paths + invalid_paths + git_paths + invalid_git_paths)
|
||||
end
|
||||
end
|
||||
|
||||
describe '.repository_wiki_git_route_regex' do
|
||||
subject { %r{\A#{described_class.repository_wiki_git_route_regex}\z} }
|
||||
|
||||
|
|
|
@ -939,6 +939,8 @@ RSpec.describe ApplicationSetting do
|
|||
throttle_unauthenticated_files_api_period_in_seconds
|
||||
throttle_authenticated_files_api_requests_per_period
|
||||
throttle_authenticated_files_api_period_in_seconds
|
||||
throttle_authenticated_git_lfs_requests_per_period
|
||||
throttle_authenticated_git_lfs_period_in_seconds
|
||||
]
|
||||
end
|
||||
|
||||
|
|
|
@ -22,7 +22,9 @@ RSpec.describe 'Rack Attack global throttles', :use_clean_rails_memory_store_cac
|
|||
throttle_unauthenticated_packages_api_requests_per_period: 100,
|
||||
throttle_unauthenticated_packages_api_period_in_seconds: 1,
|
||||
throttle_authenticated_packages_api_requests_per_period: 100,
|
||||
throttle_authenticated_packages_api_period_in_seconds: 1
|
||||
throttle_authenticated_packages_api_period_in_seconds: 1,
|
||||
throttle_authenticated_git_lfs_requests_per_period: 100,
|
||||
throttle_authenticated_git_lfs_period_in_seconds: 1
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -620,6 +622,95 @@ RSpec.describe 'Rack Attack global throttles', :use_clean_rails_memory_store_cac
|
|||
end
|
||||
end
|
||||
|
||||
describe 'authenticated git lfs requests', :api do
|
||||
let_it_be(:project) { create(:project, :internal) }
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:token) { create(:personal_access_token, user: user) }
|
||||
let_it_be(:other_user) { create(:user) }
|
||||
let_it_be(:other_user_token) { create(:personal_access_token, user: other_user) }
|
||||
|
||||
let(:request_method) { 'GET' }
|
||||
let(:throttle_setting_prefix) { 'throttle_authenticated_git_lfs' }
|
||||
let(:git_lfs_url) { "/#{project.full_path}.git/info/lfs/locks" }
|
||||
|
||||
before do
|
||||
allow(Gitlab.config.lfs).to receive(:enabled).and_return(true)
|
||||
stub_application_setting(settings_to_set)
|
||||
end
|
||||
|
||||
context 'with regular login' do
|
||||
let(:url_that_requires_authentication) { git_lfs_url }
|
||||
|
||||
it_behaves_like 'rate-limited web authenticated requests'
|
||||
end
|
||||
|
||||
context 'with the token in the headers' do
|
||||
let(:request_args) { [git_lfs_url, { headers: basic_auth_headers(user, token) }] }
|
||||
let(:other_user_request_args) { [git_lfs_url, { headers: basic_auth_headers(other_user, other_user_token) }] }
|
||||
|
||||
it_behaves_like 'rate-limited token-authenticated requests'
|
||||
end
|
||||
|
||||
context 'precedence over authenticated web throttle' do
|
||||
before do
|
||||
settings_to_set[:throttle_authenticated_git_lfs_requests_per_period] = requests_per_period
|
||||
settings_to_set[:throttle_authenticated_git_lfs_period_in_seconds] = period_in_seconds
|
||||
end
|
||||
|
||||
def do_request
|
||||
get git_lfs_url, headers: basic_auth_headers(user, token)
|
||||
end
|
||||
|
||||
context 'when authenticated git lfs throttle is enabled' do
|
||||
before do
|
||||
settings_to_set[:throttle_authenticated_git_lfs_enabled] = true
|
||||
end
|
||||
|
||||
context 'when authenticated web throttle is lower' do
|
||||
before do
|
||||
settings_to_set[:throttle_authenticated_web_requests_per_period] = 0
|
||||
settings_to_set[:throttle_authenticated_web_period_in_seconds] = period_in_seconds
|
||||
settings_to_set[:throttle_authenticated_web_enabled] = true
|
||||
stub_application_setting(settings_to_set)
|
||||
end
|
||||
|
||||
it 'ignores authenticated web throttle' do
|
||||
requests_per_period.times do
|
||||
do_request
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
end
|
||||
|
||||
expect_rejection { do_request }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when authenticated git lfs throttle is disabled' do
|
||||
before do
|
||||
settings_to_set[:throttle_authenticated_git_lfs_enabled] = false
|
||||
end
|
||||
|
||||
context 'when authenticated web throttle is enabled' do
|
||||
before do
|
||||
settings_to_set[:throttle_authenticated_web_requests_per_period] = requests_per_period
|
||||
settings_to_set[:throttle_authenticated_web_period_in_seconds] = period_in_seconds
|
||||
settings_to_set[:throttle_authenticated_web_enabled] = true
|
||||
stub_application_setting(settings_to_set)
|
||||
end
|
||||
|
||||
it 'rejects requests over the authenticated web rate limit' do
|
||||
requests_per_period.times do
|
||||
do_request
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
end
|
||||
|
||||
expect_rejection { do_request }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'throttle bypass header' do
|
||||
let(:headers) { {} }
|
||||
let(:bypass_header) { 'gitlab-bypass-rate-limiting' }
|
||||
|
|
69
spec/rubocop/cop/migration/versioned_migration_class_spec.rb
Normal file
69
spec/rubocop/cop/migration/versioned_migration_class_spec.rb
Normal file
|
@ -0,0 +1,69 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'fast_spec_helper'
|
||||
require_relative '../../../../rubocop/cop/migration/versioned_migration_class'
|
||||
|
||||
RSpec.describe RuboCop::Cop::Migration::VersionedMigrationClass do
|
||||
subject(:cop) { described_class.new }
|
||||
|
||||
let(:migration) do
|
||||
<<~SOURCE
|
||||
class TestMigration < Gitlab::Database::Migration[1.0]
|
||||
def up
|
||||
execute 'select 1'
|
||||
end
|
||||
|
||||
def down
|
||||
execute 'select 1'
|
||||
end
|
||||
end
|
||||
SOURCE
|
||||
end
|
||||
|
||||
shared_examples 'a disabled cop' do
|
||||
it 'does not register any offenses' do
|
||||
expect_no_offenses(migration)
|
||||
end
|
||||
end
|
||||
|
||||
context 'outside of a migration' do
|
||||
it_behaves_like 'a disabled cop'
|
||||
end
|
||||
|
||||
context 'in migration' do
|
||||
before do
|
||||
allow(cop).to receive(:in_migration?).and_return(true)
|
||||
end
|
||||
|
||||
context 'in an old migration' do
|
||||
before do
|
||||
allow(cop).to receive(:version).and_return(described_class::ENFORCED_SINCE - 5)
|
||||
end
|
||||
|
||||
it_behaves_like 'a disabled cop'
|
||||
end
|
||||
|
||||
context 'that is recent' do
|
||||
before do
|
||||
allow(cop).to receive(:version).and_return(described_class::ENFORCED_SINCE + 5)
|
||||
end
|
||||
|
||||
it 'adds an offence if inheriting from ActiveRecord::Migration' do
|
||||
expect_offense(<<~RUBY)
|
||||
class MyMigration < ActiveRecord::Migration[6.1]
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Don't inherit from ActiveRecord::Migration but use Gitlab::Database::Migration[1.0] instead. See https://docs.gitlab.com/ee/development/migration_style_guide.html#migration-helpers-and-versioning.
|
||||
end
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'adds an offence if including Gitlab::Database::MigrationHelpers directly' do
|
||||
expect_offense(<<~RUBY)
|
||||
class MyMigration < Gitlab::Database::Migration[1.0]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Don't include migration helper modules directly. Inherit from Gitlab::Database::Migration[1.0] instead. See https://docs.gitlab.com/ee/development/migration_style_guide.html#migration-helpers-and-versioning.
|
||||
end
|
||||
RUBY
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -388,6 +388,26 @@ RSpec.describe ApplicationSettings::UpdateService do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when git lfs rate limits are passed' do
|
||||
let(:params) do
|
||||
{
|
||||
throttle_authenticated_git_lfs_enabled: 1,
|
||||
throttle_authenticated_git_lfs_period_in_seconds: 600,
|
||||
throttle_authenticated_git_lfs_requests_per_period: 10
|
||||
}
|
||||
end
|
||||
|
||||
it 'updates git lfs throttle settings' do
|
||||
subject.execute
|
||||
|
||||
application_settings.reload
|
||||
|
||||
expect(application_settings.throttle_authenticated_git_lfs_enabled).to be_truthy
|
||||
expect(application_settings.throttle_authenticated_git_lfs_period_in_seconds).to eq(600)
|
||||
expect(application_settings.throttle_authenticated_git_lfs_requests_per_period).to eq(10)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when issues_create_limit is passed' do
|
||||
let(:params) do
|
||||
{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
#
|
||||
# Requires let variables:
|
||||
# * throttle_setting_prefix: "throttle_authenticated_api", "throttle_authenticated_web", "throttle_protected_paths", "throttle_authenticated_packages_api"
|
||||
# * throttle_setting_prefix: "throttle_authenticated_api", "throttle_authenticated_web", "throttle_protected_paths", "throttle_authenticated_packages_api", "throttle_authenticated_git_lfs"
|
||||
# * request_method
|
||||
# * request_args
|
||||
# * other_user_request_args
|
||||
|
@ -14,7 +14,8 @@ RSpec.shared_examples 'rate-limited token-authenticated requests' do
|
|||
"throttle_protected_paths" => "throttle_authenticated_protected_paths_api",
|
||||
"throttle_authenticated_api" => "throttle_authenticated_api",
|
||||
"throttle_authenticated_web" => "throttle_authenticated_web",
|
||||
"throttle_authenticated_packages_api" => "throttle_authenticated_packages_api"
|
||||
"throttle_authenticated_packages_api" => "throttle_authenticated_packages_api",
|
||||
"throttle_authenticated_git_lfs" => "throttle_authenticated_git_lfs"
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -165,7 +166,7 @@ RSpec.shared_examples 'rate-limited token-authenticated requests' do
|
|||
end
|
||||
|
||||
# Requires let variables:
|
||||
# * throttle_setting_prefix: "throttle_authenticated_web" or "throttle_protected_paths"
|
||||
# * throttle_setting_prefix: "throttle_authenticated_web", "throttle_protected_paths", "throttle_authenticated_git_lfs"
|
||||
# * user
|
||||
# * url_that_requires_authentication
|
||||
# * request_method
|
||||
|
@ -176,7 +177,8 @@ RSpec.shared_examples 'rate-limited web authenticated requests' do
|
|||
let(:throttle_types) do
|
||||
{
|
||||
"throttle_protected_paths" => "throttle_authenticated_protected_paths_web",
|
||||
"throttle_authenticated_web" => "throttle_authenticated_web"
|
||||
"throttle_authenticated_web" => "throttle_authenticated_web",
|
||||
"throttle_authenticated_git_lfs" => "throttle_authenticated_git_lfs"
|
||||
}
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in a new issue