Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
576bba90f9
commit
cd5179ede2
|
@ -42,7 +42,7 @@ import {
|
||||||
import diffsEventHub from '../event_hub';
|
import diffsEventHub from '../event_hub';
|
||||||
import { reviewStatuses } from '../utils/file_reviews';
|
import { reviewStatuses } from '../utils/file_reviews';
|
||||||
import { diffsApp } from '../utils/performance';
|
import { diffsApp } from '../utils/performance';
|
||||||
import { updateChangesTabCount } from '../utils/merge_request';
|
import { updateChangesTabCount, extractFileHash } from '../utils/merge_request';
|
||||||
import { queueRedisHllEvents } from '../utils/queue_events';
|
import { queueRedisHllEvents } from '../utils/queue_events';
|
||||||
import FindingsDrawer from './shared/findings_drawer.vue';
|
import FindingsDrawer from './shared/findings_drawer.vue';
|
||||||
import CollapsedFilesWarning from './collapsed_files_warning.vue';
|
import CollapsedFilesWarning from './collapsed_files_warning.vue';
|
||||||
|
@ -344,12 +344,13 @@ export default {
|
||||||
...mapActions(['startTaskList']),
|
...mapActions(['startTaskList']),
|
||||||
...mapActions('diffs', [
|
...mapActions('diffs', [
|
||||||
'moveToNeighboringCommit',
|
'moveToNeighboringCommit',
|
||||||
'setBaseConfig',
|
|
||||||
'setCodequalityEndpoint',
|
'setCodequalityEndpoint',
|
||||||
'setSastEndpoint',
|
'setSastEndpoint',
|
||||||
'fetchDiffFilesMeta',
|
'fetchDiffFilesMeta',
|
||||||
'fetchDiffFilesBatch',
|
'fetchDiffFilesBatch',
|
||||||
'fetchFileByFile',
|
'fetchFileByFile',
|
||||||
|
'loadCollapsedDiff',
|
||||||
|
'setFileForcedOpen',
|
||||||
'fetchCoverageFiles',
|
'fetchCoverageFiles',
|
||||||
'fetchCodequality',
|
'fetchCodequality',
|
||||||
'fetchSast',
|
'fetchSast',
|
||||||
|
@ -373,15 +374,34 @@ export default {
|
||||||
notesEventHub.$on('refetchDiffData', this.refetchDiffData);
|
notesEventHub.$on('refetchDiffData', this.refetchDiffData);
|
||||||
notesEventHub.$on('fetchedNotesData', this.rereadNoteHash);
|
notesEventHub.$on('fetchedNotesData', this.rereadNoteHash);
|
||||||
diffsEventHub.$on('diffFilesModified', this.setDiscussions);
|
diffsEventHub.$on('diffFilesModified', this.setDiscussions);
|
||||||
|
diffsEventHub.$on('doneLoadingBatches', this.autoScroll);
|
||||||
diffsEventHub.$on(EVT_MR_PREPARED, this.fetchData);
|
diffsEventHub.$on(EVT_MR_PREPARED, this.fetchData);
|
||||||
},
|
},
|
||||||
unsubscribeFromEvents() {
|
unsubscribeFromEvents() {
|
||||||
diffsEventHub.$off(EVT_MR_PREPARED, this.fetchData);
|
diffsEventHub.$off(EVT_MR_PREPARED, this.fetchData);
|
||||||
|
diffsEventHub.$off('doneLoadingBatches', this.autoScroll);
|
||||||
diffsEventHub.$off('diffFilesModified', this.setDiscussions);
|
diffsEventHub.$off('diffFilesModified', this.setDiscussions);
|
||||||
notesEventHub.$off('fetchedNotesData', this.rereadNoteHash);
|
notesEventHub.$off('fetchedNotesData', this.rereadNoteHash);
|
||||||
notesEventHub.$off('refetchDiffData', this.refetchDiffData);
|
notesEventHub.$off('refetchDiffData', this.refetchDiffData);
|
||||||
notesEventHub.$off('fetchDiffData', this.fetchData);
|
notesEventHub.$off('fetchDiffData', this.fetchData);
|
||||||
},
|
},
|
||||||
|
autoScroll() {
|
||||||
|
const lineCode = window.location.hash;
|
||||||
|
const sha1InHash = extractFileHash({ input: lineCode });
|
||||||
|
|
||||||
|
if (sha1InHash) {
|
||||||
|
const idx = this.diffs.findIndex((diffFile) => diffFile.file_hash === sha1InHash);
|
||||||
|
const file = this.diffs[idx];
|
||||||
|
|
||||||
|
this.loadCollapsedDiff({ file })
|
||||||
|
.then(() => {
|
||||||
|
this.setDiscussions();
|
||||||
|
this.scrollVirtualScrollerToIndex(idx);
|
||||||
|
this.setFileForcedOpen({ filePath: file.new_path });
|
||||||
|
})
|
||||||
|
.catch(() => {});
|
||||||
|
}
|
||||||
|
},
|
||||||
navigateToDiffFileNumber(number) {
|
navigateToDiffFileNumber(number) {
|
||||||
this.navigateToDiffFileIndex(number - 1);
|
this.navigateToDiffFileIndex(number - 1);
|
||||||
},
|
},
|
||||||
|
|
|
@ -161,6 +161,9 @@ export default {
|
||||||
manuallyCollapsed() {
|
manuallyCollapsed() {
|
||||||
return collapsedType(this.file) === DIFF_FILE_MANUAL_COLLAPSE;
|
return collapsedType(this.file) === DIFF_FILE_MANUAL_COLLAPSE;
|
||||||
},
|
},
|
||||||
|
forcedOpen() {
|
||||||
|
return this.file.viewer.forceOpen;
|
||||||
|
},
|
||||||
showBody() {
|
showBody() {
|
||||||
return !this.isCollapsed || this.automaticallyCollapsed;
|
return !this.isCollapsed || this.automaticallyCollapsed;
|
||||||
},
|
},
|
||||||
|
@ -174,6 +177,10 @@ export default {
|
||||||
return Boolean(gon.current_user_id);
|
return Boolean(gon.current_user_id);
|
||||||
},
|
},
|
||||||
isCollapsed() {
|
isCollapsed() {
|
||||||
|
if (this.forcedOpen) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (collapsedType(this.file) !== DIFF_FILE_MANUAL_COLLAPSE) {
|
if (collapsedType(this.file) !== DIFF_FILE_MANUAL_COLLAPSE) {
|
||||||
return this.viewDiffsFileByFile ? false : this.file.viewer?.automaticallyCollapsed;
|
return this.viewDiffsFileByFile ? false : this.file.viewer?.automaticallyCollapsed;
|
||||||
}
|
}
|
||||||
|
@ -201,6 +208,11 @@ export default {
|
||||||
this.manageViewedEffects();
|
this.manageViewedEffects();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
'file.viewer.forceOpen': {
|
||||||
|
handler: function fileForcedOpenHandler() {
|
||||||
|
this.handleToggle();
|
||||||
|
},
|
||||||
|
},
|
||||||
'file.file_hash': {
|
'file.file_hash': {
|
||||||
handler: function hashChangeWatch(newHash, oldHash) {
|
handler: function hashChangeWatch(newHash, oldHash) {
|
||||||
if (
|
if (
|
||||||
|
|
|
@ -232,10 +232,15 @@ export default {
|
||||||
'setCurrentFileHash',
|
'setCurrentFileHash',
|
||||||
'reviewFile',
|
'reviewFile',
|
||||||
'setFileCollapsedByUser',
|
'setFileCollapsedByUser',
|
||||||
|
'setFileForcedOpen',
|
||||||
'setGenerateTestFilePath',
|
'setGenerateTestFilePath',
|
||||||
'toggleFileCommentForm',
|
'toggleFileCommentForm',
|
||||||
]),
|
]),
|
||||||
handleToggleFile() {
|
handleToggleFile() {
|
||||||
|
this.setFileForcedOpen({
|
||||||
|
filePath: this.diffFile.file_path,
|
||||||
|
forced: false,
|
||||||
|
});
|
||||||
this.$emit('toggleFile');
|
this.$emit('toggleFile');
|
||||||
},
|
},
|
||||||
showForkMessage(e) {
|
showForkMessage(e) {
|
||||||
|
@ -278,6 +283,10 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((open && reviewed) || (closed && !reviewed)) {
|
if ((open && reviewed) || (closed && !reviewed)) {
|
||||||
|
this.setFileForcedOpen({
|
||||||
|
filePath: this.diffFile.file_path,
|
||||||
|
forced: false,
|
||||||
|
});
|
||||||
this.$emit('toggleFile');
|
this.$emit('toggleFile');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -254,6 +254,7 @@ export const fetchDiffFilesBatch = ({ commit, state, dispatch }) => {
|
||||||
|
|
||||||
if (totalLoaded === pagination.total_pages || pagination.total_pages === null) {
|
if (totalLoaded === pagination.total_pages || pagination.total_pages === null) {
|
||||||
commit(types.SET_RETRIEVING_BATCHES, false);
|
commit(types.SET_RETRIEVING_BATCHES, false);
|
||||||
|
eventHub.$emit('doneLoadingBatches');
|
||||||
|
|
||||||
// We need to check that the currentDiffFileId points to a file that exists
|
// We need to check that the currentDiffFileId points to a file that exists
|
||||||
if (
|
if (
|
||||||
|
@ -879,6 +880,7 @@ export function switchToFullDiffFromRenamedFile({ commit }, { diffFile }) {
|
||||||
...diffFile.alternate_viewer,
|
...diffFile.alternate_viewer,
|
||||||
automaticallyCollapsed: false,
|
automaticallyCollapsed: false,
|
||||||
manuallyCollapsed: false,
|
manuallyCollapsed: false,
|
||||||
|
forceOpen: false,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
commit(types.SET_CURRENT_VIEW_DIFF_FILE_LINES, { filePath: diffFile.file_path, lines });
|
commit(types.SET_CURRENT_VIEW_DIFF_FILE_LINES, { filePath: diffFile.file_path, lines });
|
||||||
|
@ -893,6 +895,10 @@ export const setFileCollapsedAutomatically = ({ commit }, { filePath, collapsed
|
||||||
commit(types.SET_FILE_COLLAPSED, { filePath, collapsed, trigger: DIFF_FILE_AUTOMATIC_COLLAPSE });
|
commit(types.SET_FILE_COLLAPSED, { filePath, collapsed, trigger: DIFF_FILE_AUTOMATIC_COLLAPSE });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export function setFileForcedOpen({ commit }, { filePath, forced }) {
|
||||||
|
commit(types.SET_FILE_FORCED_OPEN, { filePath, forced });
|
||||||
|
}
|
||||||
|
|
||||||
export const setSuggestPopoverDismissed = ({ commit, state }) =>
|
export const setSuggestPopoverDismissed = ({ commit, state }) =>
|
||||||
axios
|
axios
|
||||||
.post(state.dismissEndpoint, {
|
.post(state.dismissEndpoint, {
|
||||||
|
|
|
@ -39,6 +39,7 @@ export const REQUEST_FULL_DIFF = 'REQUEST_FULL_DIFF';
|
||||||
export const RECEIVE_FULL_DIFF_SUCCESS = 'RECEIVE_FULL_DIFF_SUCCESS';
|
export const RECEIVE_FULL_DIFF_SUCCESS = 'RECEIVE_FULL_DIFF_SUCCESS';
|
||||||
export const RECEIVE_FULL_DIFF_ERROR = 'RECEIVE_FULL_DIFF_ERROR';
|
export const RECEIVE_FULL_DIFF_ERROR = 'RECEIVE_FULL_DIFF_ERROR';
|
||||||
export const SET_FILE_COLLAPSED = 'SET_FILE_COLLAPSED';
|
export const SET_FILE_COLLAPSED = 'SET_FILE_COLLAPSED';
|
||||||
|
export const SET_FILE_FORCED_OPEN = 'SET_FILE_FORCED_OPEN';
|
||||||
|
|
||||||
export const SET_CURRENT_VIEW_DIFF_FILE_LINES = 'SET_CURRENT_VIEW_DIFF_FILE_LINES';
|
export const SET_CURRENT_VIEW_DIFF_FILE_LINES = 'SET_CURRENT_VIEW_DIFF_FILE_LINES';
|
||||||
export const ADD_CURRENT_VIEW_DIFF_FILE_LINES = 'ADD_CURRENT_VIEW_DIFF_FILE_LINES';
|
export const ADD_CURRENT_VIEW_DIFF_FILE_LINES = 'ADD_CURRENT_VIEW_DIFF_FILE_LINES';
|
||||||
|
|
|
@ -349,6 +349,11 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
[types.SET_FILE_FORCED_OPEN](state, { filePath, forced = true }) {
|
||||||
|
const file = state.diffFiles.find((f) => f.file_path === filePath);
|
||||||
|
|
||||||
|
Vue.set(file.viewer, 'forceOpen', forced);
|
||||||
|
},
|
||||||
[types.SET_CURRENT_VIEW_DIFF_FILE_LINES](state, { filePath, lines }) {
|
[types.SET_CURRENT_VIEW_DIFF_FILE_LINES](state, { filePath, lines }) {
|
||||||
const file = state.diffFiles.find((f) => f.file_path === filePath);
|
const file = state.diffFiles.find((f) => f.file_path === filePath);
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,7 @@ function collapsed(file) {
|
||||||
return {
|
return {
|
||||||
automaticallyCollapsed: viewer.automaticallyCollapsed || viewer.collapsed || false,
|
automaticallyCollapsed: viewer.automaticallyCollapsed || viewer.collapsed || false,
|
||||||
manuallyCollapsed: null,
|
manuallyCollapsed: null,
|
||||||
|
forceOpen: false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { ZERO_CHANGES_ALT_DISPLAY } from '../constants';
|
import { ZERO_CHANGES_ALT_DISPLAY } from '../constants';
|
||||||
|
|
||||||
const endpointRE = /^(\/?(.+\/)+(.+)\/-\/merge_requests\/(\d+)).*$/i;
|
const endpointRE = /^(\/?(.+\/)+(.+)\/-\/merge_requests\/(\d+)).*$/i;
|
||||||
|
const SHA1RE = /([a-f0-9]{40})/g;
|
||||||
|
|
||||||
function getVersionInfo({ endpoint } = {}) {
|
function getVersionInfo({ endpoint } = {}) {
|
||||||
const dummyRoot = 'https://gitlab.com';
|
const dummyRoot = 'https://gitlab.com';
|
||||||
|
@ -51,3 +52,9 @@ export function getDerivedMergeRequestInformation({ endpoint } = {}) {
|
||||||
startSha,
|
startSha,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function extractFileHash({ input = '' } = {}) {
|
||||||
|
const matches = input.match(SHA1RE);
|
||||||
|
|
||||||
|
return matches?.[0];
|
||||||
|
}
|
||||||
|
|
|
@ -112,6 +112,7 @@ export default {
|
||||||
<template>
|
<template>
|
||||||
<gl-tabs
|
<gl-tabs
|
||||||
v-model="selectedTabIndex"
|
v-model="selectedTabIndex"
|
||||||
|
content-class="gl-py-0"
|
||||||
sync-active-tab-with-query-params
|
sync-active-tab-with-query-params
|
||||||
:query-param-name="$options.ACTIVE_TAB_QUERY_PARAM_NAME"
|
:query-param-name="$options.ACTIVE_TAB_QUERY_PARAM_NAME"
|
||||||
>
|
>
|
||||||
|
|
|
@ -63,6 +63,6 @@ class Admin::IdentitiesController < Admin::ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def identity_params
|
def identity_params
|
||||||
params.require(:identity).permit(:provider, :extern_uid)
|
params.require(:identity).permit(:provider, :extern_uid, :saml_provider_id)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module SidekiqHelper
|
|
||||||
SIDEKIQ_PS_REGEXP = %r{\A
|
|
||||||
(?<pid>\d+)\s+
|
|
||||||
(?<cpu>[\d\.,]+)\s+
|
|
||||||
(?<mem>[\d\.,]+)\s+
|
|
||||||
(?<state>[DIEKNRSTVWXZLpsl\+<>/\d]+)\s+
|
|
||||||
(?<start>.+?)\s+
|
|
||||||
(?<command>(?:ruby\d+:\s+)?sidekiq.*\].*)
|
|
||||||
\z}x
|
|
||||||
|
|
||||||
def parse_sidekiq_ps(line)
|
|
||||||
match = line.strip.match(SIDEKIQ_PS_REGEXP)
|
|
||||||
match ? match[1..6] : Array.new(6, '?')
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -64,15 +64,6 @@ module SortingHelper
|
||||||
options
|
options
|
||||||
end
|
end
|
||||||
|
|
||||||
def forks_sort_options_hash
|
|
||||||
{
|
|
||||||
sort_value_recently_created => sort_title_created_date,
|
|
||||||
sort_value_oldest_created => sort_title_created_date,
|
|
||||||
sort_value_latest_activity => sort_title_latest_activity,
|
|
||||||
sort_value_oldest_activity => sort_title_latest_activity
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
def forks_reverse_sort_options_hash
|
def forks_reverse_sort_options_hash
|
||||||
{
|
{
|
||||||
sort_value_recently_created => sort_value_oldest_created,
|
sort_value_recently_created => sort_value_oldest_created,
|
||||||
|
@ -93,12 +84,6 @@ module SortingHelper
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
def subgroups_sort_options_hash
|
|
||||||
groups_sort_options_hash.merge(
|
|
||||||
sort_value_stars_desc => sort_title_most_stars
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
def admin_groups_sort_options_hash
|
def admin_groups_sort_options_hash
|
||||||
groups_sort_options_hash.merge(
|
groups_sort_options_hash.merge(
|
||||||
sort_value_largest_group => sort_title_largest_group
|
sort_value_largest_group => sort_title_largest_group
|
||||||
|
@ -199,19 +184,6 @@ module SortingHelper
|
||||||
}.merge(issuable_sort_option_overrides)
|
}.merge(issuable_sort_option_overrides)
|
||||||
end
|
end
|
||||||
|
|
||||||
def audit_logs_sort_order_hash
|
|
||||||
{
|
|
||||||
sort_value_recently_created => sort_title_recently_created,
|
|
||||||
sort_value_oldest_created => sort_title_oldest_created
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
def issuable_sort_option_title(sort_value)
|
|
||||||
sort_value = issuable_sort_option_overrides[sort_value] || sort_value
|
|
||||||
|
|
||||||
sort_options_hash[sort_value]
|
|
||||||
end
|
|
||||||
|
|
||||||
def issuable_sort_options(viewing_issues, viewing_merge_requests)
|
def issuable_sort_options(viewing_issues, viewing_merge_requests)
|
||||||
options = [
|
options = [
|
||||||
{ value: sort_value_priority, text: sort_title_priority, href: page_filter_path(sort: sort_value_priority) },
|
{ value: sort_value_priority, text: sort_title_priority, href: page_filter_path(sort: sort_value_priority) },
|
||||||
|
@ -321,17 +293,6 @@ module SortingHelper
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
def packages_sort_option_title(sort_value)
|
|
||||||
packages_sort_options_hash[sort_value] || sort_title_created_date
|
|
||||||
end
|
|
||||||
|
|
||||||
def packages_sort_direction_button(sort_value)
|
|
||||||
reverse_sort = packages_reverse_sort_order_hash[sort_value]
|
|
||||||
url = package_sort_path(sort: reverse_sort)
|
|
||||||
|
|
||||||
sort_direction_button(url, reverse_sort, sort_value)
|
|
||||||
end
|
|
||||||
|
|
||||||
def forks_sort_direction_button(sort_value, without = [:state, :scope, :label_name, :milestone_id, :assignee_id, :author_id])
|
def forks_sort_direction_button(sort_value, without = [:state, :scope, :label_name, :milestone_id, :assignee_id, :author_id])
|
||||||
reverse_sort = forks_reverse_sort_options_hash[sort_value]
|
reverse_sort = forks_reverse_sort_options_hash[sort_value]
|
||||||
url = page_filter_path(sort: reverse_sort, without: without)
|
url = page_filter_path(sort: reverse_sort, without: without)
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
.col-sm-10
|
.col-sm-10
|
||||||
- values = Gitlab::Auth::OAuth::Provider.providers.map { |name| ["#{Gitlab::Auth::OAuth::Provider.label_for(name)} (#{name})", name] }
|
- values = Gitlab::Auth::OAuth::Provider.providers.map { |name| ["#{Gitlab::Auth::OAuth::Provider.label_for(name)} (#{name})", name] }
|
||||||
= f.select :provider, values, { allow_blank: false }, class: 'form-control'
|
= f.select :provider, values, { allow_blank: false }, class: 'form-control'
|
||||||
|
= render_if_exists partial: 'admin/identities/provider_id', locals: { f: f }
|
||||||
.form-group.row
|
.form-group.row
|
||||||
.col-sm-2.col-form-label
|
.col-sm-2.col-form-label
|
||||||
= f.label :extern_uid, _("Identifier")
|
= f.label :extern_uid, _("Identifier")
|
||||||
|
@ -15,4 +16,3 @@
|
||||||
|
|
||||||
.form-actions
|
.form-actions
|
||||||
= f.submit _('Save changes'), pajamas_button: true
|
= f.submit _('Save changes'), pajamas_button: true
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
---
|
||||||
|
name: use_embeddings_with_vertex
|
||||||
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/130421
|
||||||
|
rollout_issue_url:
|
||||||
|
milestone: '16.5'
|
||||||
|
type: development
|
||||||
|
group: group::duo chat
|
||||||
|
default_enabled: false
|
|
@ -135,8 +135,8 @@ The following metrics are available:
|
||||||
| `gitlab_issuable_fast_count_by_state_total` | Counter | 13.5 | Total number of row count operations on issue/merge request list pages | |
|
| `gitlab_issuable_fast_count_by_state_total` | Counter | 13.5 | Total number of row count operations on issue/merge request list pages | |
|
||||||
| `gitlab_issuable_fast_count_by_state_failures_total` | Counter | 13.5 | Number of soft-failed row count operations on issue/merge request list pages | |
|
| `gitlab_issuable_fast_count_by_state_failures_total` | Counter | 13.5 | Number of soft-failed row count operations on issue/merge request list pages | |
|
||||||
| `gitlab_ci_trace_finalize_duration_seconds` | Histogram | 13.6 | Duration of build trace chunks migration to object storage | |
|
| `gitlab_ci_trace_finalize_duration_seconds` | Histogram | 13.6 | Duration of build trace chunks migration to object storage | |
|
||||||
| `gitlab_vulnerability_report_branch_comparison_real_duration_seconds` | Histogram | 15.11 | Execution duration of vulnerability report present on default branch sql query | |
|
| `gitlab_vulnerability_report_branch_comparison_real_duration_seconds` | Histogram | 15.11 | Execution duration of vulnerability report present on default branch SQL query | |
|
||||||
| `gitlab_vulnerability_report_branch_comparison_cpu_duration_seconds` | Histogram | 15.11 | Execution duration of vulnerability report present on default branch sql query | |
|
| `gitlab_vulnerability_report_branch_comparison_cpu_duration_seconds` | Histogram | 15.11 | Execution duration of vulnerability report present on default branch SQL query | |
|
||||||
| `gitlab_external_http_total` | Counter | 13.8 | Total number of HTTP calls to external systems | `controller`, `action` |
|
| `gitlab_external_http_total` | Counter | 13.8 | Total number of HTTP calls to external systems | `controller`, `action` |
|
||||||
| `gitlab_external_http_duration_seconds` | Counter | 13.8 | Duration in seconds spent on each HTTP call to external systems | |
|
| `gitlab_external_http_duration_seconds` | Counter | 13.8 | Duration in seconds spent on each HTTP call to external systems | |
|
||||||
| `gitlab_external_http_exception_total` | Counter | 13.8 | Total number of exceptions raised when making external HTTP calls | |
|
| `gitlab_external_http_exception_total` | Counter | 13.8 | Total number of exceptions raised when making external HTTP calls | |
|
||||||
|
|
|
@ -833,7 +833,7 @@ to be used with GitLab. The following IPs will be used as an example:
|
||||||
|
|
||||||
You can optionally use a third party external service for Redis as long as it meets the [requirements](../../install/requirements.md#redis).
|
You can optionally use a third party external service for Redis as long as it meets the [requirements](../../install/requirements.md#redis).
|
||||||
|
|
||||||
A reputable provider or solution should be used for this. [Google Memorystore](https://cloud.google.com/memorystore/docs/redis/redis-overview) and [AWS Elasticache](https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/WhatIs.html) are known to work. However, note that the Redis Cluster mode specifically isn't supported by GitLab. See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information.
|
A reputable provider or solution should be used for this. [Google Memorystore](https://cloud.google.com/memorystore/docs/redis/redis-overview) and [AWS ElastiCache](https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/WhatIs.html) are known to work. However, note that the Redis Cluster mode specifically isn't supported by GitLab. See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information.
|
||||||
|
|
||||||
### Configure the Redis Cache cluster
|
### Configure the Redis Cache cluster
|
||||||
|
|
||||||
|
|
|
@ -850,7 +850,7 @@ to be used with GitLab. The following IPs will be used as an example:
|
||||||
|
|
||||||
You can optionally use a third party external service for Redis as long as it meets the [requirements](../../install/requirements.md#redis).
|
You can optionally use a third party external service for Redis as long as it meets the [requirements](../../install/requirements.md#redis).
|
||||||
|
|
||||||
A reputable provider or solution should be used for this. [Google Memorystore](https://cloud.google.com/memorystore/docs/redis/redis-overview) and [AWS Elasticache](https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/WhatIs.html) are known to work. However, note that the Redis Cluster mode specifically isn't supported by GitLab. See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information.
|
A reputable provider or solution should be used for this. [Google Memorystore](https://cloud.google.com/memorystore/docs/redis/redis-overview) and [AWS ElastiCache](https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/WhatIs.html) are known to work. However, note that the Redis Cluster mode specifically isn't supported by GitLab. See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information.
|
||||||
|
|
||||||
### Configure the Redis Cache cluster
|
### Configure the Redis Cache cluster
|
||||||
|
|
||||||
|
|
|
@ -334,7 +334,7 @@ to be used with GitLab.
|
||||||
|
|
||||||
You can optionally use a third party external service for Redis as long as it meets the [requirements](../../install/requirements.md#redis).
|
You can optionally use a third party external service for Redis as long as it meets the [requirements](../../install/requirements.md#redis).
|
||||||
|
|
||||||
A reputable provider or solution should be used for this. [Google Memorystore](https://cloud.google.com/memorystore/docs/redis/redis-overview) and [AWS Elasticache](https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/WhatIs.html) are known to work. However, note that the Redis Cluster mode specifically isn't supported by GitLab. See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information.
|
A reputable provider or solution should be used for this. [Google Memorystore](https://cloud.google.com/memorystore/docs/redis/redis-overview) and [AWS ElastiCache](https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/WhatIs.html) are known to work. However, note that the Redis Cluster mode specifically isn't supported by GitLab. See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information.
|
||||||
|
|
||||||
### Standalone Redis using the Linux package
|
### Standalone Redis using the Linux package
|
||||||
|
|
||||||
|
|
|
@ -450,7 +450,7 @@ to be used with GitLab. The following IPs will be used as an example:
|
||||||
|
|
||||||
You can optionally use a third party external service for Redis as long as it meets the [requirements](../../install/requirements.md#redis).
|
You can optionally use a third party external service for Redis as long as it meets the [requirements](../../install/requirements.md#redis).
|
||||||
|
|
||||||
A reputable provider or solution should be used for this. [Google Memorystore](https://cloud.google.com/memorystore/docs/redis/redis-overview) and [AWS Elasticache](https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/WhatIs.html) are known to work. However, note that the Redis Cluster mode specifically isn't supported by GitLab. See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information.
|
A reputable provider or solution should be used for this. [Google Memorystore](https://cloud.google.com/memorystore/docs/redis/redis-overview) and [AWS ElastiCache](https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/WhatIs.html) are known to work. However, note that the Redis Cluster mode specifically isn't supported by GitLab. See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information.
|
||||||
|
|
||||||
### Standalone Redis using the Linux package
|
### Standalone Redis using the Linux package
|
||||||
|
|
||||||
|
|
|
@ -843,7 +843,7 @@ to be used with GitLab. The following IPs will be used as an example:
|
||||||
|
|
||||||
You can optionally use a third party external service for Redis as long as it meets the [requirements](../../install/requirements.md#redis).
|
You can optionally use a third party external service for Redis as long as it meets the [requirements](../../install/requirements.md#redis).
|
||||||
|
|
||||||
A reputable provider or solution should be used for this. [Google Memorystore](https://cloud.google.com/memorystore/docs/redis/redis-overview) and [AWS Elasticache](https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/WhatIs.html) are known to work. However, note that the Redis Cluster mode specifically isn't supported by GitLab. See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information.
|
A reputable provider or solution should be used for this. [Google Memorystore](https://cloud.google.com/memorystore/docs/redis/redis-overview) and [AWS ElastiCache](https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/WhatIs.html) are known to work. However, note that the Redis Cluster mode specifically isn't supported by GitLab. See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information.
|
||||||
|
|
||||||
### Configure the Redis Cache cluster
|
### Configure the Redis Cache cluster
|
||||||
|
|
||||||
|
|
|
@ -444,7 +444,7 @@ to be used with GitLab. The following IPs are used as an example:
|
||||||
|
|
||||||
You can optionally use a third party external service for Redis as long as it meets the [requirements](../../install/requirements.md#redis).
|
You can optionally use a third party external service for Redis as long as it meets the [requirements](../../install/requirements.md#redis).
|
||||||
|
|
||||||
A reputable provider or solution should be used for this. [Google Memorystore](https://cloud.google.com/memorystore/docs/redis/redis-overview) and [AWS Elasticache](https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/WhatIs.html) are known to work. However, note that the Redis Cluster mode specifically isn't supported by GitLab. See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information.
|
A reputable provider or solution should be used for this. [Google Memorystore](https://cloud.google.com/memorystore/docs/redis/redis-overview) and [AWS ElastiCache](https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/WhatIs.html) are known to work. However, note that the Redis Cluster mode specifically isn't supported by GitLab. See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information.
|
||||||
|
|
||||||
### Standalone Redis using the Linux package
|
### Standalone Redis using the Linux package
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ and subject to change without notice.
|
||||||
Create a new CycloneDX JSON export for all the project dependencies detected in a pipeline.
|
Create a new CycloneDX JSON export for all the project dependencies detected in a pipeline.
|
||||||
|
|
||||||
If an authenticated user doesn't have permission to
|
If an authenticated user doesn't have permission to
|
||||||
[read_dependency](../user/permissions.md#custom-role-requirements),
|
[`read_dependency`](../user/permissions.md#custom-role-requirements),
|
||||||
this request returns a `403 Forbidden` status code.
|
this request returns a `403 Forbidden` status code.
|
||||||
|
|
||||||
SBOM exports can be only accessed by the export's author.
|
SBOM exports can be only accessed by the export's author.
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1330,7 +1330,8 @@ target the upstream project by default.
|
||||||
"kind": "group",
|
"kind": "group",
|
||||||
"full_path": "gitlab-org",
|
"full_path": "gitlab-org",
|
||||||
"parent_id": null
|
"parent_id": null
|
||||||
}
|
},
|
||||||
|
"repository_storage": "default"
|
||||||
}
|
}
|
||||||
|
|
||||||
...
|
...
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 140 KiB After Width: | Height: | Size: 237 KiB |
|
@ -32,7 +32,7 @@ translate the content of the redirected request where needed.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
[src of the architecture diagram](https://docs.google.com/drawings/d/1PYl5Q5oWHnQAuxM-Jcw0C3eYoGw8a9w8atFpoLhhEas/edit)
|
[Diagram source](https://docs.google.com/drawings/d/1PYl5Q5oWHnQAuxM-Jcw0C3eYoGw8a9w8atFpoLhhEas/edit)
|
||||||
|
|
||||||
By using a hosted service under the control of GitLab we can ensure
|
By using a hosted service under the control of GitLab we can ensure
|
||||||
that we provide all GitLab instances with AI features in a scalable
|
that we provide all GitLab instances with AI features in a scalable
|
||||||
|
@ -385,15 +385,19 @@ different.
|
||||||
|
|
||||||
## Authentication & Authorization
|
## Authentication & Authorization
|
||||||
|
|
||||||
GitLab will provide the first layer of authorization: It authenticate
|
GitLab provides the first layer of authorization: It authenticates
|
||||||
the user and check if the license allows using the feature the user is
|
the user and checks if the license allows using the feature the user is
|
||||||
trying to use. This can be done using the authentication and license
|
trying to use. This can be done using the authentication, policy and license
|
||||||
checks that are already built into GitLab.
|
checks that are already built into GitLab.
|
||||||
|
|
||||||
Authenticating the GitLab-instance on the AI-gateway will be discussed
|
Authenticating the GitLab-instance on the AI-gateway was discussed
|
||||||
in[#177](https://gitlab.com/gitlab-org/modelops/applied-ml/code-suggestions/ai-assist/-/issues/177).
|
in:
|
||||||
Because the AI-gateway exposes proxied endpoints to AI providers, it
|
|
||||||
is important that the authentication tokens have limited validity.
|
- [Issue 177](https://gitlab.com/gitlab-org/modelops/applied-ml/code-suggestions/ai-assist/-/issues/177)
|
||||||
|
- [Epic 10808](https://gitlab.com/groups/gitlab-org/-/epics/10808)
|
||||||
|
|
||||||
|
The specific mechanism by which trust is delegated between end-users, GitLab instances,
|
||||||
|
and the AI-gateway is covered in the [AI gateway access token validation documentation](../../../development/cloud_connector/code_suggestions_for_sm.md#ai-gateway-access-token-validation).
|
||||||
|
|
||||||
## Embeddings
|
## Embeddings
|
||||||
|
|
||||||
|
|
|
@ -265,14 +265,14 @@ GitLab administrators can add a namespace to the reduced cost factor
|
||||||
GitLab SaaS runners have different cost factors, depending on the runner type (Linux, Windows, macOS) and the virtual machine configuration.
|
GitLab SaaS runners have different cost factors, depending on the runner type (Linux, Windows, macOS) and the virtual machine configuration.
|
||||||
|
|
||||||
| GitLab SaaS runner type | Machine Size | Cost factor |
|
| GitLab SaaS runner type | Machine Size | Cost factor |
|
||||||
|:-----------------------------|:---------------------|:------------|
|
|:-----------------------------|:-----------------------|:------------|
|
||||||
| Linux OS amd64 | small | 1 |
|
| Linux OS amd64 | `small` | 1 |
|
||||||
| Linux OS amd64 | medium | 2 |
|
| Linux OS amd64 | `medium` | 2 |
|
||||||
| Linux OS amd64 | large | 3 |
|
| Linux OS amd64 | `large` | 3 |
|
||||||
| Linux OS amd64 | xlarge | 6 |
|
| Linux OS amd64 | `xlarge` | 6 |
|
||||||
| Linux OS amd64 | 2xlarge | 12 |
|
| Linux OS amd64 | `2xlarge` | 12 |
|
||||||
| Linux OS amd64 + GPU-enabled | medium, GPU standard | 7 |
|
| Linux OS amd64 + GPU-enabled | `medium`, GPU standard | 7 |
|
||||||
| macOS M1 | medium | 6 (Beta) |
|
| macOS M1 | `medium` | 6 (Beta) |
|
||||||
| Windows Server | - | 1 (Beta) |
|
| Windows Server | - | 1 (Beta) |
|
||||||
|
|
||||||
### Monthly reset of compute usage
|
### Monthly reset of compute usage
|
||||||
|
|
|
@ -72,9 +72,10 @@ To continue using registration tokens after GitLab 17.0:
|
||||||
|
|
||||||
Plans to implement a UI setting to re-enable registration tokens are proposed in [issue 411923](https://gitlab.com/gitlab-org/gitlab/-/issues/411923)
|
Plans to implement a UI setting to re-enable registration tokens are proposed in [issue 411923](https://gitlab.com/gitlab-org/gitlab/-/issues/411923)
|
||||||
|
|
||||||
## Runners registered with a registration token will continue to work after 18.0
|
## Using runners registered with a runner registration token
|
||||||
|
|
||||||
Existing runners will not be affected by these changes, they will still work even after the legacy registration method is removed.
|
Existing runners will not be affected by these changes and will continue to
|
||||||
|
work after the legacy registration method is removed in GitLab 18.0.
|
||||||
|
|
||||||
## Changes to the `gitlab-runner register` command syntax
|
## Changes to the `gitlab-runner register` command syntax
|
||||||
|
|
||||||
|
|
|
@ -75,7 +75,7 @@ the authentication token is stored in the `config.toml`.
|
||||||
|
|
||||||
WARNING:
|
WARNING:
|
||||||
The ability to pass a runner registration token, and support for certain configuration arguments was
|
The ability to pass a runner registration token, and support for certain configuration arguments was
|
||||||
[deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/380872) in GitLab 15.6 and will be removed in GitLab 17.0. Authentication tokens
|
[deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/380872) in GitLab 15.6 and will be removed in GitLab 18.0. Runner authentication tokens
|
||||||
should be used instead. For more information, see [Migrating to the new runner registration workflow](new_creation_workflow.md).
|
should be used instead. For more information, see [Migrating to the new runner registration workflow](new_creation_workflow.md).
|
||||||
|
|
||||||
Prerequisite:
|
Prerequisite:
|
||||||
|
@ -466,7 +466,7 @@ The runner authentication token displays in the UI for only a short period of ti
|
||||||
|
|
||||||
WARNING:
|
WARNING:
|
||||||
The ability to pass a runner registration token, and support for certain configuration arguments was
|
The ability to pass a runner registration token, and support for certain configuration arguments was
|
||||||
[deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/380872) in GitLab 15.6 and will be removed in GitLab 17.0. Authentication tokens
|
[deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/380872) in GitLab 15.6 and will be removed in GitLab 18.0. Runner authentication tokens
|
||||||
should be used instead. For more information, see [Migrating to the new runner registration workflow](new_creation_workflow.md).
|
should be used instead. For more information, see [Migrating to the new runner registration workflow](new_creation_workflow.md).
|
||||||
|
|
||||||
Prerequisite:
|
Prerequisite:
|
||||||
|
|
|
@ -18,7 +18,7 @@ In GitLab 16.0 and later you can use ID tokens without any settings changes.
|
||||||
Jobs that use `secrets:vault` automatically do not have `CI_JOB_JWT` tokens available,
|
Jobs that use `secrets:vault` automatically do not have `CI_JOB_JWT` tokens available,
|
||||||
Jobs that don't use `secrets:vault` can still use `CI_JOB_JWT` tokens.
|
Jobs that don't use `secrets:vault` can still use `CI_JOB_JWT` tokens.
|
||||||
|
|
||||||
This tutorial will focus on v16 onwards, if you are running a slightly older version you will need to toggle the `Limit JSON Web Token (JWT) access` setting as appropriate.
|
This tutorial will focus on v16 onward, if you are running a slightly older version you will need to toggle the `Limit JSON Web Token (JWT) access` setting as appropriate.
|
||||||
|
|
||||||
There isn't one standard method to migrate to [ID tokens](../secrets/id_token_authentication.md), so this tutorial includes two variations for how to convert your existing CI/CD secrets. Choose the method that is most appropriate for your use case:
|
There isn't one standard method to migrate to [ID tokens](../secrets/id_token_authentication.md), so this tutorial includes two variations for how to convert your existing CI/CD secrets. Choose the method that is most appropriate for your use case:
|
||||||
|
|
||||||
|
|
|
@ -121,7 +121,7 @@ In this example:
|
||||||
- `image: ruby:3.0` and `retry: 2` are the default keywords for all jobs in the pipeline.
|
- `image: ruby:3.0` and `retry: 2` are the default keywords for all jobs in the pipeline.
|
||||||
- The `rspec` job does not have `image` or `retry` defined, so it uses the defaults of
|
- The `rspec` job does not have `image` or `retry` defined, so it uses the defaults of
|
||||||
`image: ruby:3.0` and `retry: 2`.
|
`image: ruby:3.0` and `retry: 2`.
|
||||||
- The `rspec 2.7` job does not have `retry` defined, but it does have `image` explictly defined.
|
- The `rspec 2.7` job does not have `retry` defined, but it does have `image` explicitly defined.
|
||||||
It uses the default `retry: 2`, but ignores the default `image` and uses the `image: ruby:2.7`
|
It uses the default `retry: 2`, but ignores the default `image` and uses the `image: ruby:2.7`
|
||||||
defined in the job.
|
defined in the job.
|
||||||
|
|
||||||
|
|
|
@ -13,9 +13,9 @@ GitLab has created a common set of tools to support our product groups and their
|
||||||
|
|
||||||
AI is moving very quickly, and we need to be able to keep pace with changes in the area. We have built an [abstraction layer](../../ee/development/ai_features/index.md) to do this, allowing us to take a more "pluggable" approach to the underlying models, data stores, and other technologies.
|
AI is moving very quickly, and we need to be able to keep pace with changes in the area. We have built an [abstraction layer](../../ee/development/ai_features/index.md) to do this, allowing us to take a more "pluggable" approach to the underlying models, data stores, and other technologies.
|
||||||
|
|
||||||
The following diagram from the [architecture blueprint](../architecture/blueprints/ai_gateway/index.md) shows a simplified view of how the different components in GitLab interact. The abstraction layer helps avoid code duplication within the REST APIs within the `AI API` block.
|
The following diagram from the [architecture blueprint](../architecture/blueprints/ai_gateway/index.md) shows a simplified view of how the different components in GitLab interact. The abstraction layer helps avoid code duplication within the REST APIs.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## SaaS-based AI abstraction layer
|
## SaaS-based AI abstraction layer
|
||||||
|
|
||||||
|
@ -33,8 +33,7 @@ By default, these actions are performed asynchronously via a Sidekiq
|
||||||
job to prevent long-running requests in Puma. It should be used for
|
job to prevent long-running requests in Puma. It should be used for
|
||||||
non-latency sensitive actions due to the added latency by Sidekiq.
|
non-latency sensitive actions due to the added latency by Sidekiq.
|
||||||
|
|
||||||
At the time of writing, the Abstraction Layer still directly calls the AI providers. This will be
|
At the time of writing, the Abstraction Layer still directly calls the AI providers. [Epic 11484](https://gitlab.com/groups/gitlab-org/-/epics/11484) proposes to change this.
|
||||||
changed [in the future](https://gitlab.com/gitlab-org/gitlab/-/issues/424614).
|
|
||||||
|
|
||||||
When a certain action is latency sensitive, we can decide to call the
|
When a certain action is latency sensitive, we can decide to call the
|
||||||
AI-gateway directly. This avoids the latency added by Sidekiq.
|
AI-gateway directly. This avoids the latency added by Sidekiq.
|
||||||
|
@ -88,24 +87,24 @@ For optimal `probes` and `lists` values:
|
||||||
- Use `lists` equal to `rows / 1000` for tables with up to 1 million rows and `sqrt(rows)` for larger datasets.
|
- Use `lists` equal to `rows / 1000` for tables with up to 1 million rows and `sqrt(rows)` for larger datasets.
|
||||||
- For `probes` start with `lists / 10` for tables up to 1 million rows and `sqrt(lists)` for larger datasets.
|
- For `probes` start with `lists / 10` for tables up to 1 million rows and `sqrt(lists)` for larger datasets.
|
||||||
|
|
||||||
### Code Suggestions
|
## Code Suggestions
|
||||||
|
|
||||||
Code Suggestions is being integrated as part of the GitLab-Rails repository which will unify the architectures between Code Suggestions and AI features that use the abstraction layer, along with offering self-managed support for the other AI features.
|
Code Suggestions is being integrated as part of the GitLab-Rails repository which will unify the architectures between Code Suggestions and AI features that use the abstraction layer, along with offering [self-managed support](#self-managed-support) for the other AI features.
|
||||||
|
|
||||||
The following table documents functionality that Code Suggestions offers today, and what those changes will look like as part of the unification:
|
The following table documents functionality that Code Suggestions offers today, and what those changes will look like as part of the unification:
|
||||||
|
|
||||||
| Topic | Details | Where this happens today | Where this will happen going forward |
|
| Topic | Details | Where this happens today | Where this will happen going forward |
|
||||||
| ----- | ------ | -------------- | ------------------ |
|
| ----- | ------ | -------------- | ------------------ |
|
||||||
| Request processing | | | |
|
| Request processing | | | |
|
||||||
| | Receives requests from IDEs (VSCode, GitLab WebIDE, MS Visual Studio, IntelliJ, JetBrains, VIM, Emacs, Sublime), including code before and after the cursor | AI Gateway | Abstraction Layer |
|
| | Receives requests from IDEs (VSCode, GitLab WebIDE, MS Visual Studio, IntelliJ, JetBrains, VIM, Emacs, Sublime), including code before and after the cursor | GitLab Rails | GitLab Rails |
|
||||||
| | Authentication the current user, verifies they are authorized to use Code Suggestions for this project | AI Gateway | Abstraction layer |
|
| | Authenticates the current user, verifies they are authorized to use Code Suggestions for this project | GitLab Rails + AI Gateway | GitLab Rails + AI Gateway |
|
||||||
| | Preprocesses the request to add context, such as including imports via TreeSitter | AI Gateway | Undecided |
|
| | Preprocesses the request to add context, such as including imports via TreeSitter | AI Gateway | Undecided |
|
||||||
| | Routes the request to the AI Provider | AI Gateway | AI Gateway |
|
| | Routes the request to the AI Provider | AI Gateway | AI Gateway |
|
||||||
| | Returns the response to the IDE | AI Gateway | Abstraction Layer |
|
| | Returns the response to the IDE | GitLab Rails | GitLab Rails |
|
||||||
| | Logs the request, including timestamp, response time, model, etc | AI Gateway | Both |
|
| | Logs the request, including timestamp, response time, model, etc | Both | Both |
|
||||||
| Telemetry | | | |
|
| Telemetry | | | |
|
||||||
| | User acceptance or rejection in the IDE | AI Gateway | [Both](https://gitlab.com/gitlab-org/gitlab/-/issues/418282) |
|
| | User acceptance or rejection in the IDE | AI Gateway | [Both](https://gitlab.com/gitlab-org/gitlab/-/issues/418282) |
|
||||||
| | Number of unique users per day | [Abstraction Layer](https://app.periscopedata.com/app/gitlab/1143612/Code-Suggestions-Usage) | Undecided |
|
| | Number of unique users per day | [GitLab Rails](https://app.periscopedata.com/app/gitlab/1143612/Code-Suggestions-Usage), AI gateway | Undecided |
|
||||||
| | Error rate, model usage, response time, IDE usage | [AI Gateway](https://log.gprd.gitlab.net/app/dashboards#/view/6c947f80-7c07-11ed-9f43-e3784d7fe3ca?_g=(refreshInterval:(pause:!t,value:0),time:(from:now-6h,to:now))) | Both |
|
| | Error rate, model usage, response time, IDE usage | [AI Gateway](https://log.gprd.gitlab.net/app/dashboards#/view/6c947f80-7c07-11ed-9f43-e3784d7fe3ca?_g=(refreshInterval:(pause:!t,value:0),time:(from:now-6h,to:now))) | Both |
|
||||||
| | Suggestions per language | AI Gateway |[Both](https://gitlab.com/groups/gitlab-org/-/epics/11017) |
|
| | Suggestions per language | AI Gateway |[Both](https://gitlab.com/groups/gitlab-org/-/epics/11017) |
|
||||||
| Monitoring | | Both | Both |
|
| Monitoring | | Both | Both |
|
||||||
|
@ -115,7 +114,15 @@ The following table documents functionality that Code Suggestions offers today,
|
||||||
| Internal Models | | | |
|
| Internal Models | | | |
|
||||||
| | Currently unmaintained, the ability to run models in our own instance, running them inside Triton, and routing requests to our own models | AI Gateway | AI Gateway |
|
| | Currently unmaintained, the ability to run models in our own instance, running them inside Triton, and routing requests to our own models | AI Gateway | AI Gateway |
|
||||||
|
|
||||||
#### Code Suggestions Latency
|
### Self-managed support
|
||||||
|
|
||||||
|
Code Suggestions for self-managed users was introduced as part of the [Cloud Connector MVC](https://gitlab.com/groups/gitlab-org/-/epics/10516).
|
||||||
|
|
||||||
|
For more information on the technical solution for this project see the [Cloud Connector MVC documentation](cloud_connector/code_suggestions_for_sm.md).
|
||||||
|
|
||||||
|
The intention is to evolve this solution to service other AI features under the Cloud Connector product umbrella.
|
||||||
|
|
||||||
|
### Code Suggestions Latency
|
||||||
|
|
||||||
Code Suggestions acceptance rates are _highly_ sensitive to latency. While writing code with an AI assistant, a user will pause only for a short duration before continuing on with manually typing out a block of code. As soon as the user has pressed a subsequent keypress, the existing suggestion will be invalidated and a new request will need to be issued to the Code Suggestions endpoint. In turn, this request will also be highly sensitive to latency.
|
Code Suggestions acceptance rates are _highly_ sensitive to latency. While writing code with an AI assistant, a user will pause only for a short duration before continuing on with manually typing out a block of code. As soon as the user has pressed a subsequent keypress, the existing suggestion will be invalidated and a new request will need to be issued to the Code Suggestions endpoint. In turn, this request will also be highly sensitive to latency.
|
||||||
|
|
||||||
|
|
|
@ -134,17 +134,26 @@ Gitlab::CurrentSettings.update(openai_api_key: "<open-ai-key>")
|
||||||
Gitlab::CurrentSettings.update!(anthropic_api_key: <insert API key>)
|
Gitlab::CurrentSettings.update!(anthropic_api_key: <insert API key>)
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Populating embeddings and using embeddings fixture
|
### Populating embeddings and using embeddings fixture
|
||||||
|
|
||||||
|
Currently we have embeddings generate both with OpenAI and VertexAI. Bellow sections explain how to populate
|
||||||
|
embeddings in the DB or extract embeddings to be used in specs.
|
||||||
|
|
||||||
|
FLAG:
|
||||||
|
We are moving towards having VertexAI embeddings only, so eventually the OpenAI embeddings support will be drop
|
||||||
|
as well as the section bellow will be removed.
|
||||||
|
|
||||||
|
#### OpenAI embeddings
|
||||||
|
|
||||||
To seed your development database with the embeddings for GitLab Documentation,
|
To seed your development database with the embeddings for GitLab Documentation,
|
||||||
you may use the pre-generated embeddings and a Rake test.
|
you may use the pre-generated embeddings and a Rake task.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
RAILS_ENV=development bundle exec rake gitlab:llm:embeddings:seed_pre_generated
|
RAILS_ENV=development bundle exec rake gitlab:llm:embeddings:seed_pre_generated
|
||||||
```
|
```
|
||||||
|
|
||||||
The DBCleaner gem we use clear the database tables before each test runs.
|
The DBCleaner gem we use clear the database tables before each test runs.
|
||||||
Instead of fully populating the table `tanuki_bot_mvc` where we store embeddings for the documentations,
|
Instead of fully populating the table `tanuki_bot_mvc` where we store OpenAI embeddings for the documentations,
|
||||||
we can add a few selected embeddings to the table from a pre-generated fixture.
|
we can add a few selected embeddings to the table from a pre-generated fixture.
|
||||||
|
|
||||||
For instance, to test that the question "How can I reset my password" is correctly
|
For instance, to test that the question "How can I reset my password" is correctly
|
||||||
|
@ -157,6 +166,31 @@ You can add or remove the questions needed to be tested in the Rake task and run
|
||||||
RAILS_ENV=development bundle exec rake gitlab:llm:embeddings:extract_embeddings
|
RAILS_ENV=development bundle exec rake gitlab:llm:embeddings:extract_embeddings
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### VertexAI embeddings
|
||||||
|
|
||||||
|
To seed your development database with the embeddings for GitLab Documentation,
|
||||||
|
you may use the pre-generated embeddings and a Rake task.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
RAILS_ENV=development bundle exec rake gitlab:llm:embeddings:vertex:seed
|
||||||
|
```
|
||||||
|
|
||||||
|
The DBCleaner gem we use clear the database tables before each test runs.
|
||||||
|
Instead of fully populating the table `vertex_gitlab_docs` where we store VertexAI embeddings for the documentations,
|
||||||
|
we can add a few selected embeddings to the table from a pre-generated fixture.
|
||||||
|
|
||||||
|
For instance, to test that the question "How can I reset my password" is correctly
|
||||||
|
retrieving the relevant embeddings and answered, we can extract the top N closet embeddings
|
||||||
|
to the question into a fixture and only restore a small number of embeddings quickly.
|
||||||
|
To faciliate an extraction process, a Rake task been written.
|
||||||
|
You can add or remove the questions needed to be tested in the Rake task and run the task to generate a new fixture.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
RAILS_ENV=development bundle exec rake gitlab:llm:embeddings:vertex:extract_embeddings
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Using embeddings in specs
|
||||||
|
|
||||||
In the specs where you need to use the embeddings,
|
In the specs where you need to use the embeddings,
|
||||||
use the RSpec config hook `:ai_embedding_fixtures` on a context.
|
use the RSpec config hook `:ai_embedding_fixtures` on a context.
|
||||||
|
|
||||||
|
|
|
@ -1423,7 +1423,7 @@ wrapper = mount(SomeComponent, {
|
||||||
|
|
||||||
#### Testing subscriptions
|
#### Testing subscriptions
|
||||||
|
|
||||||
When testing subscriptions, be aware that default behavior for subscription in `vue-apollo@4` is to re-subscribe and immediatelly issue new request on error (unless value of `skip` restricts us from doing that)
|
When testing subscriptions, be aware that default behavior for subscription in `vue-apollo@4` is to re-subscribe and immediately issue new request on error (unless value of `skip` restricts us from doing that)
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
import waitForPromises from 'helpers/wait_for_promises';
|
import waitForPromises from 'helpers/wait_for_promises';
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 140 KiB |
|
@ -139,7 +139,7 @@ Save the changes and then run `sudo gitlab-ctl reconfigure`. If there are no err
|
||||||
|
|
||||||
## Specify numeric user and group identifiers
|
## Specify numeric user and group identifiers
|
||||||
|
|
||||||
The Linux pacakage creates a user and group `mattermost`. You can specify the
|
The Linux package creates a user and group `mattermost`. You can specify the
|
||||||
numeric identifiers for these users in `/etc/gitlab/gitlab.rb` as follows:
|
numeric identifiers for these users in `/etc/gitlab/gitlab.rb` as follows:
|
||||||
|
|
||||||
```ruby
|
```ruby
|
||||||
|
|
|
@ -1353,7 +1353,7 @@ The `go.sum` file contains an entry of every module that was considered while ge
|
||||||
Multiple versions of a module are included in the `go.sum` file, but the [MVS](https://go.dev/ref/mod#minimal-version-selection)
|
Multiple versions of a module are included in the `go.sum` file, but the [MVS](https://go.dev/ref/mod#minimal-version-selection)
|
||||||
algorithm used by `go build` only selects one. As a result, when dependency scanning uses `go.sum`, it might report false positives.
|
algorithm used by `go build` only selects one. As a result, when dependency scanning uses `go.sum`, it might report false positives.
|
||||||
|
|
||||||
To prevent false positives, gemnasium only uses `go.sum` if it is unable to generate the build list for the Go project. If `go.sum` is selected, a warning occurs:
|
To prevent false positives, Gemnasium only uses `go.sum` if it is unable to generate the build list for the Go project. If `go.sum` is selected, a warning occurs:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
[WARN] [Gemnasium] [2022-09-14T20:59:38Z] ▶ Selecting "go.sum" parser for "/test-projects/gitlab-shell/go.sum". False positives may occur. See https://gitlab.com/gitlab-org/gitlab/-/issues/321081.
|
[WARN] [Gemnasium] [2022-09-14T20:59:38Z] ▶ Selecting "go.sum" parser for "/test-projects/gitlab-shell/go.sum". False positives may occur. See https://gitlab.com/gitlab-org/gitlab/-/issues/321081.
|
||||||
|
|
|
@ -143,14 +143,14 @@ The workaround is to amend your group or instance push rules to allow branches f
|
||||||
|
|
||||||
- Confirm that scanners are properly configured and producing results for the latest branch. Security Policies are designed to require approval when there are no results (no security report), as this ensures that no vulnerabilities are introduced. We cannot know if there are any vulnerabilities unless the scans enforced by the policy complete successfully and are evaluated.
|
- Confirm that scanners are properly configured and producing results for the latest branch. Security Policies are designed to require approval when there are no results (no security report), as this ensures that no vulnerabilities are introduced. We cannot know if there are any vulnerabilities unless the scans enforced by the policy complete successfully and are evaluated.
|
||||||
- For scan result policies, we require artifacts for each scanner defined in the policy for both the source and target branch. To ensure scan result policies capture the necessary results, confirm your scan execution is properly implemented and enforced. If using scan execution policies, enforcing on `all branches` often address this need.
|
- For scan result policies, we require artifacts for each scanner defined in the policy for both the source and target branch. To ensure scan result policies capture the necessary results, confirm your scan execution is properly implemented and enforced. If using scan execution policies, enforcing on `all branches` often address this need.
|
||||||
- When running scan execution policies based on a SAST action, ensure target repositories contain proper code files. SAST runs different analyzers [based on the types of files in the repo](../sast/index.md#supported-languages-and-frameworks), and if no supported files are found it will not run any jobs. See the [SAST CI template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Jobs/SAST.gitlab-ci.yml) for more details.
|
- When running scan execution policies based on a SAST action, ensure target repositories contain proper code files. SAST runs different analyzers [based on the types of files in the repository](../sast/index.md#supported-languages-and-frameworks), and if no supported files are found it will not run any jobs. See the [SAST CI template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Jobs/SAST.gitlab-ci.yml) for more details.
|
||||||
- Check for any branch configuration conflicts. If your policy is configured to enforce rules on `main` but some projects within the scope are using `master` as their default branch, the policy is not applied for the latter. You can define policies to enforce rules generically on `default` branches regardless of the name used in the project or on `all protected branches` to address this issue.
|
- Check for any branch configuration conflicts. If your policy is configured to enforce rules on `main` but some projects within the scope are using `master` as their default branch, the policy is not applied for the latter. You can define policies to enforce rules generically on `default` branches regardless of the name used in the project or on `all protected branches` to address this issue.
|
||||||
- Scan result policies created at the group or sub-group level can take some time to apply to all the merge requests in the group.
|
- Scan result policies created at the group or sub-group level can take some time to apply to all the merge requests in the group.
|
||||||
- Scheduled scan execution policies run with a minimum 15 minute cadence. Learn more [about the schedule rule type](../policies/scan-execution-policies.md#schedule-rule-type).
|
- Scheduled scan execution policies run with a minimum 15 minute cadence. Learn more [about the schedule rule type](../policies/scan-execution-policies.md#schedule-rule-type).
|
||||||
- When scheduling pipelines, keep in mind that CRON scheduling is based on UTC on GitLab SaaS and is based on your server time for self managed instances. When testing new policies, it may appear pipelines are not running properly when in fact they are scheduled in your server's timezone.
|
- When scheduling pipelines, keep in mind that CRON scheduling is based on UTC on GitLab SaaS and is based on your server time for self managed instances. When testing new policies, it may appear pipelines are not running properly when in fact they are scheduled in your server's timezone.
|
||||||
- When enforcing scan execution policies, security policies use a bot in the target project that will trigger scheduled pipelines to ensure enforcement. When the bot is missing, it will be automatically created, and the following scheduled scan will use it.
|
- When enforcing scan execution policies, security policies use a bot in the target project that will trigger scheduled pipelines to ensure enforcement. When the bot is missing, it will be automatically created, and the following scheduled scan will use it.
|
||||||
- You should not link a security policy project to a development project and to the group or sub-group the development project belongs to at the same time. Linking this way will result in approval rules from the Scan Result Policy not being applied to merge requests in the development project.
|
- You should not link a security policy project to a development project and to the group or sub-group the development project belongs to at the same time. Linking this way will result in approval rules from the Scan Result Policy not being applied to merge requests in the development project.
|
||||||
- When creating a Scan Result Policy, neither the array `severity_levels` nor the array `vulnerability_states` in the [scan_finding rule](../policies/scan-result-policies.md#scan_finding-rule-type) can be left empty; for a working rule, at least one entry must exist.
|
- When creating a Scan Result Policy, neither the array `severity_levels` nor the array `vulnerability_states` in the [`scan_finding` rule](../policies/scan-result-policies.md#scan_finding-rule-type) can be left empty; for a working rule, at least one entry must exist.
|
||||||
- When configuring pipeline and scan result policies, it's important to remember that security scans performed in manual jobs aren't verified to determine whether MR approval is required. When you run a manual job with security scans, it won't ensure approval even if vulnerabilities are introduced.
|
- When configuring pipeline and scan result policies, it's important to remember that security scans performed in manual jobs aren't verified to determine whether MR approval is required. When you run a manual job with security scans, it won't ensure approval even if vulnerabilities are introduced.
|
||||||
|
|
||||||
If you are still experiencing issues, you can [view recent reported bugs](https://gitlab.com/gitlab-org/gitlab/-/issues/?sort=popularity&state=opened&label_name%5B%5D=group%3A%3Asecurity%20policies&label_name%5B%5D=type%3A%3Abug&first_page_size=20) and raise new unreported issues.
|
If you are still experiencing issues, you can [view recent reported bugs](https://gitlab.com/gitlab-org/gitlab/-/issues/?sort=popularity&state=opened&label_name%5B%5D=group%3A%3Asecurity%20policies&label_name%5B%5D=type%3A%3Abug&first_page_size=20) and raise new unreported issues.
|
||||||
|
|
|
@ -39,7 +39,7 @@ A project can have multiple pipeline types configured. A single commit can initi
|
||||||
pipelines, each of which may contain a security scan.
|
pipelines, each of which may contain a security scan.
|
||||||
|
|
||||||
- In GitLab 16.3 and later, the results of all completed pipelines for the latest commit in
|
- In GitLab 16.3 and later, the results of all completed pipelines for the latest commit in
|
||||||
the MR's source and target branch are evaluated and used to enforce the scan result policy.
|
the merge request's source and target branch are evaluated and used to enforce the scan result policy.
|
||||||
Parent-child pipelines and on-demand DAST pipelines are not considered.
|
Parent-child pipelines and on-demand DAST pipelines are not considered.
|
||||||
- In GitLab 16.2 and earlier, only the results of the latest completed pipeline were evaluated
|
- In GitLab 16.2 and earlier, only the results of the latest completed pipeline were evaluated
|
||||||
when enforcing scan result policies.
|
when enforcing scan result policies.
|
||||||
|
|
|
@ -99,4 +99,4 @@ This error typically occurs when the user you're trying to remove is part of an
|
||||||
- Remove the invited group membership from your project or group members page.
|
- Remove the invited group membership from your project or group members page.
|
||||||
- Recommended. Remove the user directly from the invited group, if you have access to the group.
|
- Recommended. Remove the user directly from the invited group, if you have access to the group.
|
||||||
|
|
||||||
The feature request to **Update billable_members endpoint to include invited group** is currently being worked on. For more information, see [issue 386583](https://gitlab.com/gitlab-org/gitlab/-/issues/386583)
|
The feature request to **Update `billable_members` endpoint to include invited group** is currently being worked on. For more information, see [issue 386583](https://gitlab.com/gitlab-org/gitlab/-/issues/386583)
|
||||||
|
|
|
@ -49,7 +49,7 @@ To view the updated syntax highlighting theme, refresh your project's page.
|
||||||
To customize the syntax highlighting theme, you can also [use the Application settings API](../../api/settings.md#list-of-settings-that-can-be-accessed-via-api-calls). Use `default_syntax_highlighting_theme` to change the syntax highlighting colors on a more granular level.
|
To customize the syntax highlighting theme, you can also [use the Application settings API](../../api/settings.md#list-of-settings-that-can-be-accessed-via-api-calls). Use `default_syntax_highlighting_theme` to change the syntax highlighting colors on a more granular level.
|
||||||
|
|
||||||
If these steps do not work, your programming language might not be supported by the syntax highlighters.
|
If these steps do not work, your programming language might not be supported by the syntax highlighters.
|
||||||
For more information, view [Rouge Ruby Library](https://github.com/rouge-ruby/rouge) for guidance on code files and Snippets. View [Moncaco Editor](https://microsoft.github.io/monaco-editor/) and [Monarch](https://microsoft.github.io/monaco-editor/monarch.html) for guidance on the Web IDE.
|
For more information, view [Rouge Ruby Library](https://github.com/rouge-ruby/rouge) for guidance on code files and Snippets. View [Monaco Editor](https://microsoft.github.io/monaco-editor/) and [Monarch](https://microsoft.github.io/monaco-editor/monarch.html) for guidance on the Web IDE.
|
||||||
|
|
||||||
## Change the diff colors
|
## Change the diff colors
|
||||||
|
|
||||||
|
@ -105,17 +105,17 @@ To change the default content on your group overview page:
|
||||||
1. On the left sidebar, select your avatar.
|
1. On the left sidebar, select your avatar.
|
||||||
1. Select **Preferences**.
|
1. Select **Preferences**.
|
||||||
1. Go to the **Behavior** section.
|
1. Go to the **Behavior** section.
|
||||||
1. For **Group overivew content**, select an option.
|
1. For **Group overview content**, select an option.
|
||||||
1. Select **Save changes**.
|
1. Select **Save changes**.
|
||||||
|
|
||||||
### Customize default content on your project overview page
|
### Customize default content on your project overview page
|
||||||
|
|
||||||
Your project overview page is the page you view when you select **Project overview** on the left sidebar. You can set your main project overview page to the Activity page, the Readme file, and other content.
|
Your project overview page is the page you view when you select **Project overview** on the left sidebar. You can set your main project overview page to the Activity page, the README file, and other content.
|
||||||
|
|
||||||
1. On the left sidebar, select your avatar.
|
1. On the left sidebar, select your avatar.
|
||||||
1. Select **Preferences**.
|
1. Select **Preferences**.
|
||||||
1. Go to the **Behavior** section.
|
1. Go to the **Behavior** section.
|
||||||
1. For **Project overivew content**, select an option.
|
1. For **Project overview content**, select an option.
|
||||||
1. Select **Save changes**.
|
1. Select **Save changes**.
|
||||||
|
|
||||||
### Hide shortcut buttons
|
### Hide shortcut buttons
|
||||||
|
|
|
@ -120,7 +120,7 @@ To use custom settings for a project or group integration:
|
||||||
| Buildkite | Run CI/CD pipelines with Buildkite. | **{check-circle}** Yes |
|
| Buildkite | Run CI/CD pipelines with Buildkite. | **{check-circle}** Yes |
|
||||||
| Campfire | Connect to chat. | **{dotted-circle}** No |
|
| Campfire | Connect to chat. | **{dotted-circle}** No |
|
||||||
| [ClickUp](clickup.md) | Use ClickUp as the issue tracker. | **{dotted-circle}** No |
|
| [ClickUp](clickup.md) | Use ClickUp as the issue tracker. | **{dotted-circle}** No |
|
||||||
| [Confluence Workspace](../../../api/integrations.md#confluence-integration) | Use Confluence Cloud Workspace as an internal wiki. | **{dotted-circle}** No |
|
| [Confluence Workspace](../../../api/integrations.md#confluence-workspace) | Use Confluence Cloud Workspace as an internal wiki. | **{dotted-circle}** No |
|
||||||
| [Custom issue tracker](custom_issue_tracker.md) | Use a custom issue tracker. | **{dotted-circle}** No |
|
| [Custom issue tracker](custom_issue_tracker.md) | Use a custom issue tracker. | **{dotted-circle}** No |
|
||||||
| [Datadog](../../../integration/datadog.md) | Trace your GitLab pipelines with Datadog. | **{check-circle}** Yes |
|
| [Datadog](../../../integration/datadog.md) | Trace your GitLab pipelines with Datadog. | **{check-circle}** Yes |
|
||||||
| [Discord Notifications](discord_notifications.md) | Send notifications about project events to a Discord channel. | **{dotted-circle}** No |
|
| [Discord Notifications](discord_notifications.md) | Send notifications about project events to a Discord channel. | **{dotted-circle}** No |
|
||||||
|
|
|
@ -100,7 +100,7 @@ from the GitLab user interface.
|
||||||
|
|
||||||
Prerequisites:
|
Prerequisites:
|
||||||
|
|
||||||
- The [Jetbrains Toolbox App](https://www.jetbrains.com/toolbox-app/) must be also be installed.
|
- The [JetBrains Toolbox App](https://www.jetbrains.com/toolbox-app/) must be also be installed.
|
||||||
|
|
||||||
To do this:
|
To do this:
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,10 @@ module API
|
||||||
expose :namespace, using: 'API::Entities::NamespaceBasic'
|
expose :namespace, using: 'API::Entities::NamespaceBasic'
|
||||||
expose :custom_attributes, using: 'API::Entities::CustomAttribute', if: :with_custom_attributes
|
expose :custom_attributes, using: 'API::Entities::CustomAttribute', if: :with_custom_attributes
|
||||||
|
|
||||||
|
expose :repository_storage, documentation: { type: 'string', example: 'default' }, if: ->(project, options) {
|
||||||
|
Ability.allowed?(options[:current_user], :change_repository_storage, project)
|
||||||
|
}
|
||||||
|
|
||||||
# rubocop: disable CodeReuse/ActiveRecord
|
# rubocop: disable CodeReuse/ActiveRecord
|
||||||
def self.preload_relation(projects_relation, options = {})
|
def self.preload_relation(projects_relation, options = {})
|
||||||
# Preloading topics, should be done with using only `:topics`,
|
# Preloading topics, should be done with using only `:topics`,
|
||||||
|
|
|
@ -159,9 +159,6 @@ module API
|
||||||
}
|
}
|
||||||
|
|
||||||
expose :autoclose_referenced_issues, documentation: { type: 'boolean' }
|
expose :autoclose_referenced_issues, documentation: { type: 'boolean' }
|
||||||
expose :repository_storage, documentation: { type: 'string', example: 'default' }, if: ->(project, options) {
|
|
||||||
Ability.allowed?(options[:current_user], :change_repository_storage, project)
|
|
||||||
}
|
|
||||||
|
|
||||||
# rubocop: disable CodeReuse/ActiveRecord
|
# rubocop: disable CodeReuse/ActiveRecord
|
||||||
def self.preload_resource(project)
|
def self.preload_resource(project)
|
||||||
|
|
|
@ -38389,6 +38389,9 @@ msgstr ""
|
||||||
msgid "Provider"
|
msgid "Provider"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Provider ID"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Provision instructions"
|
msgid "Provision instructions"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ import Vue, { nextTick } from 'vue';
|
||||||
import Vuex from 'vuex';
|
import Vuex from 'vuex';
|
||||||
import setWindowLocation from 'helpers/set_window_location_helper';
|
import setWindowLocation from 'helpers/set_window_location_helper';
|
||||||
import { TEST_HOST } from 'spec/test_constants';
|
import { TEST_HOST } from 'spec/test_constants';
|
||||||
|
|
||||||
import App from '~/diffs/components/app.vue';
|
import App from '~/diffs/components/app.vue';
|
||||||
import CommitWidget from '~/diffs/components/commit_widget.vue';
|
import CommitWidget from '~/diffs/components/commit_widget.vue';
|
||||||
import CompareVersions from '~/diffs/components/compare_versions.vue';
|
import CompareVersions from '~/diffs/components/compare_versions.vue';
|
||||||
|
@ -17,6 +18,8 @@ import DiffsFileTree from '~/diffs/components/diffs_file_tree.vue';
|
||||||
import CollapsedFilesWarning from '~/diffs/components/collapsed_files_warning.vue';
|
import CollapsedFilesWarning from '~/diffs/components/collapsed_files_warning.vue';
|
||||||
import HiddenFilesWarning from '~/diffs/components/hidden_files_warning.vue';
|
import HiddenFilesWarning from '~/diffs/components/hidden_files_warning.vue';
|
||||||
|
|
||||||
|
import eventHub from '~/diffs/event_hub';
|
||||||
|
|
||||||
import axios from '~/lib/utils/axios_utils';
|
import axios from '~/lib/utils/axios_utils';
|
||||||
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
||||||
import { Mousetrap } from '~/lib/mousetrap';
|
import { Mousetrap } from '~/lib/mousetrap';
|
||||||
|
@ -760,4 +763,29 @@ describe('diffs/components/app', () => {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('autoscroll', () => {
|
||||||
|
let loadSpy;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
createComponent();
|
||||||
|
loadSpy = jest.spyOn(wrapper.vm, 'loadCollapsedDiff').mockResolvedValue('resolved');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does nothing if the location hash does not include a file hash', () => {
|
||||||
|
window.location.hash = 'not_a_file_hash';
|
||||||
|
|
||||||
|
eventHub.$emit('doneLoadingBatches');
|
||||||
|
|
||||||
|
expect(loadSpy).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('requests that the correct file be loaded', () => {
|
||||||
|
window.location.hash = '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_0_1';
|
||||||
|
|
||||||
|
eventHub.$emit('doneLoadingBatches');
|
||||||
|
|
||||||
|
expect(loadSpy).toHaveBeenCalledWith({ file: store.state.diffs.diffFiles[0] });
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -8,8 +8,12 @@ import { mockTracking, triggerEvent } from 'helpers/tracking_helper';
|
||||||
|
|
||||||
import DiffFileHeader from '~/diffs/components/diff_file_header.vue';
|
import DiffFileHeader from '~/diffs/components/diff_file_header.vue';
|
||||||
import { DIFF_FILE_AUTOMATIC_COLLAPSE, DIFF_FILE_MANUAL_COLLAPSE } from '~/diffs/constants';
|
import { DIFF_FILE_AUTOMATIC_COLLAPSE, DIFF_FILE_MANUAL_COLLAPSE } from '~/diffs/constants';
|
||||||
import { reviewFile } from '~/diffs/store/actions';
|
import { reviewFile, setFileForcedOpen } from '~/diffs/store/actions';
|
||||||
import { SET_DIFF_FILE_VIEWED, SET_MR_FILE_REVIEWS } from '~/diffs/store/mutation_types';
|
import {
|
||||||
|
SET_DIFF_FILE_VIEWED,
|
||||||
|
SET_MR_FILE_REVIEWS,
|
||||||
|
SET_FILE_FORCED_OPEN,
|
||||||
|
} from '~/diffs/store/mutation_types';
|
||||||
import { diffViewerModes } from '~/ide/constants';
|
import { diffViewerModes } from '~/ide/constants';
|
||||||
import { scrollToElement } from '~/lib/utils/common_utils';
|
import { scrollToElement } from '~/lib/utils/common_utils';
|
||||||
import { truncateSha } from '~/lib/utils/text_utility';
|
import { truncateSha } from '~/lib/utils/text_utility';
|
||||||
|
@ -67,6 +71,7 @@ describe('DiffFileHeader component', () => {
|
||||||
toggleFullDiff: jest.fn(),
|
toggleFullDiff: jest.fn(),
|
||||||
setCurrentFileHash: jest.fn(),
|
setCurrentFileHash: jest.fn(),
|
||||||
setFileCollapsedByUser: jest.fn(),
|
setFileCollapsedByUser: jest.fn(),
|
||||||
|
setFileForcedOpen: jest.fn(),
|
||||||
reviewFile: jest.fn(),
|
reviewFile: jest.fn(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -138,6 +143,19 @@ describe('DiffFileHeader component', () => {
|
||||||
expect(wrapper.emitted().toggleFile).toBeDefined();
|
expect(wrapper.emitted().toggleFile).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('when header is clicked it triggers the action that removes the value that forces a file to be uncollapsed', () => {
|
||||||
|
createComponent();
|
||||||
|
findHeader().trigger('click');
|
||||||
|
|
||||||
|
return testAction(
|
||||||
|
setFileForcedOpen,
|
||||||
|
{ filePath: diffFile.file_path, forced: false },
|
||||||
|
{},
|
||||||
|
[{ type: SET_FILE_FORCED_OPEN, payload: { filePath: diffFile.file_path, forced: false } }],
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
it('when collapseIcon is clicked emits toggleFile', async () => {
|
it('when collapseIcon is clicked emits toggleFile', async () => {
|
||||||
createComponent({ props: { collapsible: true } });
|
createComponent({ props: { collapsible: true } });
|
||||||
findCollapseButton().vm.$emit('click', new Event('click'));
|
findCollapseButton().vm.$emit('click', new Event('click'));
|
||||||
|
@ -643,6 +661,44 @@ describe('DiffFileHeader component', () => {
|
||||||
expect(Boolean(wrapper.emitted().toggleFile)).toBe(fires);
|
expect(Boolean(wrapper.emitted().toggleFile)).toBe(fires);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
it('removes the property that forces a file to be shown when the file review is toggled', () => {
|
||||||
|
createComponent({
|
||||||
|
props: {
|
||||||
|
diffFile: {
|
||||||
|
...diffFile,
|
||||||
|
viewer: {
|
||||||
|
...diffFile.viewer,
|
||||||
|
automaticallyCollapsed: false,
|
||||||
|
manuallyCollapsed: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
showLocalFileReviews: true,
|
||||||
|
addMergeRequestButtons: true,
|
||||||
|
expanded: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
findReviewFileCheckbox().vm.$emit('change', true);
|
||||||
|
|
||||||
|
testAction(
|
||||||
|
setFileForcedOpen,
|
||||||
|
{ filePath: diffFile.file_path, forced: false },
|
||||||
|
{},
|
||||||
|
[{ type: SET_FILE_FORCED_OPEN, payload: { filePath: diffFile.file_path, forced: false } }],
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
|
findReviewFileCheckbox().vm.$emit('change', false);
|
||||||
|
|
||||||
|
testAction(
|
||||||
|
setFileForcedOpen,
|
||||||
|
{ filePath: diffFile.file_path, forced: false },
|
||||||
|
{},
|
||||||
|
[{ type: SET_FILE_FORCED_OPEN, payload: { filePath: diffFile.file_path, forced: false } }],
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should render the comment on files button', () => {
|
it('should render the comment on files button', () => {
|
||||||
|
|
|
@ -324,6 +324,22 @@ describe('DiffFile', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('collapsing', () => {
|
describe('collapsing', () => {
|
||||||
|
describe('forced open', () => {
|
||||||
|
it('should have content even when it is automatically collapsed', () => {
|
||||||
|
makeFileAutomaticallyCollapsed(store);
|
||||||
|
|
||||||
|
expect(findDiffContentArea(wrapper).element.children.length).toBe(1);
|
||||||
|
expect(wrapper.classes('has-body')).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have content even when it is manually collapsed', () => {
|
||||||
|
makeFileManuallyCollapsed(store);
|
||||||
|
|
||||||
|
expect(findDiffContentArea(wrapper).element.children.length).toBe(1);
|
||||||
|
expect(wrapper.classes('has-body')).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe(`\`${EVT_EXPAND_ALL_FILES}\` event`, () => {
|
describe(`\`${EVT_EXPAND_ALL_FILES}\` event`, () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.spyOn(wrapper.vm, 'handleToggle').mockImplementation(() => {});
|
jest.spyOn(wrapper.vm, 'handleToggle').mockImplementation(() => {});
|
||||||
|
|
|
@ -1627,6 +1627,7 @@ describe('DiffsStoreActions', () => {
|
||||||
name: updatedViewerName,
|
name: updatedViewerName,
|
||||||
automaticallyCollapsed: false,
|
automaticallyCollapsed: false,
|
||||||
manuallyCollapsed: false,
|
manuallyCollapsed: false,
|
||||||
|
forceOpen: false,
|
||||||
};
|
};
|
||||||
const testData = [{ rich_text: 'test' }, { rich_text: 'file2' }];
|
const testData = [{ rich_text: 'test' }, { rich_text: 'file2' }];
|
||||||
let renamedFile;
|
let renamedFile;
|
||||||
|
@ -1673,7 +1674,7 @@ describe('DiffsStoreActions', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('setFileUserCollapsed', () => {
|
describe('setFileCollapsedByUser', () => {
|
||||||
it('commits SET_FILE_COLLAPSED', () => {
|
it('commits SET_FILE_COLLAPSED', () => {
|
||||||
return testAction(
|
return testAction(
|
||||||
diffActions.setFileCollapsedByUser,
|
diffActions.setFileCollapsedByUser,
|
||||||
|
@ -1690,6 +1691,17 @@ describe('DiffsStoreActions', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('setFileForcedOpen', () => {
|
||||||
|
it('commits SET_FILE_FORCED_OPEN', () => {
|
||||||
|
return testAction(diffActions.setFileForcedOpen, { filePath: 'test', forced: true }, null, [
|
||||||
|
{
|
||||||
|
type: types.SET_FILE_FORCED_OPEN,
|
||||||
|
payload: { filePath: 'test', forced: true },
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('setExpandedDiffLines', () => {
|
describe('setExpandedDiffLines', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
utils.idleCallback.mockImplementation((cb) => {
|
utils.idleCallback.mockImplementation((cb) => {
|
||||||
|
|
|
@ -1055,4 +1055,14 @@ describe('DiffsStoreMutations', () => {
|
||||||
expect(state.diffFiles[0].drafts[0]).toEqual('test');
|
expect(state.diffFiles[0].drafts[0]).toEqual('test');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('SET_FILE_FORCED_OPEN', () => {
|
||||||
|
it('sets the forceOpen property of a diff file viewer correctly', () => {
|
||||||
|
const state = { diffFiles: [{ file_path: 'abc', viewer: { forceOpen: 'not-a-boolean' } }] };
|
||||||
|
|
||||||
|
mutations[types.SET_FILE_FORCED_OPEN](state, { filePath: 'abc', force: true });
|
||||||
|
|
||||||
|
expect(state.diffFiles[0].viewer.forceOpen).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import {
|
import {
|
||||||
updateChangesTabCount,
|
updateChangesTabCount,
|
||||||
getDerivedMergeRequestInformation,
|
getDerivedMergeRequestInformation,
|
||||||
|
extractFileHash,
|
||||||
} from '~/diffs/utils/merge_request';
|
} from '~/diffs/utils/merge_request';
|
||||||
import { ZERO_CHANGES_ALT_DISPLAY } from '~/diffs/constants';
|
import { ZERO_CHANGES_ALT_DISPLAY } from '~/diffs/constants';
|
||||||
import { diffMetadata } from '../mock_data/diff_metadata';
|
import { diffMetadata } from '../mock_data/diff_metadata';
|
||||||
|
@ -128,4 +129,19 @@ describe('Merge Request utilities', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('extractFileHash', () => {
|
||||||
|
const sha1Like = 'abcdef1234567890abcdef1234567890abcdef12';
|
||||||
|
const sha1LikeToo = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
|
||||||
|
|
||||||
|
it('returns undefined when a SHA1-like string cannot be found in the input', () => {
|
||||||
|
expect(extractFileHash({ input: 'something' })).toBe(undefined);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns the first matching string of SHA1-like characters in the input', () => {
|
||||||
|
const fullString = `#${sha1Like}_34_42--${sha1LikeToo}`;
|
||||||
|
|
||||||
|
expect(extractFileHash({ input: fullString })).toBe(sha1Like);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,73 +0,0 @@
|
||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
RSpec.describe SidekiqHelper, feature_category: :shared do
|
|
||||||
describe 'parse_sidekiq_ps' do
|
|
||||||
it 'parses line with time' do
|
|
||||||
line = '55137 10,0 2,1 S+ 2:30pm sidekiq 4.1.4 gitlab [0 of 25 busy] '
|
|
||||||
parts = helper.parse_sidekiq_ps(line)
|
|
||||||
|
|
||||||
expect(parts).to eq(['55137', '10,0', '2,1', 'S+', '2:30pm', 'sidekiq 4.1.4 gitlab [0 of 25 busy]'])
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'parses line with date' do
|
|
||||||
line = '55137 10,0 2,1 S+ Aug 4 sidekiq 4.1.4 gitlab [0 of 25 busy] '
|
|
||||||
parts = helper.parse_sidekiq_ps(line)
|
|
||||||
|
|
||||||
expect(parts).to eq(['55137', '10,0', '2,1', 'S+', 'Aug 4', 'sidekiq 4.1.4 gitlab [0 of 25 busy]'])
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'parses line with two digit date' do
|
|
||||||
line = '55137 10,0 2,1 S+ Aug 04 sidekiq 4.1.4 gitlab [0 of 25 busy] '
|
|
||||||
parts = helper.parse_sidekiq_ps(line)
|
|
||||||
|
|
||||||
expect(parts).to eq(['55137', '10,0', '2,1', 'S+', 'Aug 04', 'sidekiq 4.1.4 gitlab [0 of 25 busy]'])
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'parses line with dot as float separator' do
|
|
||||||
line = '55137 10.0 2.1 S+ 2:30pm sidekiq 4.1.4 gitlab [0 of 25 busy] '
|
|
||||||
parts = helper.parse_sidekiq_ps(line)
|
|
||||||
|
|
||||||
expect(parts).to eq(['55137', '10.0', '2.1', 'S+', '2:30pm', 'sidekiq 4.1.4 gitlab [0 of 25 busy]'])
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'parses OSX output' do
|
|
||||||
line = ' 1641 1.5 3.8 S+ 4:04PM sidekiq 4.2.1 gitlab [0 of 25 busy]'
|
|
||||||
parts = helper.parse_sidekiq_ps(line)
|
|
||||||
|
|
||||||
expect(parts).to eq(['1641', '1.5', '3.8', 'S+', '4:04PM', 'sidekiq 4.2.1 gitlab [0 of 25 busy]'])
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'parses Ubuntu output' do
|
|
||||||
# Ubuntu Linux 16.04 LTS / procps-3.3.10-4ubuntu2
|
|
||||||
line = ' 938 1.4 2.5 Sl+ 21:23:21 sidekiq 4.2.1 gitlab [0 of 25 busy] '
|
|
||||||
parts = helper.parse_sidekiq_ps(line)
|
|
||||||
|
|
||||||
expect(parts).to eq(['938', '1.4', '2.5', 'Sl+', '21:23:21', 'sidekiq 4.2.1 gitlab [0 of 25 busy]'])
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'parses Debian output' do
|
|
||||||
# Debian Linux Wheezy/Jessie
|
|
||||||
line = '17725 1.0 12.1 Ssl 19:20:15 sidekiq 4.2.1 gitlab-rails [0 of 25 busy] '
|
|
||||||
parts = helper.parse_sidekiq_ps(line)
|
|
||||||
|
|
||||||
expect(parts).to eq(['17725', '1.0', '12.1', 'Ssl', '19:20:15', 'sidekiq 4.2.1 gitlab-rails [0 of 25 busy]'])
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'parses OpenBSD output' do
|
|
||||||
# OpenBSD 6.1
|
|
||||||
line = '49258 0.5 2.3 R/0 Fri10PM ruby23: sidekiq 4.2.7 gitlab [0 of 25 busy] (ruby23)'
|
|
||||||
parts = helper.parse_sidekiq_ps(line)
|
|
||||||
|
|
||||||
expect(parts).to eq(['49258', '0.5', '2.3', 'R/0', 'Fri10PM', 'ruby23: sidekiq 4.2.7 gitlab [0 of 25 busy] (ruby23)'])
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'does fail gracefully on line not matching the format' do
|
|
||||||
line = '55137 10.0 2.1 S+ 2:30pm something'
|
|
||||||
parts = helper.parse_sidekiq_ps(line)
|
|
||||||
|
|
||||||
expect(parts).to eq(['?', '?', '?', '?', '?', '?'])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -76,20 +76,6 @@ RSpec.describe SortingHelper do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#issuable_sort_option_title' do
|
|
||||||
it 'returns correct title for issuable_sort_option_overrides key' do
|
|
||||||
expect(issuable_sort_option_title('created_asc')).to eq('Created date')
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns correct title for a valid sort value' do
|
|
||||||
expect(issuable_sort_option_title('priority')).to eq('Priority')
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns nil for invalid sort value' do
|
|
||||||
expect(issuable_sort_option_title('invalid_key')).to eq(nil)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe '#issuable_sort_direction_button' do
|
describe '#issuable_sort_direction_button' do
|
||||||
before do
|
before do
|
||||||
set_sorting_url 'test_label'
|
set_sorting_url 'test_label'
|
||||||
|
@ -209,17 +195,6 @@ RSpec.describe SortingHelper do
|
||||||
stub_controller_path 'forks'
|
stub_controller_path 'forks'
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#forks_sort_options_hash' do
|
|
||||||
it 'returns a hash of available sorting options' do
|
|
||||||
expect(forks_sort_options_hash).to include({
|
|
||||||
sort_value_recently_created => sort_title_created_date,
|
|
||||||
sort_value_oldest_created => sort_title_created_date,
|
|
||||||
sort_value_latest_activity => sort_title_latest_activity,
|
|
||||||
sort_value_oldest_activity => sort_title_latest_activity
|
|
||||||
})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe '#forks_reverse_sort_options_hash' do
|
describe '#forks_reverse_sort_options_hash' do
|
||||||
context 'for each sort option' do
|
context 'for each sort option' do
|
||||||
using RSpec::Parameterized::TableSyntax
|
using RSpec::Parameterized::TableSyntax
|
||||||
|
|
|
@ -61,4 +61,32 @@ RSpec.describe API::Entities::BasicProjectDetails, feature_category: :api do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#repository_storage' do
|
||||||
|
let_it_be(:project) { build(:project, :public) }
|
||||||
|
|
||||||
|
context 'with anonymous user' do
|
||||||
|
let_it_be(:current_user) { nil }
|
||||||
|
|
||||||
|
it 'is not included' do
|
||||||
|
expect(output).not_to include(:repository_storage)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with normal user' do
|
||||||
|
let_it_be(:current_user) { create(:user) }
|
||||||
|
|
||||||
|
it 'is not included' do
|
||||||
|
expect(output).not_to include(:repository_storage)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with admin user' do
|
||||||
|
let_it_be(:current_user) { create(:user, :admin) }
|
||||||
|
|
||||||
|
it 'is included', :enable_admin_mode do
|
||||||
|
expect(output).to include repository_storage: project.repository_storage
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue