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),
|
||||
},
|
||||
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 Figure from '../extensions/figure';
|
||||
import FigureCaption from '../extensions/figure_caption';
|
||||
import Frontmatter from '../extensions/frontmatter';
|
||||
import Gapcursor from '../extensions/gapcursor';
|
||||
import HardBreak from '../extensions/hard_break';
|
||||
import Heading from '../extensions/heading';
|
||||
|
@ -43,6 +44,7 @@ import TaskItem from '../extensions/task_item';
|
|||
import TaskList from '../extensions/task_list';
|
||||
import Text from '../extensions/text';
|
||||
import Video from '../extensions/video';
|
||||
import WordBreak from '../extensions/word_break';
|
||||
import { ContentEditor } from './content_editor';
|
||||
import createMarkdownSerializer from './markdown_serializer';
|
||||
import trackInputRulesAndShortcuts from './track_input_rules_and_shortcuts';
|
||||
|
@ -85,6 +87,7 @@ export const createContentEditor = ({
|
|||
Emoji,
|
||||
Figure,
|
||||
FigureCaption,
|
||||
Frontmatter,
|
||||
Gapcursor,
|
||||
HardBreak,
|
||||
Heading,
|
||||
|
@ -112,6 +115,7 @@ export const createContentEditor = ({
|
|||
TaskList,
|
||||
Text,
|
||||
Video,
|
||||
WordBreak,
|
||||
];
|
||||
|
||||
const allExtensions = [...builtInContentEditorExtensions, ...extensions];
|
||||
|
|
|
@ -15,6 +15,7 @@ import Division from '../extensions/division';
|
|||
import Emoji from '../extensions/emoji';
|
||||
import Figure from '../extensions/figure';
|
||||
import FigureCaption from '../extensions/figure_caption';
|
||||
import Frontmatter from '../extensions/frontmatter';
|
||||
import HardBreak from '../extensions/hard_break';
|
||||
import Heading from '../extensions/heading';
|
||||
import HorizontalRule from '../extensions/horizontal_rule';
|
||||
|
@ -39,6 +40,7 @@ import TaskItem from '../extensions/task_item';
|
|||
import TaskList from '../extensions/task_list';
|
||||
import Text from '../extensions/text';
|
||||
import Video from '../extensions/video';
|
||||
import WordBreak from '../extensions/word_break';
|
||||
import {
|
||||
isPlainURL,
|
||||
renderHardBreak,
|
||||
|
@ -136,6 +138,20 @@ const defaultSerializerConfig = {
|
|||
|
||||
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'),
|
||||
[FigureCaption.name]: renderHTMLNode('figcaption'),
|
||||
[HardBreak.name]: renderHardBreak,
|
||||
|
@ -166,6 +182,7 @@ const defaultSerializerConfig = {
|
|||
},
|
||||
[Text.name]: defaultMarkdownSerializer.nodes.text,
|
||||
[Video.name]: renderPlayable,
|
||||
[WordBreak.name]: (state) => state.write('<wbr>'),
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -1,6 +1,14 @@
|
|||
<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 ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
|
||||
import ErrorTrackingForm from './error_tracking_form.vue';
|
||||
import ProjectDropdown from './project_dropdown.vue';
|
||||
|
||||
|
@ -12,7 +20,9 @@ export default {
|
|||
GlFormGroup,
|
||||
GlFormRadioGroup,
|
||||
GlFormRadio,
|
||||
GlFormInputGroup,
|
||||
ProjectDropdown,
|
||||
ClipboardButton,
|
||||
},
|
||||
props: {
|
||||
initialApiHost: {
|
||||
|
@ -46,6 +56,11 @@ export default {
|
|||
type: String,
|
||||
required: true,
|
||||
},
|
||||
gitlabDsn: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
|
@ -63,6 +78,9 @@ export default {
|
|||
'settingsLoading',
|
||||
'token',
|
||||
]),
|
||||
showGitlabDsnSetting() {
|
||||
return this.integrated && this.enabled && this.gitlabDsn;
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.setInitialState({
|
||||
|
@ -119,6 +137,17 @@ export default {
|
|||
</gl-form-radio>
|
||||
</gl-form-radio-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">
|
||||
<error-tracking-form />
|
||||
<div class="form-group">
|
||||
|
|
|
@ -13,6 +13,7 @@ export default () => {
|
|||
token,
|
||||
listProjectsEndpoint,
|
||||
operationsSettingsEndpoint,
|
||||
gitlabDsn,
|
||||
},
|
||||
} = formContainerEl;
|
||||
|
||||
|
@ -29,6 +30,7 @@ export default () => {
|
|||
initialToken: token,
|
||||
listProjectsEndpoint,
|
||||
operationsSettingsEndpoint,
|
||||
gitlabDsn,
|
||||
},
|
||||
});
|
||||
},
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
import { sprintf, n__, __ } from '../../../../locale';
|
||||
import { __ } from '../../../../locale';
|
||||
import { COMMIT_TO_NEW_BRANCH } from './constants';
|
||||
|
||||
const BRANCH_SUFFIX_COUNT = 5;
|
||||
const createTranslatedTextForFiles = (files, text) => {
|
||||
if (!files.length) return null;
|
||||
|
||||
return sprintf(n__('%{text} %{files}', '%{text} %{files} files', files.length), {
|
||||
files: files.reduce((acc, val) => acc.concat(val.path), []).join(', '),
|
||||
text,
|
||||
});
|
||||
const filesPart = files.reduce((acc, val) => acc.concat(val.path), []).join(', ');
|
||||
|
||||
return `${text} ${filesPart}`;
|
||||
};
|
||||
|
||||
export const discardDraftButtonDisabled = (state) =>
|
||||
|
|
|
@ -136,7 +136,13 @@ export default {
|
|||
<template>
|
||||
<gl-button-group>
|
||||
<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">
|
||||
<gl-button icon="planning" disabled data-testid="countdown">
|
||||
<gl-countdown :end-date-string="scheduledAt" />
|
||||
|
|
|
@ -4,7 +4,7 @@ class Admin::Serverless::DomainsController < Admin::ApplicationController
|
|||
before_action :check_feature_flag
|
||||
before_action :domain, only: [:update, :verify, :destroy]
|
||||
|
||||
feature_category :serverless
|
||||
feature_category :not_owned
|
||||
|
||||
def index
|
||||
@domain = PagesDomain.instance_serverless.first_or_initialize
|
||||
|
|
|
@ -5,7 +5,7 @@ module Projects
|
|||
class FunctionsController < Projects::ApplicationController
|
||||
before_action :authorize_read_cluster!
|
||||
|
||||
feature_category :serverless
|
||||
feature_category :not_owned
|
||||
|
||||
def index
|
||||
respond_to do |format|
|
||||
|
|
|
@ -46,6 +46,11 @@ module ErrorTracking
|
|||
|
||||
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
|
||||
enabled && !integrated_client?
|
||||
end
|
||||
|
@ -54,6 +59,12 @@ module ErrorTracking
|
|||
integrated
|
||||
end
|
||||
|
||||
def gitlab_dsn
|
||||
strong_memoize(:gitlab_dsn) do
|
||||
client_key&.sentry_dsn
|
||||
end
|
||||
end
|
||||
|
||||
def api_url=(value)
|
||||
super
|
||||
clear_memoization(:api_url_slugs)
|
||||
|
@ -236,5 +247,19 @@ module ErrorTracking
|
|||
errors.add(:project, 'is a required field')
|
||||
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
|
||||
|
|
|
@ -1,26 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class NamespacePolicy < 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
|
||||
class NamespacePolicy < ::Namespaces::UserNamespacePolicy
|
||||
# NamespacePolicy has been traditionally for user namespaces.
|
||||
# So these policies have been moved into Namespaces::UserNamespacePolicy.
|
||||
# Once the user namespace conversion is complete, we can look at
|
||||
# either removing this file or locating common namespace policy items
|
||||
# here.
|
||||
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)
|
||||
build.ensure_scheduling_type!
|
||||
|
||||
reprocess!(build).tap do |new_build|
|
||||
clone!(build).tap do |new_build|
|
||||
check_assignable_runners!(new_build)
|
||||
next if new_build.failed?
|
||||
|
||||
|
@ -31,7 +31,7 @@ module Ci
|
|||
end
|
||||
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
def reprocess!(build)
|
||||
def clone!(build)
|
||||
# Cloning a build requires a strict type check to ensure
|
||||
# the attributes being used for the clone are taken straight
|
||||
# from the model and not overridden by other abstractions.
|
||||
|
|
|
@ -9,17 +9,12 @@ module Ci
|
|||
raise Gitlab::Access::AccessDeniedError
|
||||
end
|
||||
|
||||
needs = Set.new
|
||||
|
||||
pipeline.ensure_scheduling_type!
|
||||
|
||||
builds_relation(pipeline).find_each do |build|
|
||||
next unless can_be_retried?(build)
|
||||
|
||||
Ci::RetryBuildService.new(project, current_user)
|
||||
.reprocess!(build)
|
||||
|
||||
needs += build.needs.map(&:name)
|
||||
Ci::RetryBuildService.new(project, current_user).clone!(build)
|
||||
end
|
||||
|
||||
pipeline.builds.latest.skipped.find_each do |skipped|
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
- if show_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
|
||||
= 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,
|
||||
enabled: setting.enabled.to_json,
|
||||
integrated: setting.integrated.to_json,
|
||||
gitlab_dsn: setting.gitlab_dsn,
|
||||
token: setting.token.present? ? '*' * 12 : nil } }
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
- continuous_integration_scaling
|
||||
- database
|
||||
- dataops
|
||||
- delivery
|
||||
- delivery_management
|
||||
- dependency_firewall
|
||||
- dependency_proxy
|
||||
|
@ -53,16 +54,15 @@
|
|||
- five_minute_production_app
|
||||
- foundations
|
||||
- fuzz_testing
|
||||
- gdk
|
||||
- geo_replication
|
||||
- git_lfs
|
||||
- gitaly
|
||||
- gitlab_docs
|
||||
- global_search
|
||||
- helm_chart_registry
|
||||
- horse
|
||||
- importers
|
||||
- incident_management
|
||||
- infrastructure
|
||||
- infrastructure_as_code
|
||||
- insider_threat
|
||||
- integrations
|
||||
|
@ -103,12 +103,12 @@
|
|||
- roadmaps
|
||||
- runbooks
|
||||
- runner
|
||||
- scalability
|
||||
- secret_detection
|
||||
- secrets_management
|
||||
- security_benchmarking
|
||||
- security_orchestration
|
||||
- self_monitoring
|
||||
- serverless
|
||||
- service_desk
|
||||
- service_ping
|
||||
- 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;
|
||||
|
||||
CREATE TABLE ci_job_artifacts (
|
||||
id_convert_to_bigint integer DEFAULT 0 NOT NULL,
|
||||
project_id integer NOT NULL,
|
||||
job_id_convert_to_bigint integer DEFAULT 0 NOT NULL,
|
||||
file_type integer NOT NULL,
|
||||
size bigint,
|
||||
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;
|
||||
|
||||
CREATE TABLE events (
|
||||
id_convert_to_bigint integer DEFAULT 0 NOT NULL,
|
||||
project_id integer,
|
||||
author_id integer NOT NULL,
|
||||
target_id integer,
|
||||
|
|
|
@ -67,7 +67,7 @@ message is logged to:
|
|||
- `log/file_hook.log` in a source installation.
|
||||
|
||||
NOTE:
|
||||
Before 14.0 release, the file name was `plugin.log`
|
||||
Before 14.0 release, the filename was `plugin.log`
|
||||
|
||||
## Creating file hooks
|
||||
|
||||
|
|
|
@ -199,7 +199,7 @@ then make the following modifications:
|
|||
|
||||
## `application_role` already enables this. You only need this line if
|
||||
## 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
|
||||
|
||||
##
|
||||
|
|
|
@ -41,7 +41,7 @@ Learn how to install, configure, update, and maintain your GitLab instance.
|
|||
|
||||
### 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.
|
||||
- [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.
|
||||
|
|
|
@ -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.
|
||||
|
||||
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.
|
||||
- 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:
|
||||
|
||||
| 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.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
|
||||
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
|
||||
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.
|
||||
|
||||
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
|
||||
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). |
|
||||
| `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. |
|
||||
| `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:
|
||||
|
||||
|
@ -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_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. |
|
||||
| `cron_timezone` | string | no | The timezone for the cron fields. |
|
||||
| `cron_timezone` | string | no | The time zone for the cron fields. |
|
||||
|
||||
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="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="queryvulnerabilitiesreporttype"></a>`reportType` | [`[VulnerabilityReportType!]`](#vulnerabilityreporttype) | Filter vulnerabilities by report type. |
|
||||
| <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="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="groupvulnerabilitiesreporttype"></a>`reportType` | [`[VulnerabilityReportType!]`](#vulnerabilityreporttype) | Filter vulnerabilities by report type. |
|
||||
| <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="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="projectvulnerabilitiesreporttype"></a>`reportType` | [`[VulnerabilityReportType!]`](#vulnerabilityreporttype) | Filter vulnerabilities by report type. |
|
||||
| <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 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
|
||||
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)
|
||||
|
||||
NOTE:
|
||||
Users need administrator access to use these endpoints.
|
||||
Users need the Administrator role to use these endpoints.
|
||||
|
||||
## 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
|
||||
---
|
||||
|
||||
# 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
|
||||
other services to access GitLab resources on user's behalf.
|
||||
GitLab provides an API to allow third-party services to access GitLab resources on a 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
|
||||
other services, see the [OAuth2 authentication service provider](../integration/oauth_provider.md)
|
||||
documentation. This functionality is based on the
|
||||
[doorkeeper Ruby gem](https://github.com/doorkeeper-gem/doorkeeper).
|
||||
To configure GitLab for this, see
|
||||
[Configure GitLab as an OAuth 2.0 authentication identity provider](../integration/oauth_provider.md).
|
||||
|
||||
This functionality is based on the [doorkeeper Ruby gem](https://github.com/doorkeeper-gem/doorkeeper).
|
||||
|
||||
## 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
|
||||
server-side apps.
|
||||
- **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)
|
||||
recommends against Implicit grant flow.
|
||||
- **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). |
|
||||
| `package_name` | string | yes | The source package name. |
|
||||
| `package_version` | string | yes | The source package version. |
|
||||
| `file_name` | string | yes | The file name. |
|
||||
| `file_name` | string | yes | The filename. |
|
||||
|
||||
```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"
|
||||
|
@ -92,7 +92,7 @@ curl --header "Private-Token: <personal_access_token>" \
|
|||
--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
|
||||
|
||||
|
@ -150,7 +150,7 @@ curl --header "Private-Token: <personal_access_token>" \
|
|||
--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
|
||||
|
||||
|
@ -178,7 +178,7 @@ curl --header "Private-Token: <personal_access_token>" \
|
|||
--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
|
||||
|
||||
|
@ -206,7 +206,7 @@ curl --header "Private-Token: <personal_access_token>" \
|
|||
--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
|
||||
|
||||
|
@ -236,4 +236,4 @@ curl --header "Private-Token: <personal_access_token>" \
|
|||
--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. |
|
||||
| `channel` | string | yes | Helm repository channel. |
|
||||
| `file_name` | string | yes | Chart file name. |
|
||||
| `file_name` | string | yes | Chart filename. |
|
||||
|
||||
```shell
|
||||
curl --user <username>:<personal_access_token> \
|
||||
|
|
|
@ -115,7 +115,7 @@ POST /projects/:id/pipeline_schedules
|
|||
| `description` | string | yes | The description of the pipeline schedule. |
|
||||
| `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_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`). |
|
||||
|
||||
```shell
|
||||
|
@ -162,7 +162,7 @@ PUT /projects/:id/pipeline_schedules/:pipeline_schedule_id
|
|||
| `description` | string | no | The description of the pipeline schedule. |
|
||||
| `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_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. |
|
||||
|
||||
```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.
|
||||
|
||||
NOTE:
|
||||
Administrator access is required to use this API.
|
||||
The Administrator role is required to use this API.
|
||||
|
||||
## Get current plan limits
|
||||
|
||||
|
|
|
@ -729,3 +729,5 @@ Example response:
|
|||
|
||||
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).
|
||||
|
||||
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.
|
||||
|
||||
```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:
|
||||
|
@ -1175,7 +1175,7 @@ Example response:
|
|||
"path": "README.md",
|
||||
"filename": "README.md",
|
||||
"id": null,
|
||||
"ref": "feature",
|
||||
"ref": "master",
|
||||
"startline": 46,
|
||||
"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.
|
||||
|
||||
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).
|
||||
|
||||
|
|
|
@ -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
|
||||
forward to decouple a feature from its container. The degree of coupling
|
||||
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.
|
||||
- The range of features span across many teams, and these changes will need to
|
||||
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.
|
||||
|
||||
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
|
||||
include:
|
||||
|
@ -1178,6 +1179,7 @@ job:
|
|||
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)
|
||||
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**:
|
||||
|
||||
|
|
|
@ -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
|
||||
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).
|
||||
|
||||
|
|
|
@ -15,13 +15,26 @@ description: Learn how to contribute to GitLab Documentation.
|
|||
|
||||
# Redirects in GitLab documentation
|
||||
|
||||
Moving or renaming a document is the same as changing its location. Be sure
|
||||
to assign a technical writer to any merge request that renames or moves a page.
|
||||
Technical Writers can help with any questions and can review your change.
|
||||
When you move, rename, or delete a page, you must add a redirect. Redirects reduce
|
||||
how often users get 404s when visiting the documentation site from out-of-date links, like:
|
||||
|
||||
When moving or renaming a page, you must redirect browsers to the new page.
|
||||
This ensures users find the new page, and have the opportunity to update their
|
||||
bookmarks.
|
||||
- Bookmarks
|
||||
- Links from external sites
|
||||
- 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:
|
||||
|
||||
|
|
|
@ -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
|
||||
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
|
||||
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)
|
||||
|
|
|
@ -534,15 +534,24 @@ affecting version `2.50.3-2+deb9u1` of Debian package `glib2.0`:
|
|||
},
|
||||
"version": "2.50.3-2+deb9u1",
|
||||
"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
|
||||
`operating_system` and the package `name`, so these attributes are mandatory. The `image` is also
|
||||
mandatory. All other attributes are optional.
|
||||
`namespace`, `kind`, `name`, and `container` fields from the `kubernetes_resource`,
|
||||
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
|
||||
|
||||
|
|
|
@ -103,7 +103,7 @@ sudo docker run --detach \
|
|||
```
|
||||
|
||||
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)**,
|
||||
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,
|
||||
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
|
||||
GitLab fails.
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ installation.
|
|||
Activate all GitLab Enterprise Edition functionality with a license.
|
||||
- [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
|
||||
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.
|
||||
|
||||
- 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.
|
||||
|
||||
## 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.
|
||||
|
||||
If you're integrating Jenkins with many GitLab projects, consider granting the user global
|
||||
Administrator permission. Otherwise, add the user to each project, and grant the Developer role.
|
||||
If you're integrating Jenkins with many GitLab projects, consider granting the user the global
|
||||
Administrator role. Otherwise, add the user to each project, and grant the Developer role.
|
||||
|
||||
## 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
|
||||
---
|
||||
|
||||
# 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
|
||||
authentication service provider.
|
||||
This document describes how you can use GitLab as an OAuth 2.0 authentication identity provider.
|
||||
|
||||
If you want to use:
|
||||
|
||||
- The [OAuth 2.0](https://oauth.net/2/) protocol to access GitLab resources on
|
||||
a user's behalf, see [OAuth 2.0 provider](../api/oauth2.md).
|
||||
- Other OAuth 2.0 authentication service providers to sign in to
|
||||
GitLab, see the [OAuth 2.0 client documentation](omniauth.md).
|
||||
- The related API, see [Applications API](../api/applications.md).
|
||||
- OAuth 2 applications can be created and managed using the GitLab UI (described below)
|
||||
or managed using the [Applications API](../api/applications.md).
|
||||
- After an application is created, external services can manage access tokens using the
|
||||
[OAuth 2 API](../api/oauth2.md).
|
||||
- To allow users to sign in to GitLab using third-party OAuth 2 providers, see
|
||||
[OmniAuth documentation](omniauth.md).
|
||||
|
||||
## 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 left sidebar, select **Monitor > On-call Schedules**.
|
||||
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**.
|
||||
|
||||
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)
|
||||
- [Project access tokens](../../api/index.md#personalproject-access-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
|
||||
|
||||
|
|
|
@ -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
|
||||
your [subscription](https://about.gitlab.com/pricing/)
|
||||
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.
|
||||
|
||||
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).
|
||||
|
||||
|
@ -78,7 +78,7 @@ There are several types of users in GitLab:
|
|||
|
||||
- Regular users and GitLab.com users. <!-- Note: further description TBA -->
|
||||
- [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
|
||||
self-managed instances' features and settings.
|
||||
- [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
|
||||
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. When [installing JupyterHub with Helm](https://zero-to-jupyterhub.readthedocs.io/en/latest/jupyterhub/installation.html), use the following values
|
||||
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:
|
||||
|
||||
```yaml
|
||||
#-----------------------------------------------------------------------------
|
||||
|
|
|
@ -61,6 +61,7 @@ module Gitlab
|
|||
def self.databases
|
||||
@databases ||= database_base_models
|
||||
.transform_values { |connection_class| Connection.new(connection_class) }
|
||||
.with_indifferent_access
|
||||
.freeze
|
||||
end
|
||||
|
||||
|
|
|
@ -116,7 +116,7 @@ module Gitlab
|
|||
def record_apdex_if_needed(elapsed)
|
||||
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,
|
||||
# hardcoded 1s here will be replaced by a per-endpoint value.
|
||||
# https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/1223
|
||||
|
|
|
@ -64,9 +64,9 @@ module Gitlab
|
|||
|
||||
Sidekiq.redis do |redis|
|
||||
redis.multi do |multi|
|
||||
redis.set(idempotency_key, jid, ex: expiry, nx: true)
|
||||
read_wal_locations = check_existing_wal_locations!(redis, expiry)
|
||||
read_jid = redis.get(idempotency_key)
|
||||
multi.set(idempotency_key, jid, ex: expiry, nx: true)
|
||||
read_wal_locations = check_existing_wal_locations!(multi, expiry)
|
||||
read_jid = multi.get(idempotency_key)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -81,9 +81,9 @@ module Gitlab
|
|||
return unless job_wal_locations.present?
|
||||
|
||||
Sidekiq.redis do |redis|
|
||||
redis.multi do
|
||||
redis.multi do |multi|
|
||||
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
|
||||
|
@ -96,9 +96,9 @@ module Gitlab
|
|||
read_wal_locations = {}
|
||||
|
||||
Sidekiq.redis do |redis|
|
||||
redis.multi do
|
||||
redis.multi do |multi|
|
||||
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
|
||||
|
@ -110,8 +110,8 @@ module Gitlab
|
|||
def delete!
|
||||
Sidekiq.redis do |redis|
|
||||
redis.multi do |multi|
|
||||
redis.del(idempotency_key)
|
||||
delete_wal_locations!(redis)
|
||||
multi.del(idempotency_key)
|
||||
delete_wal_locations!(multi)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -147,7 +147,7 @@ module Gitlab
|
|||
|
||||
private
|
||||
|
||||
attr_accessor :existing_wal_locations
|
||||
attr_writer :existing_wal_locations
|
||||
attr_reader :queue_name, :job
|
||||
attr_writer :existing_jid
|
||||
|
||||
|
@ -155,6 +155,31 @@ module Gitlab
|
|||
@worker_klass ||= worker_class_name.to_s.safe_constantize
|
||||
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)
|
||||
Gitlab::Database.databases[connection_name].pg_wal_lsn_diff(job_wal_locations[connection_name], existing_wal_locations[connection_name])
|
||||
end
|
||||
|
@ -179,12 +204,6 @@ module Gitlab
|
|||
job['jid']
|
||||
end
|
||||
|
||||
def job_wal_locations
|
||||
return {} unless preserve_wal_location?
|
||||
|
||||
job['wal_locations'] || {}
|
||||
end
|
||||
|
||||
def existing_wal_location_key(connection_name)
|
||||
"#{idempotency_key}:#{connection_name}:existing_wal_location"
|
||||
end
|
||||
|
@ -209,23 +228,8 @@ module Gitlab
|
|||
"#{worker_class_name}:#{Sidekiq.dump_json(arguments)}"
|
||||
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
|
||||
def existing_wal_locations
|
||||
@existing_wal_locations ||= {}
|
||||
end
|
||||
|
||||
def preserve_wal_location?
|
||||
|
|
|
@ -4,11 +4,15 @@ module Gitlab
|
|||
module SidekiqMiddleware
|
||||
module DuplicateJobs
|
||||
module Strategies
|
||||
module DeduplicatesWhenScheduling
|
||||
class DeduplicatesWhenScheduling < Base
|
||||
extend ::Gitlab::Utils::Override
|
||||
|
||||
override :initialize
|
||||
def initialize(duplicate_job)
|
||||
@duplicate_job = duplicate_job
|
||||
end
|
||||
|
||||
override :schedule
|
||||
def schedule(job)
|
||||
if deduplicatable_job? && check! && duplicate_job.duplicate?
|
||||
job['duplicate-of'] = duplicate_job.existing_jid
|
||||
|
@ -25,6 +29,7 @@ module Gitlab
|
|||
yield
|
||||
end
|
||||
|
||||
override :perform
|
||||
def perform(job)
|
||||
update_job_wal_location!(job)
|
||||
end
|
||||
|
|
|
@ -7,11 +7,7 @@ module Gitlab
|
|||
# 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
|
||||
# while a job is still executing.
|
||||
class UntilExecuted < Base
|
||||
extend ::Gitlab::Utils::Override
|
||||
|
||||
include DeduplicatesWhenScheduling
|
||||
|
||||
class UntilExecuted < DeduplicatesWhenScheduling
|
||||
override :perform
|
||||
def perform(job)
|
||||
super
|
||||
|
|
|
@ -7,11 +7,7 @@ module Gitlab
|
|||
# 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
|
||||
# while a job is still executing.
|
||||
class UntilExecuting < Base
|
||||
extend ::Gitlab::Utils::Override
|
||||
|
||||
include DeduplicatesWhenScheduling
|
||||
|
||||
class UntilExecuting < DeduplicatesWhenScheduling
|
||||
override :perform
|
||||
def perform(job)
|
||||
super
|
||||
|
|
|
@ -968,11 +968,6 @@ msgstr ""
|
|||
msgid "%{template_project_id} is unknown or invalid"
|
||||
msgstr ""
|
||||
|
||||
msgid "%{text} %{files}"
|
||||
msgid_plural "%{text} %{files} files"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
msgid "%{text} is available"
|
||||
msgstr ""
|
||||
|
||||
|
@ -24460,6 +24455,9 @@ msgstr ""
|
|||
msgid "Paste project path (i.e. gitlab-org/gitlab)"
|
||||
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."
|
||||
msgstr ""
|
||||
|
||||
|
@ -39997,6 +39995,9 @@ msgid_plural "from %d jobs"
|
|||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
msgid "frontmatter"
|
||||
msgstr ""
|
||||
|
||||
msgid "group"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -183,7 +183,7 @@ module QA
|
|||
another_project.remove_via_api!
|
||||
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|
|
||||
commit.project = project
|
||||
commit.commit_message = 'Add .gitlab-ci.yml'
|
||||
|
@ -256,7 +256,7 @@ module QA
|
|||
Page::Group::Settings::PackageRegistries.perform(&:set_allow_duplicates_disabled)
|
||||
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|
|
||||
Service::DockerRun::Maven.new(dir).publish!
|
||||
end
|
||||
|
@ -301,7 +301,7 @@ module QA
|
|||
Page::Group::Settings::PackageRegistries.perform(&:set_allow_duplicates_enabled)
|
||||
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|
|
||||
Service::DockerRun::Maven.new(dir).publish!
|
||||
end
|
||||
|
|
|
@ -2,36 +2,276 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
def visit_jobs_page
|
||||
visit(project_jobs_path(project))
|
||||
|
||||
wait_for_requests
|
||||
end
|
||||
|
||||
RSpec.describe 'User browses jobs' do
|
||||
let!(:build) { create(:ci_build, :coverage, pipeline: pipeline) }
|
||||
let(:pipeline) { create(:ci_empty_pipeline, project: project, sha: project.commit.sha, ref: 'master') }
|
||||
let(:project) { create(:project, :repository, namespace: user.namespace) }
|
||||
let(:user) { create(:user) }
|
||||
describe 'with jobs_table_vue feature flag turned off' do
|
||||
let!(:build) { create(:ci_build, :coverage, pipeline: pipeline) }
|
||||
let(:pipeline) { create(:ci_empty_pipeline, project: project, sha: project.commit.sha, ref: 'master') }
|
||||
let(:project) { create(:project, :repository, namespace: user.namespace) }
|
||||
let(:user) { create(:user) }
|
||||
|
||||
before do
|
||||
stub_feature_flags(jobs_table_vue: false)
|
||||
project.add_maintainer(user)
|
||||
project.enable_ci
|
||||
project.update_attribute(:build_coverage_regex, /Coverage (\d+)%/)
|
||||
before do
|
||||
stub_feature_flags(jobs_table_vue: false)
|
||||
project.add_maintainer(user)
|
||||
project.enable_ci
|
||||
project.update_attribute(:build_coverage_regex, /Coverage (\d+)%/)
|
||||
|
||||
sign_in(user)
|
||||
sign_in(user)
|
||||
|
||||
visit(project_jobs_path(project))
|
||||
end
|
||||
visit(project_jobs_path(project))
|
||||
end
|
||||
|
||||
it 'shows the coverage' do
|
||||
page.within('td.coverage') do
|
||||
expect(page).to have_content('99.9%')
|
||||
it 'shows the coverage' do
|
||||
page.within('td.coverage') do
|
||||
expect(page).to have_content('99.9%')
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a failed job' do
|
||||
let!(:build) { create(:ci_build, :coverage, :failed, pipeline: pipeline) }
|
||||
|
||||
it 'displays a tooltip with the failure reason' do
|
||||
page.within('.ci-table') do
|
||||
failed_job_link = page.find('.ci-failed')
|
||||
expect(failed_job_link[:title]).to eq('Failed - (unknown failure)')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a failed job' do
|
||||
let!(:build) { create(:ci_build, :coverage, :failed, pipeline: pipeline) }
|
||||
describe 'with jobs_table_vue feature flag turned on', :js do
|
||||
let(:project) { create(:project, :repository) }
|
||||
let(:user) { create(:user) }
|
||||
|
||||
it 'displays a tooltip with the failure reason' do
|
||||
page.within('.ci-table') do
|
||||
failed_job_link = page.find('.ci-failed')
|
||||
expect(failed_job_link[:title]).to eq('Failed - (unknown failure)')
|
||||
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
|
||||
|
|
|
@ -175,6 +175,12 @@ RSpec.describe 'Projects > Settings > For a forked project', :js do
|
|||
wait_for_requests
|
||||
|
||||
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
|
||||
|
|
|
@ -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 { nextTick } from 'vue';
|
||||
import Vuex from 'vuex';
|
||||
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
|
||||
import { TEST_HOST } from 'helpers/test_constants';
|
||||
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
|
||||
import ErrorTrackingSettings from '~/error_tracking_settings/components/app.vue';
|
||||
|
@ -12,6 +13,8 @@ import createStore from '~/error_tracking_settings/store';
|
|||
const localVue = createLocalVue();
|
||||
localVue.use(Vuex);
|
||||
|
||||
const TEST_GITLAB_DSN = 'https://gitlab.example.com/123456';
|
||||
|
||||
describe('error tracking settings app', () => {
|
||||
let store;
|
||||
let wrapper;
|
||||
|
@ -29,6 +32,10 @@ describe('error tracking settings app', () => {
|
|||
initialProject: null,
|
||||
listProjectsEndpoint: 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);
|
||||
const findElementWithText = (wrappers, text) => wrappers.filter((item) => item.text() === text);
|
||||
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(() => {
|
||||
store = createStore();
|
||||
|
@ -93,17 +106,35 @@ describe('error tracking settings app', () => {
|
|||
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);
|
||||
|
||||
// set the "integrated" setting to "true"
|
||||
findBackendSettingsRadioGroup().vm.$emit('change', true);
|
||||
|
||||
await nextTick();
|
||||
await enableGitLabErrorTracking();
|
||||
|
||||
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])(
|
||||
'calls the `updateIntegrated` action when the setting changes to `%s`',
|
||||
(integrated) => {
|
||||
|
|
|
@ -219,3 +219,22 @@
|
|||
# Sit amit
|
||||
|
||||
### 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(
|
||||
'Update test-file, index.js files',
|
||||
'Update test-file, index.js',
|
||||
);
|
||||
});
|
||||
|
||||
|
|
|
@ -15,6 +15,13 @@ RSpec.describe Gitlab::Database do
|
|||
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
|
||||
before do
|
||||
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
|
||||
|
||||
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
|
||||
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) }
|
||||
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
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe NamespacePolicy do
|
||||
RSpec.describe Namespaces::UserNamespacePolicy do
|
||||
let(:user) { create(:user) }
|
||||
let(:owner) { create(:user) }
|
||||
let(:admin) { create(:admin) }
|
|
@ -277,15 +277,15 @@ RSpec.describe Ci::RetryBuildService do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#reprocess' do
|
||||
describe '#clone!' do
|
||||
let(:new_build) do
|
||||
travel_to(1.second.from_now) do
|
||||
service.reprocess!(build)
|
||||
service.clone!(build)
|
||||
end
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
context 'when user has ability to execute build' do
|
||||
|
@ -343,7 +343,7 @@ RSpec.describe Ci::RetryBuildService do
|
|||
let(:user) { reporter }
|
||||
|
||||
it 'raises an error' do
|
||||
expect { service.reprocess!(build) }
|
||||
expect { service.clone!(build) }
|
||||
.to raise_error Gitlab::Access::AccessDeniedError
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue