Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
5248069bd6
commit
96855c4214
|
@ -0,0 +1,32 @@
|
||||||
|
<script>
|
||||||
|
import { NodeViewWrapper, NodeViewContent } from '@tiptap/vue-2';
|
||||||
|
import { __ } from '~/locale';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'FrontMatter',
|
||||||
|
components: {
|
||||||
|
NodeViewWrapper,
|
||||||
|
NodeViewContent,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
node: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
i18n: {
|
||||||
|
frontmatter: __('frontmatter'),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<node-view-wrapper class="gl-relative code highlight" as="pre">
|
||||||
|
<span
|
||||||
|
data-testid="frontmatter-label"
|
||||||
|
class="gl-absolute gl-top-0 gl-right-3"
|
||||||
|
contenteditable="false"
|
||||||
|
>{{ $options.i18n.frontmatter }}:{{ node.attrs.language }}</span
|
||||||
|
>
|
||||||
|
<node-view-content as="code" />
|
||||||
|
</node-view-wrapper>
|
||||||
|
</template>
|
|
@ -11,7 +11,8 @@ export default CodeBlockLowlight.extend({
|
||||||
parseHTML: (element) => extractLanguage(element),
|
parseHTML: (element) => extractLanguage(element),
|
||||||
},
|
},
|
||||||
class: {
|
class: {
|
||||||
default: 'code highlight js-syntax-highlight',
|
// eslint-disable-next-line @gitlab/require-i18n-strings
|
||||||
|
default: 'code highlight',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
import { VueNodeViewRenderer } from '@tiptap/vue-2';
|
||||||
|
import { PARSE_HTML_PRIORITY_HIGHEST } from '../constants';
|
||||||
|
import FrontmatterWrapper from '../components/wrappers/frontmatter.vue';
|
||||||
|
import CodeBlockHighlight from './code_block_highlight';
|
||||||
|
|
||||||
|
export default CodeBlockHighlight.extend({
|
||||||
|
name: 'frontmatter',
|
||||||
|
parseHTML() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
tag: 'pre[data-lang-params="frontmatter"]',
|
||||||
|
preserveWhitespace: 'full',
|
||||||
|
priority: PARSE_HTML_PRIORITY_HIGHEST,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
},
|
||||||
|
addNodeView() {
|
||||||
|
return new VueNodeViewRenderer(FrontmatterWrapper);
|
||||||
|
},
|
||||||
|
});
|
|
@ -0,0 +1,29 @@
|
||||||
|
import { Node, mergeAttributes, nodeInputRule } from '@tiptap/core';
|
||||||
|
|
||||||
|
export const inputRegex = /^<wbr>$/;
|
||||||
|
|
||||||
|
export default Node.create({
|
||||||
|
name: 'wordBreak',
|
||||||
|
inline: true,
|
||||||
|
group: 'inline',
|
||||||
|
selectable: false,
|
||||||
|
atom: true,
|
||||||
|
|
||||||
|
defaultOptions: {
|
||||||
|
HTMLAttributes: {
|
||||||
|
class: 'gl-display-inline-flex gl-px-1 gl-bg-blue-100 gl-rounded-base gl-font-sm',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
parseHTML() {
|
||||||
|
return [{ tag: 'wbr' }];
|
||||||
|
},
|
||||||
|
|
||||||
|
renderHTML({ HTMLAttributes }) {
|
||||||
|
return ['span', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), '-'];
|
||||||
|
},
|
||||||
|
|
||||||
|
addInputRules() {
|
||||||
|
return [nodeInputRule(inputRegex, this.type)];
|
||||||
|
},
|
||||||
|
});
|
|
@ -16,6 +16,7 @@ import Dropcursor from '../extensions/dropcursor';
|
||||||
import Emoji from '../extensions/emoji';
|
import Emoji from '../extensions/emoji';
|
||||||
import Figure from '../extensions/figure';
|
import Figure from '../extensions/figure';
|
||||||
import FigureCaption from '../extensions/figure_caption';
|
import FigureCaption from '../extensions/figure_caption';
|
||||||
|
import Frontmatter from '../extensions/frontmatter';
|
||||||
import Gapcursor from '../extensions/gapcursor';
|
import Gapcursor from '../extensions/gapcursor';
|
||||||
import HardBreak from '../extensions/hard_break';
|
import HardBreak from '../extensions/hard_break';
|
||||||
import Heading from '../extensions/heading';
|
import Heading from '../extensions/heading';
|
||||||
|
@ -43,6 +44,7 @@ import TaskItem from '../extensions/task_item';
|
||||||
import TaskList from '../extensions/task_list';
|
import TaskList from '../extensions/task_list';
|
||||||
import Text from '../extensions/text';
|
import Text from '../extensions/text';
|
||||||
import Video from '../extensions/video';
|
import Video from '../extensions/video';
|
||||||
|
import WordBreak from '../extensions/word_break';
|
||||||
import { ContentEditor } from './content_editor';
|
import { ContentEditor } from './content_editor';
|
||||||
import createMarkdownSerializer from './markdown_serializer';
|
import createMarkdownSerializer from './markdown_serializer';
|
||||||
import trackInputRulesAndShortcuts from './track_input_rules_and_shortcuts';
|
import trackInputRulesAndShortcuts from './track_input_rules_and_shortcuts';
|
||||||
|
@ -85,6 +87,7 @@ export const createContentEditor = ({
|
||||||
Emoji,
|
Emoji,
|
||||||
Figure,
|
Figure,
|
||||||
FigureCaption,
|
FigureCaption,
|
||||||
|
Frontmatter,
|
||||||
Gapcursor,
|
Gapcursor,
|
||||||
HardBreak,
|
HardBreak,
|
||||||
Heading,
|
Heading,
|
||||||
|
@ -112,6 +115,7 @@ export const createContentEditor = ({
|
||||||
TaskList,
|
TaskList,
|
||||||
Text,
|
Text,
|
||||||
Video,
|
Video,
|
||||||
|
WordBreak,
|
||||||
];
|
];
|
||||||
|
|
||||||
const allExtensions = [...builtInContentEditorExtensions, ...extensions];
|
const allExtensions = [...builtInContentEditorExtensions, ...extensions];
|
||||||
|
|
|
@ -15,6 +15,7 @@ import Division from '../extensions/division';
|
||||||
import Emoji from '../extensions/emoji';
|
import Emoji from '../extensions/emoji';
|
||||||
import Figure from '../extensions/figure';
|
import Figure from '../extensions/figure';
|
||||||
import FigureCaption from '../extensions/figure_caption';
|
import FigureCaption from '../extensions/figure_caption';
|
||||||
|
import Frontmatter from '../extensions/frontmatter';
|
||||||
import HardBreak from '../extensions/hard_break';
|
import HardBreak from '../extensions/hard_break';
|
||||||
import Heading from '../extensions/heading';
|
import Heading from '../extensions/heading';
|
||||||
import HorizontalRule from '../extensions/horizontal_rule';
|
import HorizontalRule from '../extensions/horizontal_rule';
|
||||||
|
@ -39,6 +40,7 @@ import TaskItem from '../extensions/task_item';
|
||||||
import TaskList from '../extensions/task_list';
|
import TaskList from '../extensions/task_list';
|
||||||
import Text from '../extensions/text';
|
import Text from '../extensions/text';
|
||||||
import Video from '../extensions/video';
|
import Video from '../extensions/video';
|
||||||
|
import WordBreak from '../extensions/word_break';
|
||||||
import {
|
import {
|
||||||
isPlainURL,
|
isPlainURL,
|
||||||
renderHardBreak,
|
renderHardBreak,
|
||||||
|
@ -136,6 +138,20 @@ const defaultSerializerConfig = {
|
||||||
|
|
||||||
state.write(`:${name}:`);
|
state.write(`:${name}:`);
|
||||||
},
|
},
|
||||||
|
[Frontmatter.name]: (state, node) => {
|
||||||
|
const { language } = node.attrs;
|
||||||
|
const syntax = {
|
||||||
|
toml: '+++',
|
||||||
|
json: ';;;',
|
||||||
|
yaml: '---',
|
||||||
|
}[language];
|
||||||
|
|
||||||
|
state.write(`${syntax}\n`);
|
||||||
|
state.text(node.textContent, false);
|
||||||
|
state.ensureNewLine();
|
||||||
|
state.write(syntax);
|
||||||
|
state.closeBlock(node);
|
||||||
|
},
|
||||||
[Figure.name]: renderHTMLNode('figure'),
|
[Figure.name]: renderHTMLNode('figure'),
|
||||||
[FigureCaption.name]: renderHTMLNode('figcaption'),
|
[FigureCaption.name]: renderHTMLNode('figcaption'),
|
||||||
[HardBreak.name]: renderHardBreak,
|
[HardBreak.name]: renderHardBreak,
|
||||||
|
@ -166,6 +182,7 @@ const defaultSerializerConfig = {
|
||||||
},
|
},
|
||||||
[Text.name]: defaultMarkdownSerializer.nodes.text,
|
[Text.name]: defaultMarkdownSerializer.nodes.text,
|
||||||
[Video.name]: renderPlayable,
|
[Video.name]: renderPlayable,
|
||||||
|
[WordBreak.name]: (state) => state.write('<wbr>'),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,14 @@
|
||||||
<script>
|
<script>
|
||||||
import { GlButton, GlFormGroup, GlFormCheckbox, GlFormRadioGroup, GlFormRadio } from '@gitlab/ui';
|
import {
|
||||||
|
GlButton,
|
||||||
|
GlFormGroup,
|
||||||
|
GlFormCheckbox,
|
||||||
|
GlFormRadioGroup,
|
||||||
|
GlFormRadio,
|
||||||
|
GlFormInputGroup,
|
||||||
|
} from '@gitlab/ui';
|
||||||
import { mapActions, mapGetters, mapState } from 'vuex';
|
import { mapActions, mapGetters, mapState } from 'vuex';
|
||||||
|
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
|
||||||
import ErrorTrackingForm from './error_tracking_form.vue';
|
import ErrorTrackingForm from './error_tracking_form.vue';
|
||||||
import ProjectDropdown from './project_dropdown.vue';
|
import ProjectDropdown from './project_dropdown.vue';
|
||||||
|
|
||||||
|
@ -12,7 +20,9 @@ export default {
|
||||||
GlFormGroup,
|
GlFormGroup,
|
||||||
GlFormRadioGroup,
|
GlFormRadioGroup,
|
||||||
GlFormRadio,
|
GlFormRadio,
|
||||||
|
GlFormInputGroup,
|
||||||
ProjectDropdown,
|
ProjectDropdown,
|
||||||
|
ClipboardButton,
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
initialApiHost: {
|
initialApiHost: {
|
||||||
|
@ -46,6 +56,11 @@ export default {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
|
gitlabDsn: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters([
|
...mapGetters([
|
||||||
|
@ -63,6 +78,9 @@ export default {
|
||||||
'settingsLoading',
|
'settingsLoading',
|
||||||
'token',
|
'token',
|
||||||
]),
|
]),
|
||||||
|
showGitlabDsnSetting() {
|
||||||
|
return this.integrated && this.enabled && this.gitlabDsn;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.setInitialState({
|
this.setInitialState({
|
||||||
|
@ -119,6 +137,17 @@ export default {
|
||||||
</gl-form-radio>
|
</gl-form-radio>
|
||||||
</gl-form-radio-group>
|
</gl-form-radio-group>
|
||||||
</gl-form-group>
|
</gl-form-group>
|
||||||
|
<gl-form-group
|
||||||
|
v-if="showGitlabDsnSetting"
|
||||||
|
:label="__('Paste this DSN into your Sentry SDK')"
|
||||||
|
data-testid="gitlab-dsn-setting-form"
|
||||||
|
>
|
||||||
|
<gl-form-input-group readonly :value="gitlabDsn">
|
||||||
|
<template #append>
|
||||||
|
<clipboard-button :text="gitlabDsn" :title="__('Copy')" />
|
||||||
|
</template>
|
||||||
|
</gl-form-input-group>
|
||||||
|
</gl-form-group>
|
||||||
<div v-if="!integrated" class="js-sentry-setting-form" data-testid="sentry-setting-form">
|
<div v-if="!integrated" class="js-sentry-setting-form" data-testid="sentry-setting-form">
|
||||||
<error-tracking-form />
|
<error-tracking-form />
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
|
|
@ -13,6 +13,7 @@ export default () => {
|
||||||
token,
|
token,
|
||||||
listProjectsEndpoint,
|
listProjectsEndpoint,
|
||||||
operationsSettingsEndpoint,
|
operationsSettingsEndpoint,
|
||||||
|
gitlabDsn,
|
||||||
},
|
},
|
||||||
} = formContainerEl;
|
} = formContainerEl;
|
||||||
|
|
||||||
|
@ -29,6 +30,7 @@ export default () => {
|
||||||
initialToken: token,
|
initialToken: token,
|
||||||
listProjectsEndpoint,
|
listProjectsEndpoint,
|
||||||
operationsSettingsEndpoint,
|
operationsSettingsEndpoint,
|
||||||
|
gitlabDsn,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
import { sprintf, n__, __ } from '../../../../locale';
|
import { __ } from '../../../../locale';
|
||||||
import { COMMIT_TO_NEW_BRANCH } from './constants';
|
import { COMMIT_TO_NEW_BRANCH } from './constants';
|
||||||
|
|
||||||
const BRANCH_SUFFIX_COUNT = 5;
|
const BRANCH_SUFFIX_COUNT = 5;
|
||||||
const createTranslatedTextForFiles = (files, text) => {
|
const createTranslatedTextForFiles = (files, text) => {
|
||||||
if (!files.length) return null;
|
if (!files.length) return null;
|
||||||
|
|
||||||
return sprintf(n__('%{text} %{files}', '%{text} %{files} files', files.length), {
|
const filesPart = files.reduce((acc, val) => acc.concat(val.path), []).join(', ');
|
||||||
files: files.reduce((acc, val) => acc.concat(val.path), []).join(', '),
|
|
||||||
text,
|
return `${text} ${filesPart}`;
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const discardDraftButtonDisabled = (state) =>
|
export const discardDraftButtonDisabled = (state) =>
|
||||||
|
|
|
@ -136,7 +136,13 @@ export default {
|
||||||
<template>
|
<template>
|
||||||
<gl-button-group>
|
<gl-button-group>
|
||||||
<template v-if="canReadJob">
|
<template v-if="canReadJob">
|
||||||
<gl-button v-if="isActive" icon="cancel" :title="$options.CANCEL" @click="cancelJob()" />
|
<gl-button
|
||||||
|
v-if="isActive"
|
||||||
|
data-testid="cancel-button"
|
||||||
|
icon="cancel"
|
||||||
|
:title="$options.CANCEL"
|
||||||
|
@click="cancelJob()"
|
||||||
|
/>
|
||||||
<template v-else-if="isScheduled">
|
<template v-else-if="isScheduled">
|
||||||
<gl-button icon="planning" disabled data-testid="countdown">
|
<gl-button icon="planning" disabled data-testid="countdown">
|
||||||
<gl-countdown :end-date-string="scheduledAt" />
|
<gl-countdown :end-date-string="scheduledAt" />
|
||||||
|
|
|
@ -4,7 +4,7 @@ class Admin::Serverless::DomainsController < Admin::ApplicationController
|
||||||
before_action :check_feature_flag
|
before_action :check_feature_flag
|
||||||
before_action :domain, only: [:update, :verify, :destroy]
|
before_action :domain, only: [:update, :verify, :destroy]
|
||||||
|
|
||||||
feature_category :serverless
|
feature_category :not_owned
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@domain = PagesDomain.instance_serverless.first_or_initialize
|
@domain = PagesDomain.instance_serverless.first_or_initialize
|
||||||
|
|
|
@ -5,7 +5,7 @@ module Projects
|
||||||
class FunctionsController < Projects::ApplicationController
|
class FunctionsController < Projects::ApplicationController
|
||||||
before_action :authorize_read_cluster!
|
before_action :authorize_read_cluster!
|
||||||
|
|
||||||
feature_category :serverless
|
feature_category :not_owned
|
||||||
|
|
||||||
def index
|
def index
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
|
|
|
@ -46,6 +46,11 @@ module ErrorTracking
|
||||||
|
|
||||||
after_save :clear_reactive_cache!
|
after_save :clear_reactive_cache!
|
||||||
|
|
||||||
|
# When a user enables the integrated error tracking
|
||||||
|
# we want to immediately provide them with a first
|
||||||
|
# working client key so they have a DSN for Sentry SDK.
|
||||||
|
after_save :create_client_key!
|
||||||
|
|
||||||
def sentry_enabled
|
def sentry_enabled
|
||||||
enabled && !integrated_client?
|
enabled && !integrated_client?
|
||||||
end
|
end
|
||||||
|
@ -54,6 +59,12 @@ module ErrorTracking
|
||||||
integrated
|
integrated
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def gitlab_dsn
|
||||||
|
strong_memoize(:gitlab_dsn) do
|
||||||
|
client_key&.sentry_dsn
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def api_url=(value)
|
def api_url=(value)
|
||||||
super
|
super
|
||||||
clear_memoization(:api_url_slugs)
|
clear_memoization(:api_url_slugs)
|
||||||
|
@ -236,5 +247,19 @@ module ErrorTracking
|
||||||
errors.add(:project, 'is a required field')
|
errors.add(:project, 'is a required field')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def client_key
|
||||||
|
# Project can have multiple client keys.
|
||||||
|
# However for UI simplicity we render the first active one for user.
|
||||||
|
# In future we should make it possible to manage client keys from UI.
|
||||||
|
# Issue https://gitlab.com/gitlab-org/gitlab/-/issues/329596
|
||||||
|
project.error_tracking_client_keys.active.first
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_client_key!
|
||||||
|
if enabled? && integrated_client? && !client_key
|
||||||
|
project.error_tracking_client_keys.create!
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,26 +1,9 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class NamespacePolicy < BasePolicy
|
class NamespacePolicy < ::Namespaces::UserNamespacePolicy
|
||||||
rule { anonymous }.prevent_all
|
# NamespacePolicy has been traditionally for user namespaces.
|
||||||
|
# So these policies have been moved into Namespaces::UserNamespacePolicy.
|
||||||
condition(:personal_project, scope: :subject) { @subject.kind == 'user' }
|
# Once the user namespace conversion is complete, we can look at
|
||||||
condition(:can_create_personal_project, scope: :user) { @user.can_create_project? }
|
# either removing this file or locating common namespace policy items
|
||||||
condition(:owner) { @subject.owner == @user }
|
# here.
|
||||||
|
|
||||||
rule { owner | admin }.policy do
|
|
||||||
enable :owner_access
|
|
||||||
enable :create_projects
|
|
||||||
enable :admin_namespace
|
|
||||||
enable :read_namespace
|
|
||||||
enable :read_statistics
|
|
||||||
enable :create_jira_connect_subscription
|
|
||||||
enable :create_package_settings
|
|
||||||
enable :read_package_settings
|
|
||||||
end
|
|
||||||
|
|
||||||
rule { personal_project & ~can_create_personal_project }.prevent :create_projects
|
|
||||||
|
|
||||||
rule { (owner | admin) & can?(:create_projects) }.enable :transfer_projects
|
|
||||||
end
|
end
|
||||||
|
|
||||||
NamespacePolicy.prepend_mod_with('NamespacePolicy')
|
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Namespaces
|
||||||
|
class UserNamespacePolicy < BasePolicy
|
||||||
|
rule { anonymous }.prevent_all
|
||||||
|
|
||||||
|
condition(:personal_project, scope: :subject) { @subject.kind == 'user' }
|
||||||
|
condition(:can_create_personal_project, scope: :user) { @user.can_create_project? }
|
||||||
|
condition(:owner) { @subject.owner == @user }
|
||||||
|
|
||||||
|
rule { owner | admin }.policy do
|
||||||
|
enable :owner_access
|
||||||
|
enable :create_projects
|
||||||
|
enable :admin_namespace
|
||||||
|
enable :read_namespace
|
||||||
|
enable :read_statistics
|
||||||
|
enable :create_jira_connect_subscription
|
||||||
|
enable :create_package_settings
|
||||||
|
enable :read_package_settings
|
||||||
|
end
|
||||||
|
|
||||||
|
rule { personal_project & ~can_create_personal_project }.prevent :create_projects
|
||||||
|
|
||||||
|
rule { (owner | admin) & can?(:create_projects) }.enable :transfer_projects
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Namespaces::UserNamespacePolicy.prepend_mod_with('Namespaces::UserNamespacePolicy')
|
|
@ -17,7 +17,7 @@ module Ci
|
||||||
def execute(build)
|
def execute(build)
|
||||||
build.ensure_scheduling_type!
|
build.ensure_scheduling_type!
|
||||||
|
|
||||||
reprocess!(build).tap do |new_build|
|
clone!(build).tap do |new_build|
|
||||||
check_assignable_runners!(new_build)
|
check_assignable_runners!(new_build)
|
||||||
next if new_build.failed?
|
next if new_build.failed?
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ module Ci
|
||||||
end
|
end
|
||||||
|
|
||||||
# rubocop: disable CodeReuse/ActiveRecord
|
# rubocop: disable CodeReuse/ActiveRecord
|
||||||
def reprocess!(build)
|
def clone!(build)
|
||||||
# Cloning a build requires a strict type check to ensure
|
# Cloning a build requires a strict type check to ensure
|
||||||
# the attributes being used for the clone are taken straight
|
# the attributes being used for the clone are taken straight
|
||||||
# from the model and not overridden by other abstractions.
|
# from the model and not overridden by other abstractions.
|
||||||
|
|
|
@ -9,17 +9,12 @@ module Ci
|
||||||
raise Gitlab::Access::AccessDeniedError
|
raise Gitlab::Access::AccessDeniedError
|
||||||
end
|
end
|
||||||
|
|
||||||
needs = Set.new
|
|
||||||
|
|
||||||
pipeline.ensure_scheduling_type!
|
pipeline.ensure_scheduling_type!
|
||||||
|
|
||||||
builds_relation(pipeline).find_each do |build|
|
builds_relation(pipeline).find_each do |build|
|
||||||
next unless can_be_retried?(build)
|
next unless can_be_retried?(build)
|
||||||
|
|
||||||
Ci::RetryBuildService.new(project, current_user)
|
Ci::RetryBuildService.new(project, current_user).clone!(build)
|
||||||
.reprocess!(build)
|
|
||||||
|
|
||||||
needs += build.needs.map(&:name)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
pipeline.builds.latest.skipped.find_each do |skipped|
|
pipeline.builds.latest.skipped.find_each do |skipped|
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
- if show_feed_buttons
|
- if show_feed_buttons
|
||||||
= render 'shared/issuable/feed_buttons'
|
= render 'shared/issuable/feed_buttons'
|
||||||
|
|
||||||
.js-csv-import-export-buttons{ data: { show_export_button: show_export_button.to_s, show_import_button: show_import_button.to_s, issuable_type: issuable_type, issuable_count: issuables_count_for_state(issuable_type.to_sym, params[:state]), email: notification_email, export_csv_path: export_csv_project_issues_path(@project, request.query_parameters), import_csv_issues_path: import_csv_namespace_project_issues_path, container_class: 'gl-mr-3', can_edit: can_edit.to_s, project_import_jira_path: project_import_jira_path(@project) } }
|
.js-csv-import-export-buttons{ data: { show_export_button: show_export_button.to_s, show_import_button: show_import_button.to_s, issuable_type: issuable_type, issuable_count: issuables_count_for_state(issuable_type.to_sym, params[:state]), email: notification_email, export_csv_path: export_csv_project_issues_path(@project, request.query_parameters), import_csv_issues_path: import_csv_namespace_project_issues_path, container_class: 'gl-mr-3', can_edit: can_edit.to_s, project_import_jira_path: project_import_jira_path(@project), max_attachment_size: number_to_human_size(Gitlab::CurrentSettings.max_attachment_size.megabytes) } }
|
||||||
|
|
||||||
- if @can_bulk_update
|
- if @can_bulk_update
|
||||||
= button_tag _("Edit issues"), class: "gl-button btn btn-default gl-mr-3 js-bulk-update-toggle"
|
= button_tag _("Edit issues"), class: "gl-button btn btn-default gl-mr-3 js-bulk-update-toggle"
|
||||||
|
|
|
@ -18,4 +18,5 @@
|
||||||
api_host: setting.api_host,
|
api_host: setting.api_host,
|
||||||
enabled: setting.enabled.to_json,
|
enabled: setting.enabled.to_json,
|
||||||
integrated: setting.integrated.to_json,
|
integrated: setting.integrated.to_json,
|
||||||
|
gitlab_dsn: setting.gitlab_dsn,
|
||||||
token: setting.token.present? ? '*' * 12 : nil } }
|
token: setting.token.present? ? '*' * 12 : nil } }
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
- continuous_integration_scaling
|
- continuous_integration_scaling
|
||||||
- database
|
- database
|
||||||
- dataops
|
- dataops
|
||||||
|
- delivery
|
||||||
- delivery_management
|
- delivery_management
|
||||||
- dependency_firewall
|
- dependency_firewall
|
||||||
- dependency_proxy
|
- dependency_proxy
|
||||||
|
@ -53,16 +54,15 @@
|
||||||
- five_minute_production_app
|
- five_minute_production_app
|
||||||
- foundations
|
- foundations
|
||||||
- fuzz_testing
|
- fuzz_testing
|
||||||
- gdk
|
|
||||||
- geo_replication
|
- geo_replication
|
||||||
- git_lfs
|
- git_lfs
|
||||||
- gitaly
|
- gitaly
|
||||||
- gitlab_docs
|
- gitlab_docs
|
||||||
- global_search
|
- global_search
|
||||||
- helm_chart_registry
|
- helm_chart_registry
|
||||||
|
- horse
|
||||||
- importers
|
- importers
|
||||||
- incident_management
|
- incident_management
|
||||||
- infrastructure
|
|
||||||
- infrastructure_as_code
|
- infrastructure_as_code
|
||||||
- insider_threat
|
- insider_threat
|
||||||
- integrations
|
- integrations
|
||||||
|
@ -103,12 +103,12 @@
|
||||||
- roadmaps
|
- roadmaps
|
||||||
- runbooks
|
- runbooks
|
||||||
- runner
|
- runner
|
||||||
|
- scalability
|
||||||
- secret_detection
|
- secret_detection
|
||||||
- secrets_management
|
- secrets_management
|
||||||
- security_benchmarking
|
- security_benchmarking
|
||||||
- security_orchestration
|
- security_orchestration
|
||||||
- self_monitoring
|
- self_monitoring
|
||||||
- serverless
|
|
||||||
- service_desk
|
- service_desk
|
||||||
- service_ping
|
- service_ping
|
||||||
- sharding
|
- sharding
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
---
|
||||||
|
name: vulnerability_location_image_filter
|
||||||
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/69867
|
||||||
|
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/340915
|
||||||
|
milestone: '14.4'
|
||||||
|
type: development
|
||||||
|
group: group::container security
|
||||||
|
default_enabled: false
|
|
@ -0,0 +1,10 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class DropInt4ColumnsForCiJobArtifacts < Gitlab::Database::Migration[1.0]
|
||||||
|
enable_lock_retries!
|
||||||
|
|
||||||
|
def change
|
||||||
|
remove_column :ci_job_artifacts, :id_convert_to_bigint, :integer, null: false, default: 0
|
||||||
|
remove_column :ci_job_artifacts, :job_id_convert_to_bigint, :integer, null: false, default: 0
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,9 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class DropInt4ColumnForEvents < Gitlab::Database::Migration[1.0]
|
||||||
|
enable_lock_retries!
|
||||||
|
|
||||||
|
def change
|
||||||
|
remove_column :events, :id_convert_to_bigint, :integer, null: false, default: 0
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1 @@
|
||||||
|
1d18e061cb5bcdaa7d3fcea93e58d65a6f2c8b557fe53ba461b6cfa570f565be
|
|
@ -0,0 +1 @@
|
||||||
|
011b714ee5d4389a5a172ae687eea3a814915fb39a5e5eae38b6ee423a903eaf
|
|
@ -11506,9 +11506,7 @@ CREATE SEQUENCE ci_instance_variables_id_seq
|
||||||
ALTER SEQUENCE ci_instance_variables_id_seq OWNED BY ci_instance_variables.id;
|
ALTER SEQUENCE ci_instance_variables_id_seq OWNED BY ci_instance_variables.id;
|
||||||
|
|
||||||
CREATE TABLE ci_job_artifacts (
|
CREATE TABLE ci_job_artifacts (
|
||||||
id_convert_to_bigint integer DEFAULT 0 NOT NULL,
|
|
||||||
project_id integer NOT NULL,
|
project_id integer NOT NULL,
|
||||||
job_id_convert_to_bigint integer DEFAULT 0 NOT NULL,
|
|
||||||
file_type integer NOT NULL,
|
file_type integer NOT NULL,
|
||||||
size bigint,
|
size bigint,
|
||||||
created_at timestamp with time zone NOT NULL,
|
created_at timestamp with time zone NOT NULL,
|
||||||
|
@ -13705,7 +13703,6 @@ CREATE SEQUENCE error_tracking_errors_id_seq
|
||||||
ALTER SEQUENCE error_tracking_errors_id_seq OWNED BY error_tracking_errors.id;
|
ALTER SEQUENCE error_tracking_errors_id_seq OWNED BY error_tracking_errors.id;
|
||||||
|
|
||||||
CREATE TABLE events (
|
CREATE TABLE events (
|
||||||
id_convert_to_bigint integer DEFAULT 0 NOT NULL,
|
|
||||||
project_id integer,
|
project_id integer,
|
||||||
author_id integer NOT NULL,
|
author_id integer NOT NULL,
|
||||||
target_id integer,
|
target_id integer,
|
||||||
|
|
|
@ -67,7 +67,7 @@ message is logged to:
|
||||||
- `log/file_hook.log` in a source installation.
|
- `log/file_hook.log` in a source installation.
|
||||||
|
|
||||||
NOTE:
|
NOTE:
|
||||||
Before 14.0 release, the file name was `plugin.log`
|
Before 14.0 release, the filename was `plugin.log`
|
||||||
|
|
||||||
## Creating file hooks
|
## Creating file hooks
|
||||||
|
|
||||||
|
|
|
@ -199,7 +199,7 @@ then make the following modifications:
|
||||||
|
|
||||||
## `application_role` already enables this. You only need this line if
|
## `application_role` already enables this. You only need this line if
|
||||||
## you selectively enable individual services that depend on Rails, like
|
## you selectively enable individual services that depend on Rails, like
|
||||||
## `puma`, `sidekiq`, `geo-logcursor`, etc.
|
## `puma`, `sidekiq`, `geo-logcursor`, and so on.
|
||||||
gitlab_rails['enable'] = true
|
gitlab_rails['enable'] = true
|
||||||
|
|
||||||
##
|
##
|
||||||
|
|
|
@ -41,7 +41,7 @@ Learn how to install, configure, update, and maintain your GitLab instance.
|
||||||
|
|
||||||
### Configuring GitLab
|
### Configuring GitLab
|
||||||
|
|
||||||
- [Adjust your instance's timezone](timezone.md): Customize the default time zone of GitLab.
|
- [Adjust your instance's time zone](timezone.md): Customize the default time zone of GitLab.
|
||||||
- [System hooks](../system_hooks/system_hooks.md): Notifications when users, projects and keys are changed.
|
- [System hooks](../system_hooks/system_hooks.md): Notifications when users, projects and keys are changed.
|
||||||
- [Security](../security/index.md): Learn what you can do to further secure your GitLab instance.
|
- [Security](../security/index.md): Learn what you can do to further secure your GitLab instance.
|
||||||
- [Usage statistics, version check, and Service Ping](../user/admin_area/settings/usage_statistics.md): Enable or disable information about your instance to be sent to GitLab, Inc.
|
- [Usage statistics, version check, and Service Ping](../user/admin_area/settings/usage_statistics.md): Enable or disable information about your instance to be sent to GitLab, Inc.
|
||||||
|
|
|
@ -146,9 +146,9 @@ a background job archives the job log. The log is moved to `/var/opt/gitlab/gitl
|
||||||
by default, or to object storage if configured.
|
by default, or to object storage if configured.
|
||||||
|
|
||||||
In a [scaled-out architecture](reference_architectures/index.md) with Rails and Sidekiq running on more than one
|
In a [scaled-out architecture](reference_architectures/index.md) with Rails and Sidekiq running on more than one
|
||||||
server, these two locations on the filesystem have to be shared using NFS.
|
server, these two locations on the file system have to be shared using NFS.
|
||||||
|
|
||||||
To eliminate both filesystem requirements:
|
To eliminate both file system requirements:
|
||||||
|
|
||||||
- [Enable the incremental logging feature](#enable-or-disable-incremental-logging), which uses Redis instead of disk space for temporary caching of job logs.
|
- [Enable the incremental logging feature](#enable-or-disable-incremental-logging), which uses Redis instead of disk space for temporary caching of job logs.
|
||||||
- Configure [object storage](job_artifacts.md#object-storage-settings) for storing archived job logs.
|
- Configure [object storage](job_artifacts.md#object-storage-settings) for storing archived job logs.
|
||||||
|
|
|
@ -60,7 +60,7 @@ We should aim to not remove sensitive configuration in the *next major* release
|
||||||
|
|
||||||
See the table below for some examples:
|
See the table below for some examples:
|
||||||
|
|
||||||
| Config. type | Deprecation announced | Final minor release | Remove |
|
| Configuration type | Deprecation announced | Final minor release | Remove |
|
||||||
| -------- | -------- | -------- | -------- |
|
| -------- | -------- | -------- | -------- |
|
||||||
| Sensitive | 10.1.0 | 10.9.0 | 11.0.0 |
|
| Sensitive | 10.1.0 | 10.9.0 | 11.0.0 |
|
||||||
| Sensitive | 10.7.0 | 10.9.0 | 12.0.0 |
|
| Sensitive | 10.7.0 | 10.9.0 | 12.0.0 |
|
||||||
|
@ -90,6 +90,6 @@ the feature will continue working the same way as if you had `gitlab_rails['bett
|
||||||
However, setting the old version of configuration will print out a deprecation
|
However, setting the old version of configuration will print out a deprecation
|
||||||
notice at the end of installation/upgrade/reconfigure run.
|
notice at the end of installation/upgrade/reconfigure run.
|
||||||
|
|
||||||
With GitLab 11, `gitlab_rails['configuration'] = true` will no longer work and you will have to manually change the configuration in `/etc/gitlab/gitlab.rb` to the new valid config.
|
With GitLab 11, `gitlab_rails['configuration'] = true` will no longer work and you will have to manually change the configuration in `/etc/gitlab/gitlab.rb` to the new valid configuration.
|
||||||
**Note** If this configuration option is sensitive and can put integrity of the installation or
|
**Note** If this configuration option is sensitive and can put integrity of the installation or
|
||||||
data in danger, installation/upgrade will be aborted.
|
data in danger, installation/upgrade will be aborted.
|
||||||
|
|
|
@ -10,7 +10,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
||||||
|
|
||||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/21811) in GitLab 12.9.
|
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/21811) in GitLab 12.9.
|
||||||
|
|
||||||
Get a list of all deploy tokens across the GitLab instance. This endpoint requires administrator access.
|
Get a list of all deploy tokens across the GitLab instance. This endpoint requires the Administrator role.
|
||||||
|
|
||||||
```plaintext
|
```plaintext
|
||||||
GET /deploy_tokens
|
GET /deploy_tokens
|
||||||
|
|
|
@ -94,7 +94,7 @@ POST /projects/:id/freeze_periods
|
||||||
| `id` | integer or string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding). |
|
| `id` | integer or string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding). |
|
||||||
| `freeze_start` | string | yes | Start of the Freeze Period in [cron](https://crontab.guru/) format. |
|
| `freeze_start` | string | yes | Start of the Freeze Period in [cron](https://crontab.guru/) format. |
|
||||||
| `freeze_end` | string | yes | End of the Freeze Period in [cron](https://crontab.guru/) format. |
|
| `freeze_end` | string | yes | End of the Freeze Period in [cron](https://crontab.guru/) format. |
|
||||||
| `cron_timezone` | string | no | The timezone for the cron fields, defaults to UTC if not provided. |
|
| `cron_timezone` | string | no | The time zone for the cron fields, defaults to UTC if not provided. |
|
||||||
|
|
||||||
Example request:
|
Example request:
|
||||||
|
|
||||||
|
@ -131,7 +131,7 @@ PUT /projects/:id/freeze_periods/:freeze_period_id
|
||||||
| `freeze_period_id` | integer or string | yes | The database ID of the Freeze Period. |
|
| `freeze_period_id` | integer or string | yes | The database ID of the Freeze Period. |
|
||||||
| `freeze_start` | string | no | Start of the Freeze Period in [cron](https://crontab.guru/) format. |
|
| `freeze_start` | string | no | Start of the Freeze Period in [cron](https://crontab.guru/) format. |
|
||||||
| `freeze_end` | string | no | End of the Freeze Period in [cron](https://crontab.guru/) format. |
|
| `freeze_end` | string | no | End of the Freeze Period in [cron](https://crontab.guru/) format. |
|
||||||
| `cron_timezone` | string | no | The timezone for the cron fields. |
|
| `cron_timezone` | string | no | The time zone for the cron fields. |
|
||||||
|
|
||||||
Example request:
|
Example request:
|
||||||
|
|
||||||
|
|
|
@ -469,6 +469,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
|
||||||
| ---- | ---- | ----------- |
|
| ---- | ---- | ----------- |
|
||||||
| <a id="queryvulnerabilitieshasissues"></a>`hasIssues` | [`Boolean`](#boolean) | Returns only the vulnerabilities which have linked issues. |
|
| <a id="queryvulnerabilitieshasissues"></a>`hasIssues` | [`Boolean`](#boolean) | Returns only the vulnerabilities which have linked issues. |
|
||||||
| <a id="queryvulnerabilitieshasresolution"></a>`hasResolution` | [`Boolean`](#boolean) | Returns only the vulnerabilities which have been resolved on default branch. |
|
| <a id="queryvulnerabilitieshasresolution"></a>`hasResolution` | [`Boolean`](#boolean) | Returns only the vulnerabilities which have been resolved on default branch. |
|
||||||
|
| <a id="queryvulnerabilitiesimage"></a>`image` | [`[String!]`](#string) | Filter vulnerabilities by location image. When this filter is present, the response only matches entries for a `reportType` that includes `container_scanning`, `cluster_image_scanning`. |
|
||||||
| <a id="queryvulnerabilitiesprojectid"></a>`projectId` | [`[ID!]`](#id) | Filter vulnerabilities by project. |
|
| <a id="queryvulnerabilitiesprojectid"></a>`projectId` | [`[ID!]`](#id) | Filter vulnerabilities by project. |
|
||||||
| <a id="queryvulnerabilitiesreporttype"></a>`reportType` | [`[VulnerabilityReportType!]`](#vulnerabilityreporttype) | Filter vulnerabilities by report type. |
|
| <a id="queryvulnerabilitiesreporttype"></a>`reportType` | [`[VulnerabilityReportType!]`](#vulnerabilityreporttype) | Filter vulnerabilities by report type. |
|
||||||
| <a id="queryvulnerabilitiesscanner"></a>`scanner` | [`[String!]`](#string) | Filter vulnerabilities by VulnerabilityScanner.externalId. |
|
| <a id="queryvulnerabilitiesscanner"></a>`scanner` | [`[String!]`](#string) | Filter vulnerabilities by VulnerabilityScanner.externalId. |
|
||||||
|
@ -10527,6 +10528,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
|
||||||
| ---- | ---- | ----------- |
|
| ---- | ---- | ----------- |
|
||||||
| <a id="groupvulnerabilitieshasissues"></a>`hasIssues` | [`Boolean`](#boolean) | Returns only the vulnerabilities which have linked issues. |
|
| <a id="groupvulnerabilitieshasissues"></a>`hasIssues` | [`Boolean`](#boolean) | Returns only the vulnerabilities which have linked issues. |
|
||||||
| <a id="groupvulnerabilitieshasresolution"></a>`hasResolution` | [`Boolean`](#boolean) | Returns only the vulnerabilities which have been resolved on default branch. |
|
| <a id="groupvulnerabilitieshasresolution"></a>`hasResolution` | [`Boolean`](#boolean) | Returns only the vulnerabilities which have been resolved on default branch. |
|
||||||
|
| <a id="groupvulnerabilitiesimage"></a>`image` | [`[String!]`](#string) | Filter vulnerabilities by location image. When this filter is present, the response only matches entries for a `reportType` that includes `container_scanning`, `cluster_image_scanning`. |
|
||||||
| <a id="groupvulnerabilitiesprojectid"></a>`projectId` | [`[ID!]`](#id) | Filter vulnerabilities by project. |
|
| <a id="groupvulnerabilitiesprojectid"></a>`projectId` | [`[ID!]`](#id) | Filter vulnerabilities by project. |
|
||||||
| <a id="groupvulnerabilitiesreporttype"></a>`reportType` | [`[VulnerabilityReportType!]`](#vulnerabilityreporttype) | Filter vulnerabilities by report type. |
|
| <a id="groupvulnerabilitiesreporttype"></a>`reportType` | [`[VulnerabilityReportType!]`](#vulnerabilityreporttype) | Filter vulnerabilities by report type. |
|
||||||
| <a id="groupvulnerabilitiesscanner"></a>`scanner` | [`[String!]`](#string) | Filter vulnerabilities by VulnerabilityScanner.externalId. |
|
| <a id="groupvulnerabilitiesscanner"></a>`scanner` | [`[String!]`](#string) | Filter vulnerabilities by VulnerabilityScanner.externalId. |
|
||||||
|
@ -13203,6 +13205,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
|
||||||
| ---- | ---- | ----------- |
|
| ---- | ---- | ----------- |
|
||||||
| <a id="projectvulnerabilitieshasissues"></a>`hasIssues` | [`Boolean`](#boolean) | Returns only the vulnerabilities which have linked issues. |
|
| <a id="projectvulnerabilitieshasissues"></a>`hasIssues` | [`Boolean`](#boolean) | Returns only the vulnerabilities which have linked issues. |
|
||||||
| <a id="projectvulnerabilitieshasresolution"></a>`hasResolution` | [`Boolean`](#boolean) | Returns only the vulnerabilities which have been resolved on default branch. |
|
| <a id="projectvulnerabilitieshasresolution"></a>`hasResolution` | [`Boolean`](#boolean) | Returns only the vulnerabilities which have been resolved on default branch. |
|
||||||
|
| <a id="projectvulnerabilitiesimage"></a>`image` | [`[String!]`](#string) | Filter vulnerabilities by location image. When this filter is present, the response only matches entries for a `reportType` that includes `container_scanning`, `cluster_image_scanning`. |
|
||||||
| <a id="projectvulnerabilitiesprojectid"></a>`projectId` | [`[ID!]`](#id) | Filter vulnerabilities by project. |
|
| <a id="projectvulnerabilitiesprojectid"></a>`projectId` | [`[ID!]`](#id) | Filter vulnerabilities by project. |
|
||||||
| <a id="projectvulnerabilitiesreporttype"></a>`reportType` | [`[VulnerabilityReportType!]`](#vulnerabilityreporttype) | Filter vulnerabilities by report type. |
|
| <a id="projectvulnerabilitiesreporttype"></a>`reportType` | [`[VulnerabilityReportType!]`](#vulnerabilityreporttype) | Filter vulnerabilities by report type. |
|
||||||
| <a id="projectvulnerabilitiesscanner"></a>`scanner` | [`[String!]`](#string) | Filter vulnerabilities by VulnerabilityScanner.externalId. |
|
| <a id="projectvulnerabilitiesscanner"></a>`scanner` | [`[String!]`](#string) | Filter vulnerabilities by VulnerabilityScanner.externalId. |
|
||||||
|
|
|
@ -830,7 +830,7 @@ curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" \
|
||||||
|
|
||||||
## Transfer project to group
|
## Transfer project to group
|
||||||
|
|
||||||
Transfer a project to the Group namespace. Available only to instance administrators, although an [alternative API endpoint](projects.md#transfer-a-project-to-a-new-namespace) is available which does not require instance administrator access. Transferring projects may fail when tagged packages exist in the project's repository.
|
Transfer a project to the Group namespace. Available only to instance administrators, although an [alternative API endpoint](projects.md#transfer-a-project-to-a-new-namespace) is available which does not require instance administrator role. Transferring projects may fail when tagged packages exist in the project's repository.
|
||||||
|
|
||||||
```plaintext
|
```plaintext
|
||||||
POST /groups/:id/projects/:project_id
|
POST /groups/:id/projects/:project_id
|
||||||
|
|
|
@ -11,7 +11,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
||||||
Instance-level Kubernetes clusters allow you to connect a Kubernetes cluster to the GitLab instance, which enables you to use the same cluster across multiple projects. [More information](../user/instance/clusters/index.md)
|
Instance-level Kubernetes clusters allow you to connect a Kubernetes cluster to the GitLab instance, which enables you to use the same cluster across multiple projects. [More information](../user/instance/clusters/index.md)
|
||||||
|
|
||||||
NOTE:
|
NOTE:
|
||||||
Users need administrator access to use these endpoints.
|
Users need the Administrator role to use these endpoints.
|
||||||
|
|
||||||
## List instance clusters
|
## List instance clusters
|
||||||
|
|
||||||
|
|
|
@ -5,15 +5,15 @@ group: Access
|
||||||
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/#designated-technical-writers
|
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/#designated-technical-writers
|
||||||
---
|
---
|
||||||
|
|
||||||
# GitLab as an OAuth 2.0 provider **(FREE)**
|
# OAuth 2.0 identity provider API **(FREE)**
|
||||||
|
|
||||||
This document covers using the [OAuth2](https://oauth.net/2/) protocol to allow
|
GitLab provides an API to allow third-party services to access GitLab resources on a user's behalf
|
||||||
other services to access GitLab resources on user's behalf.
|
with the [OAuth2](https://oauth.net/2/) protocol.
|
||||||
|
|
||||||
If you want GitLab to be an OAuth authentication service provider to sign into
|
To configure GitLab for this, see
|
||||||
other services, see the [OAuth2 authentication service provider](../integration/oauth_provider.md)
|
[Configure GitLab as an OAuth 2.0 authentication identity provider](../integration/oauth_provider.md).
|
||||||
documentation. This functionality is based on the
|
|
||||||
[doorkeeper Ruby gem](https://github.com/doorkeeper-gem/doorkeeper).
|
This functionality is based on the [doorkeeper Ruby gem](https://github.com/doorkeeper-gem/doorkeeper).
|
||||||
|
|
||||||
## Supported OAuth 2.0 flows
|
## Supported OAuth 2.0 flows
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ GitLab supports the following authorization flows:
|
||||||
- **Authorization code:** Secure and common flow. Recommended option for secure
|
- **Authorization code:** Secure and common flow. Recommended option for secure
|
||||||
server-side apps.
|
server-side apps.
|
||||||
- **Implicit grant:** Originally designed for user-agent only apps, such as
|
- **Implicit grant:** Originally designed for user-agent only apps, such as
|
||||||
single page web apps running on GitLab Pages).
|
single page web apps running on GitLab Pages.
|
||||||
The [Internet Engineering Task Force (IETF)](https://tools.ietf.org/html/draft-ietf-oauth-security-topics-09#section-2.1.2)
|
The [Internet Engineering Task Force (IETF)](https://tools.ietf.org/html/draft-ietf-oauth-security-topics-09#section-2.1.2)
|
||||||
recommends against Implicit grant flow.
|
recommends against Implicit grant flow.
|
||||||
- **Resource owner password credentials:** To be used **only** for securely
|
- **Resource owner password credentials:** To be used **only** for securely
|
||||||
|
|
|
@ -78,7 +78,7 @@ GET projects/:id/packages/debian/pool/:distribution/:letter/:package_name/:packa
|
||||||
| `letter` | string | yes | The Debian Classification (first-letter or lib-first-letter). |
|
| `letter` | string | yes | The Debian Classification (first-letter or lib-first-letter). |
|
||||||
| `package_name` | string | yes | The source package name. |
|
| `package_name` | string | yes | The source package name. |
|
||||||
| `package_version` | string | yes | The source package version. |
|
| `package_version` | string | yes | The source package version. |
|
||||||
| `file_name` | string | yes | The file name. |
|
| `file_name` | string | yes | The filename. |
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
curl --header "Private-Token: <personal_access_token>" "https://gitlab.example.com/api/v4/projects/1/packages/pool/my-distro/a/my-pkg/1.0.0/example_1.0.0~alpha2_amd64.deb"
|
curl --header "Private-Token: <personal_access_token>" "https://gitlab.example.com/api/v4/projects/1/packages/pool/my-distro/a/my-pkg/1.0.0/example_1.0.0~alpha2_amd64.deb"
|
||||||
|
@ -92,7 +92,7 @@ curl --header "Private-Token: <personal_access_token>" \
|
||||||
--remote-name
|
--remote-name
|
||||||
```
|
```
|
||||||
|
|
||||||
This writes the downloaded file using the remote file name in the current directory.
|
This writes the downloaded file using the remote filename in the current directory.
|
||||||
|
|
||||||
## Route prefix
|
## Route prefix
|
||||||
|
|
||||||
|
@ -150,7 +150,7 @@ curl --header "Private-Token: <personal_access_token>" \
|
||||||
--remote-name
|
--remote-name
|
||||||
```
|
```
|
||||||
|
|
||||||
This writes the downloaded file using the remote file name in the current directory.
|
This writes the downloaded file using the remote filename in the current directory.
|
||||||
|
|
||||||
## Download a signed distribution Release file
|
## Download a signed distribution Release file
|
||||||
|
|
||||||
|
@ -178,7 +178,7 @@ curl --header "Private-Token: <personal_access_token>" \
|
||||||
--remote-name
|
--remote-name
|
||||||
```
|
```
|
||||||
|
|
||||||
This writes the downloaded file using the remote file name in the current directory.
|
This writes the downloaded file using the remote filename in the current directory.
|
||||||
|
|
||||||
## Download a release file signature
|
## Download a release file signature
|
||||||
|
|
||||||
|
@ -206,7 +206,7 @@ curl --header "Private-Token: <personal_access_token>" \
|
||||||
--remote-name
|
--remote-name
|
||||||
```
|
```
|
||||||
|
|
||||||
This writes the downloaded file using the remote file name in the current directory.
|
This writes the downloaded file using the remote filename in the current directory.
|
||||||
|
|
||||||
## Download a binary file's index
|
## Download a binary file's index
|
||||||
|
|
||||||
|
@ -236,4 +236,4 @@ curl --header "Private-Token: <personal_access_token>" \
|
||||||
--remote-name
|
--remote-name
|
||||||
```
|
```
|
||||||
|
|
||||||
This writes the downloaded file using the remote file name in the current directory.
|
This writes the downloaded file using the remote filename in the current directory.
|
||||||
|
|
|
@ -63,7 +63,7 @@ GET projects/:id/packages/helm/:channel/charts/:file_name.tgz
|
||||||
| ----------- | ------ | -------- | ----------- |
|
| ----------- | ------ | -------- | ----------- |
|
||||||
| `id` | string | yes | The ID or full path of the project. |
|
| `id` | string | yes | The ID or full path of the project. |
|
||||||
| `channel` | string | yes | Helm repository channel. |
|
| `channel` | string | yes | Helm repository channel. |
|
||||||
| `file_name` | string | yes | Chart file name. |
|
| `file_name` | string | yes | Chart filename. |
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
curl --user <username>:<personal_access_token> \
|
curl --user <username>:<personal_access_token> \
|
||||||
|
|
|
@ -115,7 +115,7 @@ POST /projects/:id/pipeline_schedules
|
||||||
| `description` | string | yes | The description of the pipeline schedule. |
|
| `description` | string | yes | The description of the pipeline schedule. |
|
||||||
| `ref` | string | yes | The branch or tag name that is triggered. |
|
| `ref` | string | yes | The branch or tag name that is triggered. |
|
||||||
| `cron` | string | yes | The [cron](https://en.wikipedia.org/wiki/Cron) schedule, for example: `0 1 * * *`. |
|
| `cron` | string | yes | The [cron](https://en.wikipedia.org/wiki/Cron) schedule, for example: `0 1 * * *`. |
|
||||||
| `cron_timezone` | string | no | The timezone supported by `ActiveSupport::TimeZone`, for example: `Pacific Time (US & Canada)` (default: `UTC`). |
|
| `cron_timezone` | string | no | The time zone supported by `ActiveSupport::TimeZone`, for example: `Pacific Time (US & Canada)` (default: `UTC`). |
|
||||||
| `active` | boolean | no | The activation of pipeline schedule. If false is set, the pipeline schedule is initially deactivated (default: `true`). |
|
| `active` | boolean | no | The activation of pipeline schedule. If false is set, the pipeline schedule is initially deactivated (default: `true`). |
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
|
@ -162,7 +162,7 @@ PUT /projects/:id/pipeline_schedules/:pipeline_schedule_id
|
||||||
| `description` | string | no | The description of the pipeline schedule. |
|
| `description` | string | no | The description of the pipeline schedule. |
|
||||||
| `ref` | string | no | The branch or tag name that is triggered. |
|
| `ref` | string | no | The branch or tag name that is triggered. |
|
||||||
| `cron` | string | no | The [cron](https://en.wikipedia.org/wiki/Cron) schedule, for example: `0 1 * * *`. |
|
| `cron` | string | no | The [cron](https://en.wikipedia.org/wiki/Cron) schedule, for example: `0 1 * * *`. |
|
||||||
| `cron_timezone` | string | no | The timezone supported by `ActiveSupport::TimeZone` (for example `Pacific Time (US & Canada)`), or `TZInfo::Timezone` (for example `America/Los_Angeles`). |
|
| `cron_timezone` | string | no | The time zone supported by `ActiveSupport::TimeZone` (for example `Pacific Time (US & Canada)`), or `TZInfo::Timezone` (for example `America/Los_Angeles`). |
|
||||||
| `active` | boolean | no | The activation of pipeline schedule. If false is set, the pipeline schedule is initially deactivated. |
|
| `active` | boolean | no | The activation of pipeline schedule. If false is set, the pipeline schedule is initially deactivated. |
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
|
|
|
@ -14,7 +14,7 @@ The existing plans depend on the GitLab edition. In the Community Edition, only
|
||||||
is available. In the Enterprise Edition, additional plans are available as well.
|
is available. In the Enterprise Edition, additional plans are available as well.
|
||||||
|
|
||||||
NOTE:
|
NOTE:
|
||||||
Administrator access is required to use this API.
|
The Administrator role is required to use this API.
|
||||||
|
|
||||||
## Get current plan limits
|
## Get current plan limits
|
||||||
|
|
||||||
|
|
|
@ -729,3 +729,5 @@ Example response:
|
||||||
|
|
||||||
A release with a `released_at` attribute set to a future date is labeled
|
A release with a `released_at` attribute set to a future date is labeled
|
||||||
as an **Upcoming Release** [in the UI](../../user/project/releases/index.md#upcoming-releases).
|
as an **Upcoming Release** [in the UI](../../user/project/releases/index.md#upcoming-releases).
|
||||||
|
|
||||||
|
Additionally, if a [release is requested from the API](#list-releases), for each release with a `release_at` attribute set to a future date, an additional attribute `upcoming_release` (set to true) will be returned as part of the response.
|
||||||
|
|
|
@ -1161,7 +1161,7 @@ Blobs searches are performed on both filenames and contents. Search results:
|
||||||
times in the content.
|
times in the content.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/6/search?scope=blobs&search=installation&ref=feature"
|
curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/6/search?scope=blobs&search=keyword%20filename:*.py
|
||||||
```
|
```
|
||||||
|
|
||||||
Example response:
|
Example response:
|
||||||
|
@ -1175,7 +1175,7 @@ Example response:
|
||||||
"path": "README.md",
|
"path": "README.md",
|
||||||
"filename": "README.md",
|
"filename": "README.md",
|
||||||
"id": null,
|
"id": null,
|
||||||
"ref": "feature",
|
"ref": "master",
|
||||||
"startline": 46,
|
"startline": 46,
|
||||||
"project_id": 6
|
"project_id": 6
|
||||||
}
|
}
|
||||||
|
|
|
@ -514,7 +514,7 @@ Today, loading GraphQL requires a bunch of [dependencies](https://gitlab.com/git
|
||||||
|
|
||||||
GraphQL only needs to run in a specific context. If we could limit when it is being loaded we could effectively improve application efficiency, by reducing application load time and required memory. This, for example, is applicable for every size installation.
|
GraphQL only needs to run in a specific context. If we could limit when it is being loaded we could effectively improve application efficiency, by reducing application load time and required memory. This, for example, is applicable for every size installation.
|
||||||
|
|
||||||
A potential challenge with GraphQL and Websockets is that at some point we might want to use Action Cable subscriptions and push GraphQL/API payload from Sidekiq to clients. This would likely utilize Redis to pass data through. Where Sidekiq would publish information on Redis and ActionCable Node would pass through that information to connected clients. This way of working is possible in the above model, but we would have to use GraphQL or API (over HTTP endpoint) to calculate what should be sent.
|
A potential challenge with GraphQL and Websockets is that at some point we might want to use Action Cable subscriptions and push GraphQL/API payload from Sidekiq to clients. This would likely use Redis to pass data through. Where Sidekiq would publish information on Redis and ActionCable Node would pass through that information to connected clients. This way of working is possible in the above model, but we would have to use GraphQL or API (over HTTP endpoint) to calculate what should be sent.
|
||||||
|
|
||||||
An alternative way is to use a notification system that would always make an `ActionCable` node (the one handling WebSockets) generate a payload based on a send query instead of performing passthrough. This could be applicable since `ActionCable` is the one handling a given connection for a client. This could have a downside of having to recalculate the same payload if many clients would be watching the same resource. However, this behavior of system might still be desired for security purposes, as generated payload might be dependent on permission of watching client (we would show different for anonymous, and different for the member of the project).
|
An alternative way is to use a notification system that would always make an `ActionCable` node (the one handling WebSockets) generate a payload based on a send query instead of performing passthrough. This could be applicable since `ActionCable` is the one handling a given connection for a client. This could have a downside of having to recalculate the same payload if many clients would be watching the same resource. However, this behavior of system might still be desired for security purposes, as generated payload might be dependent on permission of watching client (we would show different for anonymous, and different for the member of the project).
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ they all live on their own. A few more problems with this approach:
|
||||||
- Features are coupled to their container. In practice it is not straight
|
- Features are coupled to their container. In practice it is not straight
|
||||||
forward to decouple a feature from its container. The degree of coupling
|
forward to decouple a feature from its container. The degree of coupling
|
||||||
varies across features.
|
varies across features.
|
||||||
- Naive duplication of features will result in a more complex and fragile code base.
|
- Naive duplication of features will result in a more complex and fragile codebase.
|
||||||
- Generalizing solutions across groups and projects may degrade system performance.
|
- Generalizing solutions across groups and projects may degrade system performance.
|
||||||
- The range of features span across many teams, and these changes will need to
|
- The range of features span across many teams, and these changes will need to
|
||||||
manage development interference.
|
manage development interference.
|
||||||
|
|
|
@ -454,7 +454,8 @@ FLAG:
|
||||||
On self-managed GitLab, by default this feature is available. To hide the feature per project or for your entire instance, ask an administrator to [disable the `ci_include_rules` flag](../../administration/feature_flags.md). On GitLab.com, this feature is available.
|
On self-managed GitLab, by default this feature is available. To hide the feature per project or for your entire instance, ask an administrator to [disable the `ci_include_rules` flag](../../administration/feature_flags.md). On GitLab.com, this feature is available.
|
||||||
|
|
||||||
You can use [`rules`](#rules) with `include` to conditionally include other configuration files.
|
You can use [`rules`](#rules) with `include` to conditionally include other configuration files.
|
||||||
You can only use `rules:if` in `include` with [certain variables](#variables-with-include).
|
You can only use [`if` rules](#rulesif) in `include`, and only with [certain variables](#variables-with-include).
|
||||||
|
`rules` keywords such as `changes` and `exists` are not supported.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
include:
|
include:
|
||||||
|
@ -1178,6 +1179,7 @@ job:
|
||||||
all rules. You can't mix `when` at the job-level with `when` in rules.
|
all rules. You can't mix `when` at the job-level with `when` in rules.
|
||||||
- Unlike variables in [`script`](../variables/index.md#use-cicd-variables-in-job-scripts)
|
- Unlike variables in [`script`](../variables/index.md#use-cicd-variables-in-job-scripts)
|
||||||
sections, variables in rules expressions are always formatted as `$VARIABLE`.
|
sections, variables in rules expressions are always formatted as `$VARIABLE`.
|
||||||
|
- You can use `rules:if` with `include` to [conditionally include other configuration files](#rules-with-include).
|
||||||
|
|
||||||
**Related topics**:
|
**Related topics**:
|
||||||
|
|
||||||
|
|
|
@ -142,7 +142,7 @@ Nanoc layout), which is displayed at the top of the page if defined.
|
||||||
The `type` metadata parameter is deprecated but still exists in documentation
|
The `type` metadata parameter is deprecated but still exists in documentation
|
||||||
pages. You can safely remove the `type` metadata parameter and its values.
|
pages. You can safely remove the `type` metadata parameter and its values.
|
||||||
|
|
||||||
## Move or rename a page
|
## Move, rename, or delete a page
|
||||||
|
|
||||||
See [redirects](redirects.md).
|
See [redirects](redirects.md).
|
||||||
|
|
||||||
|
|
|
@ -15,13 +15,26 @@ description: Learn how to contribute to GitLab Documentation.
|
||||||
|
|
||||||
# Redirects in GitLab documentation
|
# Redirects in GitLab documentation
|
||||||
|
|
||||||
Moving or renaming a document is the same as changing its location. Be sure
|
When you move, rename, or delete a page, you must add a redirect. Redirects reduce
|
||||||
to assign a technical writer to any merge request that renames or moves a page.
|
how often users get 404s when visiting the documentation site from out-of-date links, like:
|
||||||
Technical Writers can help with any questions and can review your change.
|
|
||||||
|
|
||||||
When moving or renaming a page, you must redirect browsers to the new page.
|
- Bookmarks
|
||||||
This ensures users find the new page, and have the opportunity to update their
|
- Links from external sites
|
||||||
bookmarks.
|
- Links from old blog posts
|
||||||
|
- Links in the documentation site global navigation
|
||||||
|
|
||||||
|
Add a redirect to ensure:
|
||||||
|
|
||||||
|
- Users see the new page and can update or delete their bookmark.
|
||||||
|
- External sites can update their links, especially sites that have automation that
|
||||||
|
check for redirecting links.
|
||||||
|
- The documentation site global navigation does not link to a missing page.
|
||||||
|
|
||||||
|
The links in the global navigation are already tested in the `gitlab-docs` project.
|
||||||
|
If the redirect is missing, the `gitlab-docs` project's `main` branch might break.
|
||||||
|
|
||||||
|
Be sure to assign a technical writer to any merge request that moves, renames, or deletes a page.
|
||||||
|
Technical Writers can help with any questions and can review your change.
|
||||||
|
|
||||||
There are two types of redirects:
|
There are two types of redirects:
|
||||||
|
|
||||||
|
|
|
@ -233,6 +233,11 @@ Any data or index cleanup needed to support migration retries should be handled
|
||||||
will re-enqueue itself with a delay which is set using the `throttle_delay` option described below. The batching
|
will re-enqueue itself with a delay which is set using the `throttle_delay` option described below. The batching
|
||||||
must be handled within the `migrate` method, this setting controls the re-enqueuing only.
|
must be handled within the `migrate` method, this setting controls the re-enqueuing only.
|
||||||
|
|
||||||
|
- `batch_size` - Sets the number of documents modified during a `batched!` migration run. This size should be set to a value which allows the updates
|
||||||
|
enough time to finish. This can be tuned in combination with the `throttle_delay` option described below. The batching
|
||||||
|
must be handled within a custom `migrate` method or by using the [`Elastic::MigrationBackfillHelper`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/app/workers/concerns/elastic/migration_backfill_helper.rb)
|
||||||
|
`migrate` method which uses this setting. Default value is 1000 documents.
|
||||||
|
|
||||||
- `throttle_delay` - Sets the wait time in between batch runs. This time should be set high enough to allow each migration batch
|
- `throttle_delay` - Sets the wait time in between batch runs. This time should be set high enough to allow each migration batch
|
||||||
enough time to finish. Additionally, the time should be less than 30 minutes since that is how often the
|
enough time to finish. Additionally, the time should be less than 30 minutes since that is how often the
|
||||||
[`Elastic::MigrationWorker`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/app/workers/elastic/migration_worker.rb)
|
[`Elastic::MigrationWorker`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/app/workers/elastic/migration_worker.rb)
|
||||||
|
|
|
@ -534,15 +534,24 @@ affecting version `2.50.3-2+deb9u1` of Debian package `glib2.0`:
|
||||||
},
|
},
|
||||||
"version": "2.50.3-2+deb9u1",
|
"version": "2.50.3-2+deb9u1",
|
||||||
"operating_system": "debian:9",
|
"operating_system": "debian:9",
|
||||||
"image": "index.docker.io/library/nginx:1.18"
|
"image": "index.docker.io/library/nginx:1.18",
|
||||||
|
"kubernetes_resource": {
|
||||||
|
"namespace": "production",
|
||||||
|
"kind": "Deployment",
|
||||||
|
"name": "nginx-ingress",
|
||||||
|
"container": "nginx",
|
||||||
|
"agent_id": "1"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The affected package is found when scanning the image of the pod `index.docker.io/library/nginx:1.18`.
|
The affected package is found when scanning a deployment using the `index.docker.io/library/nginx:1.18` image.
|
||||||
|
|
||||||
The location fingerprint of a Cluster Image Scanning vulnerability combines the
|
The location fingerprint of a Cluster Image Scanning vulnerability combines the
|
||||||
`operating_system` and the package `name`, so these attributes are mandatory. The `image` is also
|
`namespace`, `kind`, `name`, and `container` fields from the `kubernetes_resource`,
|
||||||
mandatory. All other attributes are optional.
|
as well as the package `name`, so these fields are required. The `image` field is also mandatory.
|
||||||
|
The `cluster_id` and `agent_id` are mutually exclusive, and one of them must be present.
|
||||||
|
All other fields are optional.
|
||||||
|
|
||||||
#### SAST
|
#### SAST
|
||||||
|
|
||||||
|
|
|
@ -103,7 +103,7 @@ sudo docker run --detach \
|
||||||
```
|
```
|
||||||
|
|
||||||
This will ensure that the Docker process has enough permissions to create the
|
This will ensure that the Docker process has enough permissions to create the
|
||||||
config files in the mounted volumes.
|
configuration files in the mounted volumes.
|
||||||
|
|
||||||
If you're using the [Kerberos integration](../integration/kerberos.md) **(PREMIUM ONLY)**,
|
If you're using the [Kerberos integration](../integration/kerberos.md) **(PREMIUM ONLY)**,
|
||||||
you must also publish your Kerberos port (for example, `--publish 8443:8443`).
|
you must also publish your Kerberos port (for example, `--publish 8443:8443`).
|
||||||
|
@ -573,7 +573,7 @@ sudo docker restart gitlab
|
||||||
|
|
||||||
This error occurs when using Docker Toolbox with VirtualBox on Windows or Mac,
|
This error occurs when using Docker Toolbox with VirtualBox on Windows or Mac,
|
||||||
and making use of Docker volumes. The `/c/Users` volume is mounted as a
|
and making use of Docker volumes. The `/c/Users` volume is mounted as a
|
||||||
VirtualBox Shared Folder, and does not support the all POSIX filesystem features.
|
VirtualBox Shared Folder, and does not support the all POSIX file system features.
|
||||||
The directory ownership and permissions cannot be changed without remounting, and
|
The directory ownership and permissions cannot be changed without remounting, and
|
||||||
GitLab fails.
|
GitLab fails.
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,7 @@ installation.
|
||||||
Activate all GitLab Enterprise Edition functionality with a license.
|
Activate all GitLab Enterprise Edition functionality with a license.
|
||||||
- [Pricing](https://about.gitlab.com/pricing/): Pricing for the different tiers.
|
- [Pricing](https://about.gitlab.com/pricing/): Pricing for the different tiers.
|
||||||
|
|
||||||
## Cross-repo Code Search
|
## Cross-repository Code Search
|
||||||
|
|
||||||
- [Advanced Search](../integration/elasticsearch.md): Leverage Elasticsearch for
|
- [Advanced Search](../integration/elasticsearch.md): Leverage Elasticsearch for
|
||||||
faster, more advanced code search across your entire GitLab instance.
|
faster, more advanced code search across your entire GitLab instance.
|
||||||
|
|
|
@ -169,7 +169,7 @@ of GitLab Support or other GitLab engineers.
|
||||||
operations to manage partitioned tables.
|
operations to manage partitioned tables.
|
||||||
|
|
||||||
- You should not modify the GitLab schema (for example, adding triggers or modifying tables).
|
- You should not modify the GitLab schema (for example, adding triggers or modifying tables).
|
||||||
Database migrations are tested against the schema definition in the GitLab code base. GitLab
|
Database migrations are tested against the schema definition in the GitLab codebase. GitLab
|
||||||
version upgrades may fail if the schema is modified.
|
version upgrades may fail if the schema is modified.
|
||||||
|
|
||||||
## Puma settings
|
## Puma settings
|
||||||
|
|
|
@ -64,8 +64,8 @@ Grant a GitLab user access to the select GitLab projects.
|
||||||
|
|
||||||
1. Grant the user permission to the GitLab projects.
|
1. Grant the user permission to the GitLab projects.
|
||||||
|
|
||||||
If you're integrating Jenkins with many GitLab projects, consider granting the user global
|
If you're integrating Jenkins with many GitLab projects, consider granting the user the global
|
||||||
Administrator permission. Otherwise, add the user to each project, and grant the Developer role.
|
Administrator role. Otherwise, add the user to each project, and grant the Developer role.
|
||||||
|
|
||||||
## Configure GitLab API access
|
## Configure GitLab API access
|
||||||
|
|
||||||
|
|
|
@ -4,18 +4,16 @@ group: Access
|
||||||
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
|
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
|
||||||
---
|
---
|
||||||
|
|
||||||
# GitLab as an OAuth 2.0 authentication service provider
|
# Configure GitLab as an OAuth 2.0 authentication identity provider
|
||||||
|
|
||||||
This document describes how you can use GitLab as an OAuth 2.0
|
This document describes how you can use GitLab as an OAuth 2.0 authentication identity provider.
|
||||||
authentication service provider.
|
|
||||||
|
|
||||||
If you want to use:
|
- OAuth 2 applications can be created and managed using the GitLab UI (described below)
|
||||||
|
or managed using the [Applications API](../api/applications.md).
|
||||||
- The [OAuth 2.0](https://oauth.net/2/) protocol to access GitLab resources on
|
- After an application is created, external services can manage access tokens using the
|
||||||
a user's behalf, see [OAuth 2.0 provider](../api/oauth2.md).
|
[OAuth 2 API](../api/oauth2.md).
|
||||||
- Other OAuth 2.0 authentication service providers to sign in to
|
- To allow users to sign in to GitLab using third-party OAuth 2 providers, see
|
||||||
GitLab, see the [OAuth 2.0 client documentation](omniauth.md).
|
[OmniAuth documentation](omniauth.md).
|
||||||
- The related API, see [Applications API](../api/applications.md).
|
|
||||||
|
|
||||||
## Introduction to OAuth
|
## Introduction to OAuth
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ To create an on-call schedule:
|
||||||
1. On the top bar, select **Menu > Projects** and find your project.
|
1. On the top bar, select **Menu > Projects** and find your project.
|
||||||
1. On the left sidebar, select **Monitor > On-call Schedules**.
|
1. On the left sidebar, select **Monitor > On-call Schedules**.
|
||||||
1. Select **Add a schedule**.
|
1. Select **Add a schedule**.
|
||||||
1. Enter the schedule's name and description and select a timezone.
|
1. Enter the schedule's name and description and select a time zone.
|
||||||
1. Select **Add schedule**.
|
1. Select **Add schedule**.
|
||||||
|
|
||||||
You now have an empty schedule with no rotations. This renders as an empty state, prompting you to
|
You now have an empty schedule with no rotations. This renders as an empty state, prompting you to
|
||||||
|
|
|
@ -43,7 +43,7 @@ This page gathers all the resources for the topic **Authentication** within GitL
|
||||||
- [Personal access tokens](../../api/index.md#personalproject-access-tokens)
|
- [Personal access tokens](../../api/index.md#personalproject-access-tokens)
|
||||||
- [Project access tokens](../../api/index.md#personalproject-access-tokens)
|
- [Project access tokens](../../api/index.md#personalproject-access-tokens)
|
||||||
- [Impersonation tokens](../../api/index.md#impersonation-tokens)
|
- [Impersonation tokens](../../api/index.md#impersonation-tokens)
|
||||||
- [GitLab as an OAuth2 provider](../../api/oauth2.md#gitlab-as-an-oauth-20-provider)
|
- [OAuth 2.0 identity provider API](../../api/oauth2.md)
|
||||||
|
|
||||||
## Third-party resources
|
## Third-party resources
|
||||||
|
|
||||||
|
|
|
@ -13,10 +13,10 @@ Welcome to GitLab! We're glad to have you here!
|
||||||
As a GitLab user you have access to all the features
|
As a GitLab user you have access to all the features
|
||||||
your [subscription](https://about.gitlab.com/pricing/)
|
your [subscription](https://about.gitlab.com/pricing/)
|
||||||
includes, except [GitLab administrator](../administration/index.md)
|
includes, except [GitLab administrator](../administration/index.md)
|
||||||
settings, unless you have admin privileges to install, configure,
|
settings, unless you have administrator privileges to install, configure,
|
||||||
and upgrade your GitLab instance.
|
and upgrade your GitLab instance.
|
||||||
|
|
||||||
Admin privileges for [GitLab.com](https://gitlab.com/) are restricted to the GitLab team.
|
Administrator privileges for [GitLab.com](https://gitlab.com/) are restricted to the GitLab team.
|
||||||
|
|
||||||
For more information on configuring GitLab self-managed instances, see the [Administrator documentation](../administration/index.md).
|
For more information on configuring GitLab self-managed instances, see the [Administrator documentation](../administration/index.md).
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ There are several types of users in GitLab:
|
||||||
|
|
||||||
- Regular users and GitLab.com users. <!-- Note: further description TBA -->
|
- Regular users and GitLab.com users. <!-- Note: further description TBA -->
|
||||||
- [Groups](group/index.md) of users.
|
- [Groups](group/index.md) of users.
|
||||||
- GitLab [admin area](admin_area/index.md) user.
|
- GitLab [administrator area](admin_area/index.md) user.
|
||||||
- [GitLab Administrator](../administration/index.md) with full access to
|
- [GitLab Administrator](../administration/index.md) with full access to
|
||||||
self-managed instances' features and settings.
|
self-managed instances' features and settings.
|
||||||
- [Internal users](../development/internal_users.md).
|
- [Internal users](../development/internal_users.md).
|
||||||
|
|
|
@ -63,8 +63,9 @@ information.
|
||||||
Follow this step-by-step guide to configure an executable runbook in GitLab using
|
Follow this step-by-step guide to configure an executable runbook in GitLab using
|
||||||
the components outlined above and the pre-loaded demo runbook.
|
the components outlined above and the pre-loaded demo runbook.
|
||||||
|
|
||||||
1. Create an [OAuth Application for JupyterHub](../../../../integration/oauth_provider.md#gitlab-as-an-oauth-20-authentication-service-provider).
|
1. Create an [OAuth application for JupyterHub](../../../../integration/oauth_provider.md).
|
||||||
1. When [installing JupyterHub with Helm](https://zero-to-jupyterhub.readthedocs.io/en/latest/jupyterhub/installation.html), use the following values
|
1. When [installing JupyterHub with Helm](https://zero-to-jupyterhub.readthedocs.io/en/latest/jupyterhub/installation.html),
|
||||||
|
use the following values:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
#-----------------------------------------------------------------------------
|
#-----------------------------------------------------------------------------
|
||||||
|
|
|
@ -61,6 +61,7 @@ module Gitlab
|
||||||
def self.databases
|
def self.databases
|
||||||
@databases ||= database_base_models
|
@databases ||= database_base_models
|
||||||
.transform_values { |connection_class| Connection.new(connection_class) }
|
.transform_values { |connection_class| Connection.new(connection_class) }
|
||||||
|
.with_indifferent_access
|
||||||
.freeze
|
.freeze
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -116,7 +116,7 @@ module Gitlab
|
||||||
def record_apdex_if_needed(elapsed)
|
def record_apdex_if_needed(elapsed)
|
||||||
return unless Gitlab::Metrics::RailsSlis.request_apdex_counters_enabled?
|
return unless Gitlab::Metrics::RailsSlis.request_apdex_counters_enabled?
|
||||||
|
|
||||||
Gitlab::Metrics::Sli[:rails_request_apdex].increment(
|
Gitlab::Metrics::RailsSlis.request_apdex.increment(
|
||||||
labels: labels_from_context,
|
labels: labels_from_context,
|
||||||
# hardcoded 1s here will be replaced by a per-endpoint value.
|
# hardcoded 1s here will be replaced by a per-endpoint value.
|
||||||
# https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/1223
|
# https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/1223
|
||||||
|
|
|
@ -64,9 +64,9 @@ module Gitlab
|
||||||
|
|
||||||
Sidekiq.redis do |redis|
|
Sidekiq.redis do |redis|
|
||||||
redis.multi do |multi|
|
redis.multi do |multi|
|
||||||
redis.set(idempotency_key, jid, ex: expiry, nx: true)
|
multi.set(idempotency_key, jid, ex: expiry, nx: true)
|
||||||
read_wal_locations = check_existing_wal_locations!(redis, expiry)
|
read_wal_locations = check_existing_wal_locations!(multi, expiry)
|
||||||
read_jid = redis.get(idempotency_key)
|
read_jid = multi.get(idempotency_key)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -81,9 +81,9 @@ module Gitlab
|
||||||
return unless job_wal_locations.present?
|
return unless job_wal_locations.present?
|
||||||
|
|
||||||
Sidekiq.redis do |redis|
|
Sidekiq.redis do |redis|
|
||||||
redis.multi do
|
redis.multi do |multi|
|
||||||
job_wal_locations.each do |connection_name, location|
|
job_wal_locations.each do |connection_name, location|
|
||||||
redis.eval(LUA_SET_WAL_SCRIPT, keys: [wal_location_key(connection_name)], argv: [location, pg_wal_lsn_diff(connection_name).to_i, WAL_LOCATION_TTL])
|
multi.eval(LUA_SET_WAL_SCRIPT, keys: [wal_location_key(connection_name)], argv: [location, pg_wal_lsn_diff(connection_name).to_i, WAL_LOCATION_TTL])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -96,9 +96,9 @@ module Gitlab
|
||||||
read_wal_locations = {}
|
read_wal_locations = {}
|
||||||
|
|
||||||
Sidekiq.redis do |redis|
|
Sidekiq.redis do |redis|
|
||||||
redis.multi do
|
redis.multi do |multi|
|
||||||
job_wal_locations.keys.each do |connection_name|
|
job_wal_locations.keys.each do |connection_name|
|
||||||
read_wal_locations[connection_name] = redis.lindex(wal_location_key(connection_name), 0)
|
read_wal_locations[connection_name] = multi.lindex(wal_location_key(connection_name), 0)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -110,8 +110,8 @@ module Gitlab
|
||||||
def delete!
|
def delete!
|
||||||
Sidekiq.redis do |redis|
|
Sidekiq.redis do |redis|
|
||||||
redis.multi do |multi|
|
redis.multi do |multi|
|
||||||
redis.del(idempotency_key)
|
multi.del(idempotency_key)
|
||||||
delete_wal_locations!(redis)
|
delete_wal_locations!(multi)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -147,7 +147,7 @@ module Gitlab
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
attr_accessor :existing_wal_locations
|
attr_writer :existing_wal_locations
|
||||||
attr_reader :queue_name, :job
|
attr_reader :queue_name, :job
|
||||||
attr_writer :existing_jid
|
attr_writer :existing_jid
|
||||||
|
|
||||||
|
@ -155,6 +155,31 @@ module Gitlab
|
||||||
@worker_klass ||= worker_class_name.to_s.safe_constantize
|
@worker_klass ||= worker_class_name.to_s.safe_constantize
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def delete_wal_locations!(redis)
|
||||||
|
job_wal_locations.keys.each do |connection_name|
|
||||||
|
redis.del(wal_location_key(connection_name))
|
||||||
|
redis.del(existing_wal_location_key(connection_name))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_existing_wal_locations!(redis, expiry)
|
||||||
|
read_wal_locations = {}
|
||||||
|
|
||||||
|
job_wal_locations.each do |connection_name, location|
|
||||||
|
key = existing_wal_location_key(connection_name)
|
||||||
|
redis.set(key, location, ex: expiry, nx: true)
|
||||||
|
read_wal_locations[connection_name] = redis.get(key)
|
||||||
|
end
|
||||||
|
|
||||||
|
read_wal_locations
|
||||||
|
end
|
||||||
|
|
||||||
|
def job_wal_locations
|
||||||
|
return {} unless preserve_wal_location?
|
||||||
|
|
||||||
|
job['wal_locations'] || {}
|
||||||
|
end
|
||||||
|
|
||||||
def pg_wal_lsn_diff(connection_name)
|
def pg_wal_lsn_diff(connection_name)
|
||||||
Gitlab::Database.databases[connection_name].pg_wal_lsn_diff(job_wal_locations[connection_name], existing_wal_locations[connection_name])
|
Gitlab::Database.databases[connection_name].pg_wal_lsn_diff(job_wal_locations[connection_name], existing_wal_locations[connection_name])
|
||||||
end
|
end
|
||||||
|
@ -179,12 +204,6 @@ module Gitlab
|
||||||
job['jid']
|
job['jid']
|
||||||
end
|
end
|
||||||
|
|
||||||
def job_wal_locations
|
|
||||||
return {} unless preserve_wal_location?
|
|
||||||
|
|
||||||
job['wal_locations'] || {}
|
|
||||||
end
|
|
||||||
|
|
||||||
def existing_wal_location_key(connection_name)
|
def existing_wal_location_key(connection_name)
|
||||||
"#{idempotency_key}:#{connection_name}:existing_wal_location"
|
"#{idempotency_key}:#{connection_name}:existing_wal_location"
|
||||||
end
|
end
|
||||||
|
@ -209,23 +228,8 @@ module Gitlab
|
||||||
"#{worker_class_name}:#{Sidekiq.dump_json(arguments)}"
|
"#{worker_class_name}:#{Sidekiq.dump_json(arguments)}"
|
||||||
end
|
end
|
||||||
|
|
||||||
def delete_wal_locations!(redis)
|
def existing_wal_locations
|
||||||
job_wal_locations.keys.each do |connection_name|
|
@existing_wal_locations ||= {}
|
||||||
redis.del(wal_location_key(connection_name))
|
|
||||||
redis.del(existing_wal_location_key(connection_name))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def check_existing_wal_locations!(redis, expiry)
|
|
||||||
read_wal_locations = {}
|
|
||||||
|
|
||||||
job_wal_locations.each do |connection_name, location|
|
|
||||||
key = existing_wal_location_key(connection_name)
|
|
||||||
redis.set(key, location, ex: expiry, nx: true)
|
|
||||||
read_wal_locations[connection_name] = redis.get(key)
|
|
||||||
end
|
|
||||||
|
|
||||||
read_wal_locations
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def preserve_wal_location?
|
def preserve_wal_location?
|
||||||
|
|
|
@ -4,11 +4,15 @@ module Gitlab
|
||||||
module SidekiqMiddleware
|
module SidekiqMiddleware
|
||||||
module DuplicateJobs
|
module DuplicateJobs
|
||||||
module Strategies
|
module Strategies
|
||||||
module DeduplicatesWhenScheduling
|
class DeduplicatesWhenScheduling < Base
|
||||||
|
extend ::Gitlab::Utils::Override
|
||||||
|
|
||||||
|
override :initialize
|
||||||
def initialize(duplicate_job)
|
def initialize(duplicate_job)
|
||||||
@duplicate_job = duplicate_job
|
@duplicate_job = duplicate_job
|
||||||
end
|
end
|
||||||
|
|
||||||
|
override :schedule
|
||||||
def schedule(job)
|
def schedule(job)
|
||||||
if deduplicatable_job? && check! && duplicate_job.duplicate?
|
if deduplicatable_job? && check! && duplicate_job.duplicate?
|
||||||
job['duplicate-of'] = duplicate_job.existing_jid
|
job['duplicate-of'] = duplicate_job.existing_jid
|
||||||
|
@ -25,6 +29,7 @@ module Gitlab
|
||||||
yield
|
yield
|
||||||
end
|
end
|
||||||
|
|
||||||
|
override :perform
|
||||||
def perform(job)
|
def perform(job)
|
||||||
update_job_wal_location!(job)
|
update_job_wal_location!(job)
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,11 +7,7 @@ module Gitlab
|
||||||
# This strategy takes a lock before scheduling the job in a queue and
|
# This strategy takes a lock before scheduling the job in a queue and
|
||||||
# removes the lock after the job has executed preventing a new job to be queued
|
# removes the lock after the job has executed preventing a new job to be queued
|
||||||
# while a job is still executing.
|
# while a job is still executing.
|
||||||
class UntilExecuted < Base
|
class UntilExecuted < DeduplicatesWhenScheduling
|
||||||
extend ::Gitlab::Utils::Override
|
|
||||||
|
|
||||||
include DeduplicatesWhenScheduling
|
|
||||||
|
|
||||||
override :perform
|
override :perform
|
||||||
def perform(job)
|
def perform(job)
|
||||||
super
|
super
|
||||||
|
|
|
@ -7,11 +7,7 @@ module Gitlab
|
||||||
# This strategy takes a lock before scheduling the job in a queue and
|
# This strategy takes a lock before scheduling the job in a queue and
|
||||||
# removes the lock before the job starts allowing a new job to be queued
|
# removes the lock before the job starts allowing a new job to be queued
|
||||||
# while a job is still executing.
|
# while a job is still executing.
|
||||||
class UntilExecuting < Base
|
class UntilExecuting < DeduplicatesWhenScheduling
|
||||||
extend ::Gitlab::Utils::Override
|
|
||||||
|
|
||||||
include DeduplicatesWhenScheduling
|
|
||||||
|
|
||||||
override :perform
|
override :perform
|
||||||
def perform(job)
|
def perform(job)
|
||||||
super
|
super
|
||||||
|
|
|
@ -968,11 +968,6 @@ msgstr ""
|
||||||
msgid "%{template_project_id} is unknown or invalid"
|
msgid "%{template_project_id} is unknown or invalid"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "%{text} %{files}"
|
|
||||||
msgid_plural "%{text} %{files} files"
|
|
||||||
msgstr[0] ""
|
|
||||||
msgstr[1] ""
|
|
||||||
|
|
||||||
msgid "%{text} is available"
|
msgid "%{text} is available"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -24460,6 +24455,9 @@ msgstr ""
|
||||||
msgid "Paste project path (i.e. gitlab-org/gitlab)"
|
msgid "Paste project path (i.e. gitlab-org/gitlab)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Paste this DSN into your Sentry SDK"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
|
msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -39997,6 +39995,9 @@ msgid_plural "from %d jobs"
|
||||||
msgstr[0] ""
|
msgstr[0] ""
|
||||||
msgstr[1] ""
|
msgstr[1] ""
|
||||||
|
|
||||||
|
msgid "frontmatter"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "group"
|
msgid "group"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
|
@ -183,7 +183,7 @@ module QA
|
||||||
another_project.remove_via_api!
|
another_project.remove_via_api!
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'pushes and pulls a Maven package via CI and deletes it', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/quality/test_cases/1627' do
|
it 'pushes and pulls a Maven package via CI and deletes it', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/quality/test_cases/1627', quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/341414', type: :investigating } do
|
||||||
Resource::Repository::Commit.fabricate_via_api! do |commit|
|
Resource::Repository::Commit.fabricate_via_api! do |commit|
|
||||||
commit.project = project
|
commit.project = project
|
||||||
commit.commit_message = 'Add .gitlab-ci.yml'
|
commit.commit_message = 'Add .gitlab-ci.yml'
|
||||||
|
@ -256,7 +256,7 @@ module QA
|
||||||
Page::Group::Settings::PackageRegistries.perform(&:set_allow_duplicates_disabled)
|
Page::Group::Settings::PackageRegistries.perform(&:set_allow_duplicates_disabled)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'prevents users from publishing duplicate Maven packages at the group level', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/quality/test_cases/1830' do
|
it 'prevents users from publishing duplicate Maven packages at the group level', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/quality/test_cases/1830', quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/341209', type: :investigating } do
|
||||||
with_fixtures([pom_xml, settings_xml]) do |dir|
|
with_fixtures([pom_xml, settings_xml]) do |dir|
|
||||||
Service::DockerRun::Maven.new(dir).publish!
|
Service::DockerRun::Maven.new(dir).publish!
|
||||||
end
|
end
|
||||||
|
@ -301,7 +301,7 @@ module QA
|
||||||
Page::Group::Settings::PackageRegistries.perform(&:set_allow_duplicates_enabled)
|
Page::Group::Settings::PackageRegistries.perform(&:set_allow_duplicates_enabled)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'allows users to publish duplicate Maven packages at the group level', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/quality/test_cases/1829' do
|
it 'allows users to publish duplicate Maven packages at the group level', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/quality/test_cases/1829', quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/341209', type: :investigating } do
|
||||||
with_fixtures([pom_xml, settings_xml]) do |dir|
|
with_fixtures([pom_xml, settings_xml]) do |dir|
|
||||||
Service::DockerRun::Maven.new(dir).publish!
|
Service::DockerRun::Maven.new(dir).publish!
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,7 +2,14 @@
|
||||||
|
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
|
||||||
|
def visit_jobs_page
|
||||||
|
visit(project_jobs_path(project))
|
||||||
|
|
||||||
|
wait_for_requests
|
||||||
|
end
|
||||||
|
|
||||||
RSpec.describe 'User browses jobs' do
|
RSpec.describe 'User browses jobs' do
|
||||||
|
describe 'with jobs_table_vue feature flag turned off' do
|
||||||
let!(:build) { create(:ci_build, :coverage, pipeline: pipeline) }
|
let!(:build) { create(:ci_build, :coverage, pipeline: pipeline) }
|
||||||
let(:pipeline) { create(:ci_empty_pipeline, project: project, sha: project.commit.sha, ref: 'master') }
|
let(:pipeline) { create(:ci_empty_pipeline, project: project, sha: project.commit.sha, ref: 'master') }
|
||||||
let(:project) { create(:project, :repository, namespace: user.namespace) }
|
let(:project) { create(:project, :repository, namespace: user.namespace) }
|
||||||
|
@ -35,4 +42,237 @@ RSpec.describe 'User browses jobs' do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'with jobs_table_vue feature flag turned on', :js do
|
||||||
|
let(:project) { create(:project, :repository) }
|
||||||
|
let(:user) { create(:user) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
stub_feature_flags(jobs_table_vue: true)
|
||||||
|
|
||||||
|
project.add_maintainer(user)
|
||||||
|
project.enable_ci
|
||||||
|
|
||||||
|
sign_in(user)
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'header tabs' do
|
||||||
|
before do
|
||||||
|
visit_jobs_page
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'shows a tab for All jobs and count' do
|
||||||
|
expect(page.find('[data-testid="jobs-all-tab"]').text).to include('All')
|
||||||
|
expect(page.find('[data-testid="jobs-all-tab"] .badge').text).to include('0')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'shows a tab for Pending jobs and count' do
|
||||||
|
expect(page.find('[data-testid="jobs-pending-tab"]').text).to include('Pending')
|
||||||
|
expect(page.find('[data-testid="jobs-pending-tab"] .badge').text).to include('0')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'shows a tab for Running jobs and count' do
|
||||||
|
expect(page.find('[data-testid="jobs-running-tab"]').text).to include('Running')
|
||||||
|
expect(page.find('[data-testid="jobs-running-tab"] .badge').text).to include('0')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'shows a tab for Finished jobs and count' do
|
||||||
|
expect(page.find('[data-testid="jobs-finished-tab"]').text).to include('Finished')
|
||||||
|
expect(page.find('[data-testid="jobs-finished-tab"] .badge').text).to include('0')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'updates the content when tab is clicked' do
|
||||||
|
page.find('[data-testid="jobs-finished-tab"]').click
|
||||||
|
wait_for_requests
|
||||||
|
|
||||||
|
expect(page).to have_content('No jobs to show')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'Empty state' do
|
||||||
|
before do
|
||||||
|
visit_jobs_page
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'renders an empty state' do
|
||||||
|
expect(page).to have_content 'Use jobs to automate your tasks'
|
||||||
|
expect(page).to have_content 'Create CI/CD configuration file'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'Job actions' do
|
||||||
|
let!(:pipeline) { create(:ci_empty_pipeline, project: project, sha: project.commit.id, ref: 'master') }
|
||||||
|
|
||||||
|
context 'when a job can be canceled' do
|
||||||
|
let!(:job) do
|
||||||
|
create(:ci_build, pipeline: pipeline,
|
||||||
|
stage: 'test')
|
||||||
|
end
|
||||||
|
|
||||||
|
before do
|
||||||
|
job.run
|
||||||
|
|
||||||
|
visit_jobs_page
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'cancels a job successfully' do
|
||||||
|
page.find('[data-testid="cancel-button"]').click
|
||||||
|
|
||||||
|
wait_for_requests
|
||||||
|
|
||||||
|
expect(page).to have_selector('.ci-canceled')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when a job can be retried' do
|
||||||
|
let!(:job) do
|
||||||
|
create(:ci_build, pipeline: pipeline,
|
||||||
|
stage: 'test')
|
||||||
|
end
|
||||||
|
|
||||||
|
before do
|
||||||
|
job.drop
|
||||||
|
|
||||||
|
visit_jobs_page
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'retries a job successfully' do
|
||||||
|
page.find('[data-testid="retry"]').click
|
||||||
|
|
||||||
|
wait_for_requests
|
||||||
|
|
||||||
|
expect(page).to have_selector('.ci-pending')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with a scheduled job' do
|
||||||
|
let!(:scheduled_job) { create(:ci_build, :scheduled, pipeline: pipeline, name: 'build') }
|
||||||
|
|
||||||
|
before do
|
||||||
|
visit_jobs_page
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'plays a job successfully' do
|
||||||
|
page.find('[data-testid="play-scheduled"]').click
|
||||||
|
|
||||||
|
page.within '#play-job-modal' do
|
||||||
|
page.find_button('OK').click
|
||||||
|
end
|
||||||
|
|
||||||
|
wait_for_requests
|
||||||
|
|
||||||
|
expect(page).to have_selector('.ci-pending')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'unschedules a job successfully' do
|
||||||
|
page.find('[data-testid="unschedule"]').click
|
||||||
|
|
||||||
|
wait_for_requests
|
||||||
|
|
||||||
|
expect(page).to have_selector('.ci-manual')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with downloadable artifacts' do
|
||||||
|
let!(:with_artifacts) do
|
||||||
|
build = create(:ci_build, :success,
|
||||||
|
pipeline: pipeline,
|
||||||
|
name: 'rspec tests',
|
||||||
|
stage: 'test')
|
||||||
|
|
||||||
|
create(:ci_job_artifact, :codequality, job: build)
|
||||||
|
end
|
||||||
|
|
||||||
|
before do
|
||||||
|
visit_jobs_page
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'shows the download artifacts button' do
|
||||||
|
expect(page).to have_selector('[data-testid="download-artifacts"]')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with artifacts expired' do
|
||||||
|
let!(:with_artifacts_expired) do
|
||||||
|
create(:ci_build, :expired, :success,
|
||||||
|
pipeline: pipeline,
|
||||||
|
name: 'rspec',
|
||||||
|
stage: 'test')
|
||||||
|
end
|
||||||
|
|
||||||
|
before do
|
||||||
|
visit_jobs_page
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not show the download artifacts button' do
|
||||||
|
expect(page).not_to have_selector('[data-testid="download-artifacts"]')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'Jobs table' do
|
||||||
|
let!(:pipeline) { create(:ci_empty_pipeline, project: project, sha: project.commit.id, ref: 'master') }
|
||||||
|
|
||||||
|
context 'column links' do
|
||||||
|
let!(:job) do
|
||||||
|
create(:ci_build, pipeline: pipeline,
|
||||||
|
stage: 'test')
|
||||||
|
end
|
||||||
|
|
||||||
|
before do
|
||||||
|
job.run
|
||||||
|
|
||||||
|
visit_jobs_page
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'contains a link to the pipeline' do
|
||||||
|
expect(page.find('[data-testid="pipeline-id"]')).to have_content "##{pipeline.id}"
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'contains a link to the job sha' do
|
||||||
|
expect(page.find('[data-testid="job-sha"]')).to have_content "#{job.sha[0..7]}"
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'contains a link to the job id' do
|
||||||
|
expect(page.find('[data-testid="job-id-link"]')).to have_content "#{job.id}"
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'contains a link to the job ref' do
|
||||||
|
expect(page.find('[data-testid="job-ref"]')).to have_content "#{job.ref}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'when user is not logged in' do
|
||||||
|
before do
|
||||||
|
sign_out(user)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when project is public' do
|
||||||
|
let(:public_project) { create(:project, :public, :repository) }
|
||||||
|
|
||||||
|
context 'without jobs' do
|
||||||
|
it 'shows an empty state' do
|
||||||
|
visit project_jobs_path(public_project)
|
||||||
|
wait_for_requests
|
||||||
|
|
||||||
|
expect(page).to have_content 'Use jobs to automate your tasks'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when project is private' do
|
||||||
|
let(:private_project) { create(:project, :private, :repository) }
|
||||||
|
|
||||||
|
it 'redirects the user to sign_in and displays the flash alert' do
|
||||||
|
visit project_jobs_path(private_project)
|
||||||
|
wait_for_requests
|
||||||
|
|
||||||
|
expect(page).to have_content 'You need to sign in'
|
||||||
|
expect(page.current_path).to eq("/users/sign_in")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -175,6 +175,12 @@ RSpec.describe 'Projects > Settings > For a forked project', :js do
|
||||||
wait_for_requests
|
wait_for_requests
|
||||||
|
|
||||||
assert_text('Your changes have been saved')
|
assert_text('Your changes have been saved')
|
||||||
|
|
||||||
|
within '.js-error-tracking-settings' do
|
||||||
|
click_button('Expand')
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(page).to have_content('Paste this DSN into your Sentry SDK')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
import { NodeViewWrapper, NodeViewContent } from '@tiptap/vue-2';
|
||||||
|
import { shallowMount } from '@vue/test-utils';
|
||||||
|
import FrontmatterWrapper from '~/content_editor/components/wrappers/frontmatter.vue';
|
||||||
|
|
||||||
|
describe('content/components/wrappers/frontmatter', () => {
|
||||||
|
let wrapper;
|
||||||
|
|
||||||
|
const createWrapper = async (nodeAttrs = { language: 'yaml' }) => {
|
||||||
|
wrapper = shallowMount(FrontmatterWrapper, {
|
||||||
|
propsData: {
|
||||||
|
node: {
|
||||||
|
attrs: nodeAttrs,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
wrapper.destroy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders a node-view-wrapper as a pre element', () => {
|
||||||
|
createWrapper();
|
||||||
|
|
||||||
|
expect(wrapper.findComponent(NodeViewWrapper).props().as).toBe('pre');
|
||||||
|
expect(wrapper.findComponent(NodeViewWrapper).classes()).toContain('gl-relative');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders a node-view-content as a code element', () => {
|
||||||
|
createWrapper();
|
||||||
|
|
||||||
|
expect(wrapper.findComponent(NodeViewContent).props().as).toBe('code');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders label indicating that code block is frontmatter', () => {
|
||||||
|
createWrapper();
|
||||||
|
|
||||||
|
const label = wrapper.find('[data-testid="frontmatter-label"]');
|
||||||
|
|
||||||
|
expect(label.text()).toEqual('frontmatter:yaml');
|
||||||
|
expect(label.classes()).toEqual(['gl-absolute', 'gl-top-0', 'gl-right-3']);
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,7 +1,8 @@
|
||||||
import { GlFormRadioGroup, GlFormRadio } from '@gitlab/ui';
|
import { GlFormRadioGroup, GlFormRadio, GlFormInputGroup } from '@gitlab/ui';
|
||||||
import { createLocalVue, shallowMount } from '@vue/test-utils';
|
import { createLocalVue, shallowMount } from '@vue/test-utils';
|
||||||
import { nextTick } from 'vue';
|
import { nextTick } from 'vue';
|
||||||
import Vuex from 'vuex';
|
import Vuex from 'vuex';
|
||||||
|
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
|
||||||
import { TEST_HOST } from 'helpers/test_constants';
|
import { TEST_HOST } from 'helpers/test_constants';
|
||||||
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
|
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
|
||||||
import ErrorTrackingSettings from '~/error_tracking_settings/components/app.vue';
|
import ErrorTrackingSettings from '~/error_tracking_settings/components/app.vue';
|
||||||
|
@ -12,6 +13,8 @@ import createStore from '~/error_tracking_settings/store';
|
||||||
const localVue = createLocalVue();
|
const localVue = createLocalVue();
|
||||||
localVue.use(Vuex);
|
localVue.use(Vuex);
|
||||||
|
|
||||||
|
const TEST_GITLAB_DSN = 'https://gitlab.example.com/123456';
|
||||||
|
|
||||||
describe('error tracking settings app', () => {
|
describe('error tracking settings app', () => {
|
||||||
let store;
|
let store;
|
||||||
let wrapper;
|
let wrapper;
|
||||||
|
@ -29,6 +32,10 @@ describe('error tracking settings app', () => {
|
||||||
initialProject: null,
|
initialProject: null,
|
||||||
listProjectsEndpoint: TEST_HOST,
|
listProjectsEndpoint: TEST_HOST,
|
||||||
operationsSettingsEndpoint: TEST_HOST,
|
operationsSettingsEndpoint: TEST_HOST,
|
||||||
|
gitlabDsn: TEST_GITLAB_DSN,
|
||||||
|
},
|
||||||
|
stubs: {
|
||||||
|
GlFormInputGroup, // we need this non-shallow to query for a component within a slot
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
@ -41,6 +48,12 @@ describe('error tracking settings app', () => {
|
||||||
findBackendSettingsRadioGroup().findAllComponents(GlFormRadio);
|
findBackendSettingsRadioGroup().findAllComponents(GlFormRadio);
|
||||||
const findElementWithText = (wrappers, text) => wrappers.filter((item) => item.text() === text);
|
const findElementWithText = (wrappers, text) => wrappers.filter((item) => item.text() === text);
|
||||||
const findSentrySettings = () => wrapper.findByTestId('sentry-setting-form');
|
const findSentrySettings = () => wrapper.findByTestId('sentry-setting-form');
|
||||||
|
const findDsnSettings = () => wrapper.findByTestId('gitlab-dsn-setting-form');
|
||||||
|
|
||||||
|
const enableGitLabErrorTracking = async () => {
|
||||||
|
findBackendSettingsRadioGroup().vm.$emit('change', true);
|
||||||
|
await nextTick();
|
||||||
|
};
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
store = createStore();
|
store = createStore();
|
||||||
|
@ -93,17 +106,35 @@ describe('error tracking settings app', () => {
|
||||||
expect(findElementWithText(findBackendSettingsRadioButtons(), 'GitLab')).toHaveLength(1);
|
expect(findElementWithText(findBackendSettingsRadioButtons(), 'GitLab')).toHaveLength(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('toggles the sentry-settings section when sentry is selected as a tracking-backend', async () => {
|
it('hides the Sentry settings when GitLab is selected as a tracking-backend', async () => {
|
||||||
expect(findSentrySettings().exists()).toBe(true);
|
expect(findSentrySettings().exists()).toBe(true);
|
||||||
|
|
||||||
// set the "integrated" setting to "true"
|
await enableGitLabErrorTracking();
|
||||||
findBackendSettingsRadioGroup().vm.$emit('change', true);
|
|
||||||
|
|
||||||
await nextTick();
|
|
||||||
|
|
||||||
expect(findSentrySettings().exists()).toBe(false);
|
expect(findSentrySettings().exists()).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('GitLab DSN section', () => {
|
||||||
|
it('is visible when GitLab is selected as a tracking-backend and DSN is present', async () => {
|
||||||
|
expect(findDsnSettings().exists()).toBe(false);
|
||||||
|
|
||||||
|
await enableGitLabErrorTracking();
|
||||||
|
|
||||||
|
expect(findDsnSettings().exists()).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('contains copy-to-clipboard functionality for the GitLab DSN string', async () => {
|
||||||
|
await enableGitLabErrorTracking();
|
||||||
|
|
||||||
|
const clipBoardInput = findDsnSettings().findComponent(GlFormInputGroup);
|
||||||
|
const clipBoardButton = findDsnSettings().findComponent(ClipboardButton);
|
||||||
|
|
||||||
|
expect(clipBoardInput.props('value')).toBe(TEST_GITLAB_DSN);
|
||||||
|
expect(clipBoardInput.attributes('readonly')).toBeTruthy();
|
||||||
|
expect(clipBoardButton.props('text')).toBe(TEST_GITLAB_DSN);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it.each([true, false])(
|
it.each([true, false])(
|
||||||
'calls the `updateIntegrated` action when the setting changes to `%s`',
|
'calls the `updateIntegrated` action when the setting changes to `%s`',
|
||||||
(integrated) => {
|
(integrated) => {
|
||||||
|
|
|
@ -219,3 +219,22 @@
|
||||||
# Sit amit
|
# Sit amit
|
||||||
|
|
||||||
### I don't know
|
### I don't know
|
||||||
|
- name: word_break
|
||||||
|
markdown: Fernstraßen<wbr>bau<wbr>privat<wbr>finanzierungs<wbr>gesetz
|
||||||
|
- name: frontmatter_yaml
|
||||||
|
markdown: |-
|
||||||
|
---
|
||||||
|
title: Page title
|
||||||
|
---
|
||||||
|
- name: frontmatter_toml
|
||||||
|
markdown: |-
|
||||||
|
+++
|
||||||
|
title = "Page title"
|
||||||
|
+++
|
||||||
|
- name: frontmatter_json
|
||||||
|
markdown: |-
|
||||||
|
;;;
|
||||||
|
{
|
||||||
|
"title": "Page title"
|
||||||
|
}
|
||||||
|
;;;
|
||||||
|
|
|
@ -126,7 +126,7 @@ describe('IDE commit module getters', () => {
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(getters.preBuiltCommitMessage(state, null, rootState)).toBe(
|
expect(getters.preBuiltCommitMessage(state, null, rootState)).toBe(
|
||||||
'Update test-file, index.js files',
|
'Update test-file, index.js',
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,13 @@ RSpec.describe Gitlab::Database do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '.databases' do
|
||||||
|
it 'stores connections as a HashWithIndifferentAccess' do
|
||||||
|
expect(described_class.databases.has_key?('main')).to be true
|
||||||
|
expect(described_class.databases.has_key?(:main)).to be true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe '.default_pool_size' do
|
describe '.default_pool_size' do
|
||||||
before do
|
before do
|
||||||
allow(Gitlab::Runtime).to receive(:max_threads).and_return(7)
|
allow(Gitlab::Runtime).to receive(:max_threads).and_return(7)
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'spec_helper'
|
||||||
|
require_migration!('drop_int4_columns_for_ci_job_artifacts')
|
||||||
|
|
||||||
|
RSpec.describe DropInt4ColumnsForCiJobArtifacts do
|
||||||
|
let(:ci_job_artifacts) { table(:ci_job_artifacts) }
|
||||||
|
|
||||||
|
it 'correctly migrates up and down' do
|
||||||
|
reversible_migration do |migration|
|
||||||
|
migration.before -> {
|
||||||
|
expect(ci_job_artifacts.column_names).to include('id_convert_to_bigint')
|
||||||
|
expect(ci_job_artifacts.column_names).to include('job_id_convert_to_bigint')
|
||||||
|
}
|
||||||
|
|
||||||
|
migration.after -> {
|
||||||
|
ci_job_artifacts.reset_column_information
|
||||||
|
expect(ci_job_artifacts.column_names).not_to include('id_convert_to_bigint')
|
||||||
|
expect(ci_job_artifacts.column_names).not_to include('job_id_convert_to_bigint')
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,21 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'spec_helper'
|
||||||
|
require_migration!('drop_int4_column_for_events')
|
||||||
|
|
||||||
|
RSpec.describe DropInt4ColumnForEvents do
|
||||||
|
let(:events) { table(:events) }
|
||||||
|
|
||||||
|
it 'correctly migrates up and down' do
|
||||||
|
reversible_migration do |migration|
|
||||||
|
migration.before -> {
|
||||||
|
expect(events.column_names).to include('id_convert_to_bigint')
|
||||||
|
}
|
||||||
|
|
||||||
|
migration.after -> {
|
||||||
|
events.reset_column_information
|
||||||
|
expect(events.column_names).not_to include('id_convert_to_bigint')
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -79,6 +79,46 @@ RSpec.describe ErrorTracking::ProjectErrorTrackingSetting do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'Callbacks' do
|
||||||
|
describe 'after_save :create_client_key!' do
|
||||||
|
subject { build(:project_error_tracking_setting, :integrated, project: project) }
|
||||||
|
|
||||||
|
context 'no client key yet' do
|
||||||
|
it 'creates a new client key' do
|
||||||
|
expect { subject.save! }.to change { ErrorTracking::ClientKey.count }.by(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'sentry backend' do
|
||||||
|
before do
|
||||||
|
subject.integrated = false
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not create a new client key' do
|
||||||
|
expect { subject.save! }.not_to change { ErrorTracking::ClientKey.count }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'feature disabled' do
|
||||||
|
before do
|
||||||
|
subject.enabled = false
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not create a new client key' do
|
||||||
|
expect { subject.save! }.not_to change { ErrorTracking::ClientKey.count }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'client key already exists' do
|
||||||
|
let!(:client_key) { create(:error_tracking_client_key, project: project) }
|
||||||
|
|
||||||
|
it 'does not create a new client key' do
|
||||||
|
expect { subject.save! }.not_to change { ErrorTracking::ClientKey.count }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe '.extract_sentry_external_url' do
|
describe '.extract_sentry_external_url' do
|
||||||
subject { described_class.extract_sentry_external_url(sentry_url) }
|
subject { described_class.extract_sentry_external_url(sentry_url) }
|
||||||
|
|
||||||
|
@ -494,4 +534,10 @@ RSpec.describe ErrorTracking::ProjectErrorTrackingSetting do
|
||||||
it { expect(subject.sentry_enabled).to eq(sentry_enabled) }
|
it { expect(subject.sentry_enabled).to eq(sentry_enabled) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#gitlab_dsn' do
|
||||||
|
let!(:client_key) { create(:error_tracking_client_key, project: project) }
|
||||||
|
|
||||||
|
it { expect(subject.gitlab_dsn).to eq(client_key.sentry_dsn) }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
|
||||||
RSpec.describe NamespacePolicy do
|
RSpec.describe Namespaces::UserNamespacePolicy do
|
||||||
let(:user) { create(:user) }
|
let(:user) { create(:user) }
|
||||||
let(:owner) { create(:user) }
|
let(:owner) { create(:user) }
|
||||||
let(:admin) { create(:admin) }
|
let(:admin) { create(:admin) }
|
|
@ -277,15 +277,15 @@ RSpec.describe Ci::RetryBuildService do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#reprocess' do
|
describe '#clone!' do
|
||||||
let(:new_build) do
|
let(:new_build) do
|
||||||
travel_to(1.second.from_now) do
|
travel_to(1.second.from_now) do
|
||||||
service.reprocess!(build)
|
service.clone!(build)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'raises an error when an unexpected class is passed' do
|
it 'raises an error when an unexpected class is passed' do
|
||||||
expect { service.reprocess!(create(:ci_build).present) }.to raise_error(TypeError)
|
expect { service.clone!(create(:ci_build).present) }.to raise_error(TypeError)
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when user has ability to execute build' do
|
context 'when user has ability to execute build' do
|
||||||
|
@ -343,7 +343,7 @@ RSpec.describe Ci::RetryBuildService do
|
||||||
let(:user) { reporter }
|
let(:user) { reporter }
|
||||||
|
|
||||||
it 'raises an error' do
|
it 'raises an error' do
|
||||||
expect { service.reprocess!(build) }
|
expect { service.clone!(build) }
|
||||||
.to raise_error Gitlab::Access::AccessDeniedError
|
.to raise_error Gitlab::Access::AccessDeniedError
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue