Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
a58667ab4b
commit
79a7da2537
|
@ -488,6 +488,11 @@ rspec:coverage:
|
||||||
- rspec unit pg12 minimal
|
- rspec unit pg12 minimal
|
||||||
- rspec integration pg12 minimal
|
- rspec integration pg12 minimal
|
||||||
- rspec system pg12 minimal
|
- rspec system pg12 minimal
|
||||||
|
# FOSS/EE decomposed jobs
|
||||||
|
- rspec migration pg12 decomposed
|
||||||
|
- rspec unit pg12 decomposed
|
||||||
|
- rspec integration pg12 decomposed
|
||||||
|
- rspec system pg12 decomposed
|
||||||
# EE jobs
|
# EE jobs
|
||||||
- rspec-ee migration pg12
|
- rspec-ee migration pg12
|
||||||
- rspec-ee unit pg12
|
- rspec-ee unit pg12
|
||||||
|
@ -498,6 +503,11 @@ rspec:coverage:
|
||||||
- rspec-ee unit pg12 minimal
|
- rspec-ee unit pg12 minimal
|
||||||
- rspec-ee integration pg12 minimal
|
- rspec-ee integration pg12 minimal
|
||||||
- rspec-ee system pg12 minimal
|
- rspec-ee system pg12 minimal
|
||||||
|
# EE decomposed jobs
|
||||||
|
- rspec-ee migration pg12 decomposed
|
||||||
|
- rspec-ee unit pg12 decomposed
|
||||||
|
- rspec-ee integration pg12 decomposed
|
||||||
|
- rspec-ee system pg12 decomposed
|
||||||
# Geo jobs
|
# Geo jobs
|
||||||
- rspec-ee unit pg12 geo
|
- rspec-ee unit pg12 geo
|
||||||
- rspec-ee integration pg12 geo
|
- rspec-ee integration pg12 geo
|
||||||
|
|
|
@ -289,17 +289,6 @@ Performance/DeleteSuffix:
|
||||||
- 'ee/app/models/geo/upload_registry.rb'
|
- 'ee/app/models/geo/upload_registry.rb'
|
||||||
- 'ee/app/workers/geo/file_download_dispatch_worker/attachment_job_finder.rb'
|
- 'ee/app/workers/geo/file_download_dispatch_worker/attachment_job_finder.rb'
|
||||||
|
|
||||||
# Offense count: 13
|
|
||||||
# Cop supports --auto-correct.
|
|
||||||
Performance/Detect:
|
|
||||||
Exclude:
|
|
||||||
- 'ee/spec/controllers/projects/dependencies_controller_spec.rb'
|
|
||||||
- 'ee/spec/requests/api/dependencies_spec.rb'
|
|
||||||
- 'qa/qa/runtime/feature.rb'
|
|
||||||
- 'spec/lib/gitlab/git/tree_spec.rb'
|
|
||||||
- 'spec/lib/gitlab/import_export/project/tree_restorer_spec.rb'
|
|
||||||
- 'spec/models/event_spec.rb'
|
|
||||||
|
|
||||||
# Offense count: 121
|
# Offense count: 121
|
||||||
Performance/MethodObjectAsBlock:
|
Performance/MethodObjectAsBlock:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
@ -827,11 +816,6 @@ Style/RescueModifier:
|
||||||
Style/SingleArgumentDig:
|
Style/SingleArgumentDig:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Offense count: 45
|
|
||||||
# Cop supports --auto-correct.
|
|
||||||
Style/SlicingWithRange:
|
|
||||||
Enabled: false
|
|
||||||
|
|
||||||
# Offense count: 63
|
# Offense count: 63
|
||||||
# Configuration parameters: AllowModifier.
|
# Configuration parameters: AllowModifier.
|
||||||
Style/SoleNestedConditional:
|
Style/SoleNestedConditional:
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
125f0fc0e49db4dd46f2e905f34178ce880dd79e
|
0e0aeb5ca4488903f41acd392911bd89d1ad3d6d
|
||||||
|
|
|
@ -314,9 +314,8 @@ export default {
|
||||||
variables: { importRequests },
|
variables: { importRequests },
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const message = error?.networkError?.response?.data?.error ?? i18n.ERROR_IMPORT;
|
|
||||||
createFlash({
|
createFlash({
|
||||||
message,
|
message: i18n.ERROR_IMPORT,
|
||||||
captureError: true,
|
captureError: true,
|
||||||
error,
|
error,
|
||||||
});
|
});
|
||||||
|
|
|
@ -32,72 +32,84 @@ export default {
|
||||||
fullPath() {
|
fullPath() {
|
||||||
return this.group.importTarget.targetNamespace.fullPath || s__('BulkImport|No parent');
|
return this.group.importTarget.targetNamespace.fullPath || s__('BulkImport|No parent');
|
||||||
},
|
},
|
||||||
invalidNameValidationMessage() {
|
validationMessage() {
|
||||||
return getInvalidNameValidationMessage(this.group.importTarget);
|
return (
|
||||||
|
this.group.progress?.message || getInvalidNameValidationMessage(this.group.importTarget)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
validNameState() {
|
||||||
|
// bootstrap-vue requires null for "indifferent" state, if we return true
|
||||||
|
// this will highlight field in green like "passed validation"
|
||||||
|
return this.group.flags.isInvalid && this.group.flags.isAvailableForImport ? false : null;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="gl-display-flex gl-align-items-stretch">
|
<div>
|
||||||
<import-group-dropdown
|
<div class="gl-display-flex gl-align-items-stretch">
|
||||||
#default="{ namespaces }"
|
<import-group-dropdown
|
||||||
:text="fullPath"
|
#default="{ namespaces }"
|
||||||
:disabled="!group.flags.isAvailableForImport"
|
:text="fullPath"
|
||||||
:namespaces="availableNamespaces"
|
|
||||||
toggle-class="gl-rounded-top-right-none! gl-rounded-bottom-right-none!"
|
|
||||||
class="gl-h-7 gl-flex-grow-1"
|
|
||||||
data-qa-selector="target_namespace_selector_dropdown"
|
|
||||||
>
|
|
||||||
<gl-dropdown-item @click="$emit('update-target-namespace', { fullPath: '', id: null })">{{
|
|
||||||
s__('BulkImport|No parent')
|
|
||||||
}}</gl-dropdown-item>
|
|
||||||
<template v-if="namespaces.length">
|
|
||||||
<gl-dropdown-divider />
|
|
||||||
<gl-dropdown-section-header>
|
|
||||||
{{ s__('BulkImport|Existing groups') }}
|
|
||||||
</gl-dropdown-section-header>
|
|
||||||
<gl-dropdown-item
|
|
||||||
v-for="ns in namespaces"
|
|
||||||
:key="ns.fullPath"
|
|
||||||
data-qa-selector="target_group_dropdown_item"
|
|
||||||
:data-qa-group-name="ns.fullPath"
|
|
||||||
@click="$emit('update-target-namespace', ns)"
|
|
||||||
>
|
|
||||||
{{ ns.fullPath }}
|
|
||||||
</gl-dropdown-item>
|
|
||||||
</template>
|
|
||||||
</import-group-dropdown>
|
|
||||||
<div
|
|
||||||
class="gl-h-7 gl-px-3 gl-display-flex gl-align-items-center gl-border-solid gl-border-0 gl-border-t-1 gl-border-b-1 gl-bg-gray-10"
|
|
||||||
:class="{
|
|
||||||
'gl-text-gray-400 gl-border-gray-100': !group.flags.isAvailableForImport,
|
|
||||||
'gl-border-gray-200': group.flags.isAvailableForImport,
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
/
|
|
||||||
</div>
|
|
||||||
<div class="gl-flex-grow-1">
|
|
||||||
<gl-form-input
|
|
||||||
class="gl-rounded-top-left-none gl-rounded-bottom-left-none"
|
|
||||||
:class="{
|
|
||||||
'gl-inset-border-1-gray-200!': group.flags.isAvailableForImport,
|
|
||||||
'gl-inset-border-1-gray-100!': !group.flags.isAvailableForImport,
|
|
||||||
'is-invalid': group.flags.isInvalid && group.flags.isAvailableForImport,
|
|
||||||
}"
|
|
||||||
debounce="500"
|
|
||||||
:disabled="!group.flags.isAvailableForImport"
|
:disabled="!group.flags.isAvailableForImport"
|
||||||
:value="group.importTarget.newName"
|
:namespaces="availableNamespaces"
|
||||||
:aria-label="__('New name')"
|
toggle-class="gl-rounded-top-right-none! gl-rounded-bottom-right-none!"
|
||||||
@input="$emit('update-new-name', $event)"
|
class="gl-h-7 gl-flex-grow-1"
|
||||||
/>
|
data-qa-selector="target_namespace_selector_dropdown"
|
||||||
<p
|
|
||||||
v-if="group.flags.isAvailableForImport && group.flags.isInvalid"
|
|
||||||
class="gl-text-red-500 gl-m-0 gl-mt-2"
|
|
||||||
>
|
>
|
||||||
{{ invalidNameValidationMessage }}
|
<gl-dropdown-item @click="$emit('update-target-namespace', { fullPath: '', id: null })">{{
|
||||||
</p>
|
s__('BulkImport|No parent')
|
||||||
|
}}</gl-dropdown-item>
|
||||||
|
<template v-if="namespaces.length">
|
||||||
|
<gl-dropdown-divider />
|
||||||
|
<gl-dropdown-section-header>
|
||||||
|
{{ s__('BulkImport|Existing groups') }}
|
||||||
|
</gl-dropdown-section-header>
|
||||||
|
<gl-dropdown-item
|
||||||
|
v-for="ns in namespaces"
|
||||||
|
:key="ns.fullPath"
|
||||||
|
data-qa-selector="target_group_dropdown_item"
|
||||||
|
:data-qa-group-name="ns.fullPath"
|
||||||
|
@click="$emit('update-target-namespace', ns)"
|
||||||
|
>
|
||||||
|
{{ ns.fullPath }}
|
||||||
|
</gl-dropdown-item>
|
||||||
|
</template>
|
||||||
|
</import-group-dropdown>
|
||||||
|
<div
|
||||||
|
class="gl-h-7 gl-px-3 gl-display-flex gl-align-items-center gl-border-solid gl-border-0 gl-border-t-1 gl-border-b-1 gl-bg-gray-10"
|
||||||
|
:class="{
|
||||||
|
'gl-text-gray-400 gl-border-gray-100': !group.flags.isAvailableForImport,
|
||||||
|
'gl-border-gray-200': group.flags.isAvailableForImport,
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
/
|
||||||
|
</div>
|
||||||
|
<div class="gl-flex-grow-1">
|
||||||
|
<gl-form-input
|
||||||
|
class="gl-rounded-top-left-none gl-rounded-bottom-left-none"
|
||||||
|
:class="{
|
||||||
|
'gl-inset-border-1-gray-200!':
|
||||||
|
group.flags.isAvailableForImport && !group.flags.isInvalid,
|
||||||
|
'gl-inset-border-1-gray-100!':
|
||||||
|
!group.flags.isAvailableForImport && !group.flags.isInvalid,
|
||||||
|
}"
|
||||||
|
debounce="500"
|
||||||
|
:disabled="!group.flags.isAvailableForImport"
|
||||||
|
:value="group.importTarget.newName"
|
||||||
|
:aria-label="__('New name')"
|
||||||
|
:state="validNameState"
|
||||||
|
@input="$emit('update-new-name', $event)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="group.flags.isAvailableForImport && (group.flags.isInvalid || validationMessage)"
|
||||||
|
class="gl-text-red-500 gl-m-0 gl-mt-2"
|
||||||
|
role="alert"
|
||||||
|
>
|
||||||
|
{{ validationMessage }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -142,9 +142,7 @@ export function createResolvers({ endpoints }) {
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
const {
|
const { data: originalResponse } = await axios.post(endpoints.createBulkImport, {
|
||||||
data: { id: jobId },
|
|
||||||
} = await axios.post(endpoints.createBulkImport, {
|
|
||||||
bulk_import: importOperations.map((op) => ({
|
bulk_import: importOperations.map((op) => ({
|
||||||
source_type: 'group_entity',
|
source_type: 'group_entity',
|
||||||
source_full_path: op.group.fullPath,
|
source_full_path: op.group.fullPath,
|
||||||
|
@ -153,15 +151,21 @@ export function createResolvers({ endpoints }) {
|
||||||
})),
|
})),
|
||||||
});
|
});
|
||||||
|
|
||||||
return importOperations.map((op) => {
|
const responses = Array.isArray(originalResponse)
|
||||||
|
? originalResponse
|
||||||
|
: [{ success: true, id: originalResponse.id }];
|
||||||
|
|
||||||
|
return importOperations.map((op, idx) => {
|
||||||
|
const response = responses[idx];
|
||||||
const lastImportTarget = {
|
const lastImportTarget = {
|
||||||
targetNamespace: op.targetNamespace,
|
targetNamespace: op.targetNamespace,
|
||||||
newName: op.newName,
|
newName: op.newName,
|
||||||
};
|
};
|
||||||
|
|
||||||
const progress = {
|
const progress = {
|
||||||
id: jobId,
|
id: response.id || `local-${Date.now()}-${idx}`,
|
||||||
status: STATUSES.CREATED,
|
status: response.success ? STATUSES.CREATED : STATUSES.FAILED,
|
||||||
|
message: response.message || null,
|
||||||
};
|
};
|
||||||
|
|
||||||
localStorageCache.set(op.group.webUrl, { progress, lastImportTarget });
|
localStorageCache.set(op.group.webUrl, { progress, lastImportTarget });
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
fragment BulkImportSourceGroupProgress on ClientBulkImportProgress {
|
fragment BulkImportSourceGroupProgress on ClientBulkImportProgress {
|
||||||
id
|
id
|
||||||
status
|
status
|
||||||
|
message
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ mutation importGroups($importRequests: [ImportGroupInput!]!) {
|
||||||
progress {
|
progress {
|
||||||
id
|
id
|
||||||
status
|
status
|
||||||
|
message
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,14 @@ export class LocalStorageCache {
|
||||||
|
|
||||||
loadCacheFromStorage() {
|
loadCacheFromStorage() {
|
||||||
try {
|
try {
|
||||||
return JSON.parse(this.storage.getItem(KEY)) ?? {};
|
const storage = JSON.parse(this.storage.getItem(KEY)) ?? {};
|
||||||
|
Object.values(storage).forEach((entry) => {
|
||||||
|
if (entry.progress && !('message' in entry.progress)) {
|
||||||
|
// eslint-disable-next-line no-param-reassign
|
||||||
|
entry.progress.message = '';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return storage;
|
||||||
} catch {
|
} catch {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ type ClientBulkImportSourceGroupConnection {
|
||||||
type ClientBulkImportProgress {
|
type ClientBulkImportProgress {
|
||||||
id: ID!
|
id: ID!
|
||||||
status: String!
|
status: String!
|
||||||
|
message: String
|
||||||
}
|
}
|
||||||
|
|
||||||
type ClientBulkImportValidationError {
|
type ClientBulkImportValidationError {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { s__, __ } from '~/locale';
|
import { s__, __ } from '~/locale';
|
||||||
|
import { helpPagePath } from '~/helpers/help_page_helper';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
DELETE_PACKAGE_TRACKING_ACTION,
|
DELETE_PACKAGE_TRACKING_ACTION,
|
||||||
|
@ -136,3 +137,8 @@ export const PACKAGE_TYPES = [
|
||||||
s__('PackageRegistry|Debian'),
|
s__('PackageRegistry|Debian'),
|
||||||
s__('PackageRegistry|Helm'),
|
s__('PackageRegistry|Helm'),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// links
|
||||||
|
|
||||||
|
export const EMPTY_LIST_HELP_URL = helpPagePath('user/packages/package_registry/index');
|
||||||
|
export const PACKAGE_HELP_URL = helpPagePath('user/packages/index');
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
import Vue from 'vue';
|
||||||
|
import Translate from '~/vue_shared/translate';
|
||||||
|
import { apolloProvider } from '~/packages_and_registries/package_registry/graphql/index';
|
||||||
|
import PackageRegistry from '~/packages_and_registries/package_registry/pages/index.vue';
|
||||||
|
import createRouter from './router';
|
||||||
|
|
||||||
|
Vue.use(Translate);
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
const el = document.getElementById('js-vue-packages-list');
|
||||||
|
const { endpoint, resourceId, fullPath, pageType, emptyListIllustration } = el.dataset;
|
||||||
|
const router = createRouter(endpoint);
|
||||||
|
|
||||||
|
const isGroupPage = pageType === 'groups';
|
||||||
|
|
||||||
|
return new Vue({
|
||||||
|
el,
|
||||||
|
router,
|
||||||
|
apolloProvider,
|
||||||
|
provide: {
|
||||||
|
resourceId,
|
||||||
|
fullPath,
|
||||||
|
emptyListIllustration,
|
||||||
|
isGroupPage,
|
||||||
|
},
|
||||||
|
render(createElement) {
|
||||||
|
return createElement(PackageRegistry);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
|
@ -0,0 +1,5 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<router-view />
|
||||||
|
</div>
|
||||||
|
</template>
|
|
@ -1,24 +0,0 @@
|
||||||
import Vue from 'vue';
|
|
||||||
import Translate from '~/vue_shared/translate';
|
|
||||||
import { apolloProvider } from '~/packages_and_registries/package_registry/graphql/index';
|
|
||||||
import PackagesListApp from '../components/list/app.vue';
|
|
||||||
|
|
||||||
Vue.use(Translate);
|
|
||||||
|
|
||||||
export default () => {
|
|
||||||
const el = document.getElementById('js-vue-packages-list');
|
|
||||||
|
|
||||||
const isGroupPage = el.dataset.pageType === 'groups';
|
|
||||||
|
|
||||||
return new Vue({
|
|
||||||
el,
|
|
||||||
apolloProvider,
|
|
||||||
provide: {
|
|
||||||
...el.dataset,
|
|
||||||
isGroupPage,
|
|
||||||
},
|
|
||||||
render(createElement) {
|
|
||||||
return createElement(PackagesListApp);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
|
@ -9,13 +9,15 @@ import {
|
||||||
GROUP_RESOURCE_TYPE,
|
GROUP_RESOURCE_TYPE,
|
||||||
GRAPHQL_PAGE_SIZE,
|
GRAPHQL_PAGE_SIZE,
|
||||||
DELETE_PACKAGE_SUCCESS_MESSAGE,
|
DELETE_PACKAGE_SUCCESS_MESSAGE,
|
||||||
|
EMPTY_LIST_HELP_URL,
|
||||||
|
PACKAGE_HELP_URL,
|
||||||
} from '~/packages_and_registries/package_registry/constants';
|
} from '~/packages_and_registries/package_registry/constants';
|
||||||
import getPackagesQuery from '~/packages_and_registries/package_registry/graphql/queries/get_packages.query.graphql';
|
import getPackagesQuery from '~/packages_and_registries/package_registry/graphql/queries/get_packages.query.graphql';
|
||||||
|
|
||||||
import DeletePackage from '~/packages_and_registries/package_registry/components/functional/delete_package.vue';
|
import DeletePackage from '~/packages_and_registries/package_registry/components/functional/delete_package.vue';
|
||||||
import PackageTitle from './package_title.vue';
|
import PackageTitle from '~/packages_and_registries/package_registry/components/list/package_title.vue';
|
||||||
import PackageSearch from './package_search.vue';
|
import PackageSearch from '~/packages_and_registries/package_registry/components/list/package_search.vue';
|
||||||
import PackageList from './packages_list.vue';
|
import PackageList from '~/packages_and_registries/package_registry/components/list/packages_list.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
@ -27,13 +29,7 @@ export default {
|
||||||
PackageSearch,
|
PackageSearch,
|
||||||
DeletePackage,
|
DeletePackage,
|
||||||
},
|
},
|
||||||
inject: [
|
inject: ['emptyListIllustration', 'isGroupPage', 'fullPath'],
|
||||||
'packageHelpUrl',
|
|
||||||
'emptyListIllustration',
|
|
||||||
'emptyListHelpUrl',
|
|
||||||
'isGroupPage',
|
|
||||||
'fullPath',
|
|
||||||
],
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
packages: {},
|
packages: {},
|
||||||
|
@ -156,12 +152,16 @@ export default {
|
||||||
'PackageRegistry|Learn how to %{noPackagesLinkStart}publish and share your packages%{noPackagesLinkEnd} with GitLab.',
|
'PackageRegistry|Learn how to %{noPackagesLinkStart}publish and share your packages%{noPackagesLinkEnd} with GitLab.',
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
links: {
|
||||||
|
EMPTY_LIST_HELP_URL,
|
||||||
|
PACKAGE_HELP_URL,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<package-title :help-url="packageHelpUrl" :count="packagesCount" />
|
<package-title :help-url="$options.links.PACKAGE_HELP_URL" :count="packagesCount" />
|
||||||
<package-search @update="handleSearchUpdate" />
|
<package-search @update="handleSearchUpdate" />
|
||||||
|
|
||||||
<delete-package
|
<delete-package
|
||||||
|
@ -185,7 +185,9 @@ export default {
|
||||||
<gl-sprintf v-if="hasFilters" :message="$options.i18n.widenFilters" />
|
<gl-sprintf v-if="hasFilters" :message="$options.i18n.widenFilters" />
|
||||||
<gl-sprintf v-else :message="$options.i18n.noResultsText">
|
<gl-sprintf v-else :message="$options.i18n.noResultsText">
|
||||||
<template #noPackagesLink="{ content }">
|
<template #noPackagesLink="{ content }">
|
||||||
<gl-link :href="emptyListHelpUrl" target="_blank">{{ content }}</gl-link>
|
<gl-link :href="$options.links.EMPTY_LIST_HELP_URL" target="_blank">{{
|
||||||
|
content
|
||||||
|
}}</gl-link>
|
||||||
</template>
|
</template>
|
||||||
</gl-sprintf>
|
</gl-sprintf>
|
||||||
</template>
|
</template>
|
|
@ -0,0 +1,21 @@
|
||||||
|
import Vue from 'vue';
|
||||||
|
import VueRouter from 'vue-router';
|
||||||
|
import List from '~/packages_and_registries/package_registry/pages/list.vue';
|
||||||
|
|
||||||
|
Vue.use(VueRouter);
|
||||||
|
|
||||||
|
export default function createRouter(base) {
|
||||||
|
const router = new VueRouter({
|
||||||
|
base,
|
||||||
|
mode: 'history',
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
name: 'list',
|
||||||
|
path: '/',
|
||||||
|
component: List,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
return router;
|
||||||
|
}
|
|
@ -1,3 +1,3 @@
|
||||||
import packageList from '~/packages_and_registries/package_registry/pages/list';
|
import packageApp from '~/packages_and_registries/package_registry/index';
|
||||||
|
|
||||||
packageList();
|
packageApp();
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
import packageList from '~/packages_and_registries/package_registry/pages/list';
|
import packageApp from '~/packages_and_registries/package_registry/index';
|
||||||
|
|
||||||
packageList();
|
packageApp();
|
||||||
|
|
|
@ -165,6 +165,6 @@ export default {
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="flash-container js-suggestions-flash"></div>
|
<div class="flash-container js-suggestions-flash"></div>
|
||||||
<div v-show="isRendered" ref="container" v-safe-html="noteHtml" class="md"></div>
|
<div v-show="isRendered" ref="container" v-safe-html="noteHtml" class="md suggestions"></div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -139,6 +139,10 @@
|
||||||
font-family: $monospace-font !important;
|
font-family: $monospace-font !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.suggestions.md > .markdown-code-block {
|
||||||
|
@include gl-static;
|
||||||
|
}
|
||||||
|
|
||||||
.md-suggestion-header {
|
.md-suggestion-header {
|
||||||
height: $suggestion-header-height;
|
height: $suggestion-header-height;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
|
@ -40,13 +40,9 @@ class Import::BulkImportsController < ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
response = ::BulkImports::CreateService.new(current_user, create_params, credentials).execute
|
responses = create_params.map { |entry| ::BulkImports::CreateService.new(current_user, entry, credentials).execute }
|
||||||
|
|
||||||
if response.success?
|
render json: responses.map { |response| { success: response.success?, id: response.payload[:id], message: response.message } }
|
||||||
render json: response.payload.to_json(only: [:id])
|
|
||||||
else
|
|
||||||
render json: { error: response.message }, status: response.http_status
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def realtime_changes
|
def realtime_changes
|
||||||
|
|
|
@ -99,7 +99,7 @@ class Projects::BlobController < Projects::ApplicationController
|
||||||
@content = params[:content]
|
@content = params[:content]
|
||||||
@blob.load_all_data!
|
@blob.load_all_data!
|
||||||
diffy = Diffy::Diff.new(@blob.data, @content, diff: '-U 3', include_diff_info: true)
|
diffy = Diffy::Diff.new(@blob.data, @content, diff: '-U 3', include_diff_info: true)
|
||||||
diff_lines = diffy.diff.scan(/.*\n/)[2..-1]
|
diff_lines = diffy.diff.scan(/.*\n/)[2..]
|
||||||
diff_lines = Gitlab::Diff::Parser.new.parse(diff_lines).to_a
|
diff_lines = Gitlab::Diff::Parser.new.parse(diff_lines).to_a
|
||||||
@diff_lines = Gitlab::Diff::Highlight.new(diff_lines, repository: @repository).highlight
|
@diff_lines = Gitlab::Diff::Highlight.new(diff_lines, repository: @repository).highlight
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ module Resolvers
|
||||||
job_types: security_report_types
|
job_types: security_report_types
|
||||||
).execute
|
).execute
|
||||||
else
|
else
|
||||||
pipeline.statuses
|
pipeline.statuses_order_id_desc
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -18,7 +18,7 @@ module Resolvers
|
||||||
|
|
||||||
def preloads
|
def preloads
|
||||||
{
|
{
|
||||||
jobs: { statuses: [:needs] },
|
jobs: { statuses_order_id_desc: [:needs] },
|
||||||
upstream: [:triggered_by_pipeline],
|
upstream: [:triggered_by_pipeline],
|
||||||
downstream: [:triggered_pipelines]
|
downstream: [:triggered_pipelines]
|
||||||
}
|
}
|
||||||
|
|
|
@ -283,7 +283,7 @@ module DiffHelper
|
||||||
|
|
||||||
return path unless path.size > max && max > 3
|
return path unless path.size > max && max > 3
|
||||||
|
|
||||||
"...#{path[-(max - 3)..-1]}"
|
"...#{path[-(max - 3)..]}"
|
||||||
end
|
end
|
||||||
|
|
||||||
def code_navigation_path(diffs)
|
def code_navigation_path(diffs)
|
||||||
|
|
|
@ -38,17 +38,6 @@ module PackagesHelper
|
||||||
"#{Gitlab.config.gitlab.host}/#{group_id}"
|
"#{Gitlab.config.gitlab.host}/#{group_id}"
|
||||||
end
|
end
|
||||||
|
|
||||||
def packages_list_data(type, resource)
|
|
||||||
{
|
|
||||||
resource_id: resource.id,
|
|
||||||
full_path: resource.full_path,
|
|
||||||
page_type: type,
|
|
||||||
empty_list_help_url: help_page_path('user/packages/package_registry/index'),
|
|
||||||
empty_list_illustration: image_path('illustrations/no-packages.svg'),
|
|
||||||
package_help_url: help_page_path('user/packages/index')
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
def track_package_event(event_name, scope, **args)
|
def track_package_event(event_name, scope, **args)
|
||||||
::Packages::CreateEventService.new(nil, current_user, event_name: event_name, scope: scope).execute
|
::Packages::CreateEventService.new(nil, current_user, event_name: event_name, scope: scope).execute
|
||||||
category = args.delete(:category) || self.class.name
|
category = args.delete(:category) || self.class.name
|
||||||
|
|
|
@ -63,6 +63,7 @@ module Ci
|
||||||
has_many :statuses, class_name: 'CommitStatus', foreign_key: :commit_id, inverse_of: :pipeline
|
has_many :statuses, class_name: 'CommitStatus', foreign_key: :commit_id, inverse_of: :pipeline
|
||||||
has_many :latest_statuses_ordered_by_stage, -> { latest.order(:stage_idx, :stage) }, class_name: 'CommitStatus', foreign_key: :commit_id, inverse_of: :pipeline
|
has_many :latest_statuses_ordered_by_stage, -> { latest.order(:stage_idx, :stage) }, class_name: 'CommitStatus', foreign_key: :commit_id, inverse_of: :pipeline
|
||||||
has_many :latest_statuses, -> { latest }, class_name: 'CommitStatus', foreign_key: :commit_id, inverse_of: :pipeline
|
has_many :latest_statuses, -> { latest }, class_name: 'CommitStatus', foreign_key: :commit_id, inverse_of: :pipeline
|
||||||
|
has_many :statuses_order_id_desc, -> { order_id_desc }, class_name: 'CommitStatus', foreign_key: :commit_id
|
||||||
has_many :processables, class_name: 'Ci::Processable', foreign_key: :commit_id, inverse_of: :pipeline
|
has_many :processables, class_name: 'Ci::Processable', foreign_key: :commit_id, inverse_of: :pipeline
|
||||||
has_many :bridges, class_name: 'Ci::Bridge', foreign_key: :commit_id, inverse_of: :pipeline
|
has_many :bridges, class_name: 'Ci::Bridge', foreign_key: :commit_id, inverse_of: :pipeline
|
||||||
has_many :builds, foreign_key: :commit_id, inverse_of: :pipeline
|
has_many :builds, foreign_key: :commit_id, inverse_of: :pipeline
|
||||||
|
|
|
@ -11,7 +11,7 @@ module TokenAuthenticatableStrategies
|
||||||
# The pattern of the token is "#{DYNAMIC_NONCE_IDENTIFIER}#{token}#{iv_of_12_characters}"
|
# The pattern of the token is "#{DYNAMIC_NONCE_IDENTIFIER}#{token}#{iv_of_12_characters}"
|
||||||
if token.start_with?(DYNAMIC_NONCE_IDENTIFIER) && token.size > NONCE_SIZE + DYNAMIC_NONCE_IDENTIFIER.size
|
if token.start_with?(DYNAMIC_NONCE_IDENTIFIER) && token.size > NONCE_SIZE + DYNAMIC_NONCE_IDENTIFIER.size
|
||||||
token_to_decrypt = token[1...-NONCE_SIZE]
|
token_to_decrypt = token[1...-NONCE_SIZE]
|
||||||
iv = token[-NONCE_SIZE..-1]
|
iv = token[-NONCE_SIZE..]
|
||||||
|
|
||||||
Gitlab::CryptoHelper.aes256_gcm_decrypt(token_to_decrypt, nonce: iv)
|
Gitlab::CryptoHelper.aes256_gcm_decrypt(token_to_decrypt, nonce: iv)
|
||||||
else
|
else
|
||||||
|
|
|
@ -31,10 +31,6 @@ class ProjectHook < WebHook
|
||||||
_('Webhooks')
|
_('Webhooks')
|
||||||
end
|
end
|
||||||
|
|
||||||
def web_hooks_disable_failed?
|
|
||||||
Feature.enabled?(:web_hooks_disable_failed, project)
|
|
||||||
end
|
|
||||||
|
|
||||||
override :rate_limit
|
override :rate_limit
|
||||||
def rate_limit
|
def rate_limit
|
||||||
project.actual_limits.limit_for(:web_hook_calls)
|
project.actual_limits.limit_for(:web_hook_calls)
|
||||||
|
@ -44,6 +40,13 @@ class ProjectHook < WebHook
|
||||||
def application_context
|
def application_context
|
||||||
super.merge(project: project)
|
super.merge(project: project)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
override :web_hooks_disable_failed?
|
||||||
|
def web_hooks_disable_failed?
|
||||||
|
Feature.enabled?(:web_hooks_disable_failed, project)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
ProjectHook.prepend_mod_with('ProjectHook')
|
ProjectHook.prepend_mod_with('ProjectHook')
|
||||||
|
|
|
@ -34,9 +34,19 @@ class WebHook < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def executable?
|
def executable?
|
||||||
return true unless web_hooks_disable_failed?
|
!temporarily_disabled? && !permanently_disabled?
|
||||||
|
end
|
||||||
|
|
||||||
recent_failures <= FAILURE_THRESHOLD && (disabled_until.nil? || disabled_until < Time.current)
|
def temporarily_disabled?
|
||||||
|
return false unless web_hooks_disable_failed?
|
||||||
|
|
||||||
|
disabled_until.present? && disabled_until >= Time.current
|
||||||
|
end
|
||||||
|
|
||||||
|
def permanently_disabled?
|
||||||
|
return false unless web_hooks_disable_failed?
|
||||||
|
|
||||||
|
recent_failures > FAILURE_THRESHOLD
|
||||||
end
|
end
|
||||||
|
|
||||||
# rubocop: disable CodeReuse/ServiceClass
|
# rubocop: disable CodeReuse/ServiceClass
|
||||||
|
@ -69,6 +79,8 @@ class WebHook < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def disable!
|
def disable!
|
||||||
|
return if permanently_disabled?
|
||||||
|
|
||||||
update_attribute(:recent_failures, FAILURE_THRESHOLD + 1)
|
update_attribute(:recent_failures, FAILURE_THRESHOLD + 1)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -80,7 +92,7 @@ class WebHook < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def backoff!
|
def backoff!
|
||||||
return if backoff_count >= MAX_FAILURES && disabled_until && disabled_until > Time.current
|
return if permanently_disabled? || (backoff_count >= MAX_FAILURES && temporarily_disabled?)
|
||||||
|
|
||||||
assign_attributes(disabled_until: next_backoff.from_now, backoff_count: backoff_count.succ.clamp(0, MAX_FAILURES))
|
assign_attributes(disabled_until: next_backoff.from_now, backoff_count: backoff_count.succ.clamp(0, MAX_FAILURES))
|
||||||
save(validate: false)
|
save(validate: false)
|
||||||
|
@ -93,7 +105,19 @@ class WebHook < ApplicationRecord
|
||||||
save(validate: false)
|
save(validate: false)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Overridden in ProjectHook and GroupHook, other webhooks are not rate-limited.
|
# @return [Boolean] Whether or not the WebHook is currently throttled.
|
||||||
|
def rate_limited?
|
||||||
|
return false unless rate_limit
|
||||||
|
|
||||||
|
Gitlab::ApplicationRateLimiter.peek(
|
||||||
|
:web_hook_calls,
|
||||||
|
scope: [self],
|
||||||
|
threshold: rate_limit
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Threshold for the rate-limit.
|
||||||
|
# Overridden in ProjectHook and GroupHook, other WebHooks are not rate-limited.
|
||||||
def rate_limit
|
def rate_limit
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
|
|
|
@ -204,7 +204,7 @@ module Namespaces
|
||||||
end
|
end
|
||||||
|
|
||||||
if bottom
|
if bottom
|
||||||
skope = skope.where(id: bottom.traversal_ids[0..-1])
|
skope = skope.where(id: bottom.traversal_ids)
|
||||||
end
|
end
|
||||||
|
|
||||||
# The original `with_depth` attribute in ObjectHierarchy increments as you
|
# The original `with_depth` attribute in ObjectHierarchy increments as you
|
||||||
|
|
|
@ -37,7 +37,7 @@ module Serverless
|
||||||
'a1',
|
'a1',
|
||||||
serverless_domain_cluster.uuid[2..-3],
|
serverless_domain_cluster.uuid[2..-3],
|
||||||
'f2',
|
'f2',
|
||||||
serverless_domain_cluster.uuid[-2..-1]
|
serverless_domain_cluster.uuid[-2..]
|
||||||
].join
|
].join
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -338,7 +338,7 @@ class WikiPage
|
||||||
current_dirname = File.dirname(title)
|
current_dirname = File.dirname(title)
|
||||||
|
|
||||||
if persisted?
|
if persisted?
|
||||||
return title[1..-1] if current_dirname == '/'
|
return title[1..] if current_dirname == '/'
|
||||||
return File.join([directory.presence, title].compact) if current_dirname == '.'
|
return File.join([directory.presence, title].compact) if current_dirname == '.'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -59,7 +59,7 @@ module BulkImports
|
||||||
)
|
)
|
||||||
bulk_import.create_configuration!(credentials.slice(:url, :access_token))
|
bulk_import.create_configuration!(credentials.slice(:url, :access_token))
|
||||||
|
|
||||||
params.each do |entity|
|
Array.wrap(params).each do |entity|
|
||||||
BulkImports::Entity.create!(
|
BulkImports::Entity.create!(
|
||||||
bulk_import: bulk_import,
|
bulk_import: bulk_import,
|
||||||
source_type: entity[:source_type],
|
source_type: entity[:source_type],
|
||||||
|
|
|
@ -38,7 +38,7 @@ class CohortsService
|
||||||
|
|
||||||
{
|
{
|
||||||
registration_month: registration_month,
|
registration_month: registration_month,
|
||||||
activity_months: activity_months[1..-1],
|
activity_months: activity_months[1..],
|
||||||
total: activity_months.first[:total],
|
total: activity_months.first[:total],
|
||||||
inactive: inactive
|
inactive: inactive
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ class LfsObjectUploader < GitlabUploader
|
||||||
alias_method :upload, :model
|
alias_method :upload, :model
|
||||||
|
|
||||||
def filename
|
def filename
|
||||||
model.oid[4..-1]
|
model.oid[4..]
|
||||||
end
|
end
|
||||||
|
|
||||||
def store_dir
|
def store_dir
|
||||||
|
|
|
@ -3,4 +3,8 @@
|
||||||
|
|
||||||
.row
|
.row
|
||||||
.col-12
|
.col-12
|
||||||
#js-vue-packages-list{ data: packages_list_data('groups', @group) }
|
#js-vue-packages-list{ data: { resource_id: @group.id,
|
||||||
|
full_path: @group.full_path,
|
||||||
|
endpoint: group_packages_path(@group),
|
||||||
|
page_type: 'groups',
|
||||||
|
empty_list_illustration: image_path('illustrations/no-packages.svg'), } }
|
||||||
|
|
|
@ -3,4 +3,8 @@
|
||||||
|
|
||||||
.row
|
.row
|
||||||
.col-12
|
.col-12
|
||||||
#js-vue-packages-list{ data: packages_list_data('projects', @project) }
|
#js-vue-packages-list{ data: { resource_id: @project.id,
|
||||||
|
full_path: @project.full_path,
|
||||||
|
endpoint: project_packages_path(@project),
|
||||||
|
page_type: 'projects',
|
||||||
|
empty_list_illustration: image_path('illustrations/no-packages.svg'), } }
|
||||||
|
|
|
@ -108,7 +108,7 @@ module WikiCloth
|
||||||
"<span class=\"error\">#{I18n.t('template loop detected', :tree => debug_tree)}</span>"
|
"<span class=\"error\">#{I18n.t('template loop detected', :tree => debug_tree)}</span>"
|
||||||
else
|
else
|
||||||
key = params[0].to_s.strip
|
key = params[0].to_s.strip
|
||||||
key_options = params[1..-1].collect { |p| p.is_a?(Hash) ? { :name => p[:name].strip, :value => p[:value].strip } : p.strip }
|
key_options = params[1..].collect { |p| p.is_a?(Hash) ? { :name => p[:name].strip, :value => p[:value].strip } : p.strip }
|
||||||
key_options ||= []
|
key_options ||= []
|
||||||
key_digest = Digest::MD5.hexdigest(key_options.to_a.sort {|x,y| (x.is_a?(Hash) ? x[:name] : x) <=> (y.is_a?(Hash) ? y[:name] : y) }.inspect)
|
key_digest = Digest::MD5.hexdigest(key_options.to_a.sort {|x,y| (x.is_a?(Hash) ? x[:name] : x) <=> (y.is_a?(Hash) ? y[:name] : y) }.inspect)
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ full list of reference architectures, see
|
||||||
|
|
||||||
<!-- Disable ordered list rule https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md029---ordered-list-item-prefix -->
|
<!-- Disable ordered list rule https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md029---ordered-list-item-prefix -->
|
||||||
<!-- markdownlint-disable MD029 -->
|
<!-- markdownlint-disable MD029 -->
|
||||||
1. Can be optionally run on reputable third-party external PaaS PostgreSQL solutions. Google Cloud SQL and Amazon RDS are known to work, however Azure Database for PostgreSQL is [not recommended](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61) due to performance issues. Consul is primarily used for PostgreSQL high availability so can be ignored when using a PostgreSQL PaaS setup. However it is also used optionally by Prometheus for Omnibus auto host discovery.
|
1. Can be optionally run on reputable third-party external PaaS PostgreSQL solutions. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work, however Azure Database for PostgreSQL is **not recommended** due to [performance issues](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61). Consul is primarily used for PostgreSQL high availability so can be ignored when using a PostgreSQL PaaS setup. However it is also used optionally by Prometheus for Omnibus auto host discovery.
|
||||||
2. Can be optionally run on reputable third-party external PaaS Redis solutions. Google Memorystore and AWS Elasticache are known to work.
|
2. Can be optionally run on reputable third-party external PaaS Redis solutions. Google Memorystore and AWS Elasticache are known to work.
|
||||||
3. Can be optionally run on reputable third-party load balancing services (LB PaaS). AWS ELB is known to work.
|
3. Can be optionally run on reputable third-party load balancing services (LB PaaS). AWS ELB is known to work.
|
||||||
4. Should be run on reputable third-party object storage (storage PaaS) for cloud implementations. Google Cloud Storage and AWS S3 are known to work.
|
4. Should be run on reputable third-party object storage (storage PaaS) for cloud implementations. Google Cloud Storage and AWS S3 are known to work.
|
||||||
|
@ -486,8 +486,9 @@ cluster to be used with GitLab.
|
||||||
### Provide your own PostgreSQL instance
|
### Provide your own PostgreSQL instance
|
||||||
|
|
||||||
If you're hosting GitLab on a cloud provider, you can optionally use a
|
If you're hosting GitLab on a cloud provider, you can optionally use a
|
||||||
managed service for PostgreSQL. For example, AWS offers a managed Relational
|
managed service for PostgreSQL.
|
||||||
Database Service (RDS) that runs PostgreSQL.
|
|
||||||
|
A reputable provider or solution should be used for this. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work, however Azure Database for PostgreSQL is **not recommended** due to [performance issues](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61).
|
||||||
|
|
||||||
If you use a cloud-managed service, or provide your own PostgreSQL:
|
If you use a cloud-managed service, or provide your own PostgreSQL:
|
||||||
|
|
||||||
|
@ -1249,6 +1250,15 @@ There are many third-party solutions for PostgreSQL HA. The solution selected mu
|
||||||
- A static IP for all connections that doesn't change on failover.
|
- A static IP for all connections that doesn't change on failover.
|
||||||
- [`LISTEN`](https://www.postgresql.org/docs/12/sql-listen.html) SQL functionality must be supported.
|
- [`LISTEN`](https://www.postgresql.org/docs/12/sql-listen.html) SQL functionality must be supported.
|
||||||
|
|
||||||
|
NOTE:
|
||||||
|
With a third-party setup, it's possible to colocate Praefect's database on the same server as
|
||||||
|
the main [GitLab](#provide-your-own-postgresql-instance) database as a convenience unless
|
||||||
|
you are using Geo, where separate database instances are required for handling replication correctly.
|
||||||
|
In this setup, the specs of the main database setup shouldn't need to be changed as the impact should be
|
||||||
|
minimal.
|
||||||
|
|
||||||
|
A reputable provider or solution should be used for this. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work, however Azure Database for PostgreSQL is **not recommended** due to [performance issues](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61).
|
||||||
|
|
||||||
Examples of the above could include [Google's Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) or [Amazon RDS](https://aws.amazon.com/rds/).
|
Examples of the above could include [Google's Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) or [Amazon RDS](https://aws.amazon.com/rds/).
|
||||||
|
|
||||||
Once the database is set up, follow the [post configuration](#praefect-postgresql-post-configuration).
|
Once the database is set up, follow the [post configuration](#praefect-postgresql-post-configuration).
|
||||||
|
@ -2234,7 +2244,7 @@ services where applicable):
|
||||||
|
|
||||||
<!-- Disable ordered list rule https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md029---ordered-list-item-prefix -->
|
<!-- Disable ordered list rule https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md029---ordered-list-item-prefix -->
|
||||||
<!-- markdownlint-disable MD029 -->
|
<!-- markdownlint-disable MD029 -->
|
||||||
1. Can be optionally run on reputable third-party external PaaS PostgreSQL solutions. Google Cloud SQL and Amazon RDS are known to work, however Azure Database for PostgreSQL is [not recommended](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61) due to performance issues. Consul is primarily used for PostgreSQL high availability so can be ignored when using a PostgreSQL PaaS setup. However it is also used optionally by Prometheus for Omnibus auto host discovery.
|
1. Can be optionally run on reputable third-party external PaaS PostgreSQL solutions. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work, however Azure Database for PostgreSQL is **not recommended** due to [performance issues](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61). Consul is primarily used for PostgreSQL high availability so can be ignored when using a PostgreSQL PaaS setup. However it is also used optionally by Prometheus for Omnibus auto host discovery.
|
||||||
2. Can be optionally run on reputable third-party external PaaS Redis solutions. Google Memorystore and AWS Elasticache are known to work.
|
2. Can be optionally run on reputable third-party external PaaS Redis solutions. Google Memorystore and AWS Elasticache are known to work.
|
||||||
3. Can be optionally run on reputable third-party load balancing services (LB PaaS). AWS ELB is known to work.
|
3. Can be optionally run on reputable third-party load balancing services (LB PaaS). AWS ELB is known to work.
|
||||||
4. Should be run on reputable third-party object storage (storage PaaS) for cloud implementations. Google Cloud Storage and AWS S3 are known to work.
|
4. Should be run on reputable third-party object storage (storage PaaS) for cloud implementations. Google Cloud Storage and AWS S3 are known to work.
|
||||||
|
|
|
@ -37,7 +37,7 @@ full list of reference architectures, see
|
||||||
|
|
||||||
<!-- Disable ordered list rule https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md029---ordered-list-item-prefix -->
|
<!-- Disable ordered list rule https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md029---ordered-list-item-prefix -->
|
||||||
<!-- markdownlint-disable MD029 -->
|
<!-- markdownlint-disable MD029 -->
|
||||||
1. Can be optionally run on reputable third-party external PaaS PostgreSQL solutions. Google Cloud SQL and Amazon RDS are known to work, however Azure Database for PostgreSQL is [not recommended](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61) due to performance issues. Consul is primarily used for PostgreSQL high availability so can be ignored when using a PostgreSQL PaaS setup. However it is also used optionally by Prometheus for Omnibus auto host discovery.
|
1. Can be optionally run on reputable third-party external PaaS PostgreSQL solutions. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work, however Azure Database for PostgreSQL is **not recommended** due to [performance issues](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61). Consul is primarily used for PostgreSQL high availability so can be ignored when using a PostgreSQL PaaS setup. However it is also used optionally by Prometheus for Omnibus auto host discovery.
|
||||||
2. Can be optionally run on reputable third-party external PaaS Redis solutions. Google Memorystore and AWS Elasticache are known to work.
|
2. Can be optionally run on reputable third-party external PaaS Redis solutions. Google Memorystore and AWS Elasticache are known to work.
|
||||||
3. Can be optionally run on reputable third-party load balancing services (LB PaaS). AWS ELB is known to work.
|
3. Can be optionally run on reputable third-party load balancing services (LB PaaS). AWS ELB is known to work.
|
||||||
4. Should be run on reputable third-party object storage (storage PaaS) for cloud implementations. Google Cloud Storage and AWS S3 are known to work.
|
4. Should be run on reputable third-party object storage (storage PaaS) for cloud implementations. Google Cloud Storage and AWS S3 are known to work.
|
||||||
|
@ -489,8 +489,9 @@ cluster to be used with GitLab.
|
||||||
### Provide your own PostgreSQL instance
|
### Provide your own PostgreSQL instance
|
||||||
|
|
||||||
If you're hosting GitLab on a cloud provider, you can optionally use a
|
If you're hosting GitLab on a cloud provider, you can optionally use a
|
||||||
managed service for PostgreSQL. For example, AWS offers a managed Relational
|
managed service for PostgreSQL.
|
||||||
Database Service (RDS) that runs PostgreSQL.
|
|
||||||
|
A reputable provider or solution should be used for this. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work, however Azure Database for PostgreSQL is **not recommended** due to [performance issues](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61).
|
||||||
|
|
||||||
If you use a cloud-managed service, or provide your own PostgreSQL:
|
If you use a cloud-managed service, or provide your own PostgreSQL:
|
||||||
|
|
||||||
|
@ -1255,7 +1256,14 @@ There are many third-party solutions for PostgreSQL HA. The solution selected mu
|
||||||
- A static IP for all connections that doesn't change on failover.
|
- A static IP for all connections that doesn't change on failover.
|
||||||
- [`LISTEN`](https://www.postgresql.org/docs/12/sql-listen.html) SQL functionality must be supported.
|
- [`LISTEN`](https://www.postgresql.org/docs/12/sql-listen.html) SQL functionality must be supported.
|
||||||
|
|
||||||
Examples of the above could include [Google's Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) or [Amazon RDS](https://aws.amazon.com/rds/).
|
NOTE:
|
||||||
|
With a third-party setup, it's possible to colocate Praefect's database on the same server as
|
||||||
|
the main [GitLab](#provide-your-own-postgresql-instance) database as a convenience unless
|
||||||
|
you are using Geo, where separate database instances are required for handling replication correctly.
|
||||||
|
In this setup, the specs of the main database setup shouldn't need to be changed as the impact should be
|
||||||
|
minimal.
|
||||||
|
|
||||||
|
A reputable provider or solution should be used for this. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work, however Azure Database for PostgreSQL is **not recommended** due to [performance issues](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61).
|
||||||
|
|
||||||
Once the database is set up, follow the [post configuration](#praefect-postgresql-post-configuration).
|
Once the database is set up, follow the [post configuration](#praefect-postgresql-post-configuration).
|
||||||
|
|
||||||
|
@ -2234,7 +2242,7 @@ services where applicable):
|
||||||
|
|
||||||
<!-- Disable ordered list rule https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md029---ordered-list-item-prefix -->
|
<!-- Disable ordered list rule https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md029---ordered-list-item-prefix -->
|
||||||
<!-- markdownlint-disable MD029 -->
|
<!-- markdownlint-disable MD029 -->
|
||||||
1. Can be optionally run on reputable third-party external PaaS PostgreSQL solutions. Google Cloud SQL and Amazon RDS are known to work, however Azure Database for PostgreSQL is [not recommended](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61) due to performance issues. Consul is primarily used for PostgreSQL high availability so can be ignored when using a PostgreSQL PaaS setup. However it is also used optionally by Prometheus for Omnibus auto host discovery.
|
1. Can be optionally run on reputable third-party external PaaS PostgreSQL solutions. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work, however Azure Database for PostgreSQL is **not recommended** due to [performance issues](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61). Consul is primarily used for PostgreSQL high availability so can be ignored when using a PostgreSQL PaaS setup. However it is also used optionally by Prometheus for Omnibus auto host discovery.
|
||||||
2. Can be optionally run on reputable third-party external PaaS Redis solutions. Google Memorystore and AWS Elasticache are known to work.
|
2. Can be optionally run on reputable third-party external PaaS Redis solutions. Google Memorystore and AWS Elasticache are known to work.
|
||||||
3. Can be optionally run on reputable third-party load balancing services (LB PaaS). AWS ELB is known to work.
|
3. Can be optionally run on reputable third-party load balancing services (LB PaaS). AWS ELB is known to work.
|
||||||
4. Should be run on reputable third-party object storage (storage PaaS) for cloud implementations. Google Cloud Storage and AWS S3 are known to work.
|
4. Should be run on reputable third-party object storage (storage PaaS) for cloud implementations. Google Cloud Storage and AWS S3 are known to work.
|
||||||
|
|
|
@ -30,7 +30,7 @@ For a full list of reference architectures, see
|
||||||
| NFS server (optional, not recommended) | 1 | 4 vCPU, 3.6 GB memory | `n1-highcpu-4` | `c5.xlarge` | `F4s v2` |
|
| NFS server (optional, not recommended) | 1 | 4 vCPU, 3.6 GB memory | `n1-highcpu-4` | `c5.xlarge` | `F4s v2` |
|
||||||
|
|
||||||
<!-- markdownlint-disable MD029 -->
|
<!-- markdownlint-disable MD029 -->
|
||||||
1. Can be optionally run on reputable third-party external PaaS PostgreSQL solutions. Google Cloud SQL and Amazon RDS are known to work, however Azure Database for PostgreSQL is [not recommended](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61) due to performance issues. Consul is primarily used for PostgreSQL high availability so can be ignored when using a PostgreSQL PaaS setup. However it is also used optionally by Prometheus for Omnibus auto host discovery.
|
1. Can be optionally run on reputable third-party external PaaS PostgreSQL solutions. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work, however Azure Database for PostgreSQL is **not recommended** due to [performance issues](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61). Consul is primarily used for PostgreSQL high availability so can be ignored when using a PostgreSQL PaaS setup. However it is also used optionally by Prometheus for Omnibus auto host discovery.
|
||||||
2. Can be optionally run as reputable third-party external PaaS Redis solutions. Google Memorystore and AWS Elasticache are known to work.
|
2. Can be optionally run as reputable third-party external PaaS Redis solutions. Google Memorystore and AWS Elasticache are known to work.
|
||||||
3. Can be optionally run as reputable third-party load balancing services (LB PaaS). AWS ELB is known to work.
|
3. Can be optionally run as reputable third-party load balancing services (LB PaaS). AWS ELB is known to work.
|
||||||
4. Should be run on reputable third-party object storage (storage PaaS) for cloud implementations. Google Cloud Storage and AWS S3 are known to work.
|
4. Should be run on reputable third-party object storage (storage PaaS) for cloud implementations. Google Cloud Storage and AWS S3 are known to work.
|
||||||
|
@ -233,8 +233,9 @@ to be used with GitLab.
|
||||||
### Provide your own PostgreSQL instance
|
### Provide your own PostgreSQL instance
|
||||||
|
|
||||||
If you're hosting GitLab on a cloud provider, you can optionally use a
|
If you're hosting GitLab on a cloud provider, you can optionally use a
|
||||||
managed service for PostgreSQL. For example, AWS offers a managed relational
|
managed service for PostgreSQL.
|
||||||
database service (RDS) that runs PostgreSQL.
|
|
||||||
|
A reputable provider or solution should be used for this. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work, however Azure Database for PostgreSQL is **not recommended** due to [performance issues](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61).
|
||||||
|
|
||||||
If you use a cloud-managed service, or provide your own PostgreSQL:
|
If you use a cloud-managed service, or provide your own PostgreSQL:
|
||||||
|
|
||||||
|
@ -1028,7 +1029,7 @@ services where applicable):
|
||||||
|
|
||||||
<!-- Disable ordered list rule https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md029---ordered-list-item-prefix -->
|
<!-- Disable ordered list rule https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md029---ordered-list-item-prefix -->
|
||||||
<!-- markdownlint-disable MD029 -->
|
<!-- markdownlint-disable MD029 -->
|
||||||
1. Can be optionally run on reputable third-party external PaaS PostgreSQL solutions. Google Cloud SQL and Amazon RDS are known to work, however Azure Database for PostgreSQL is [not recommended](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61) due to performance issues. Consul is primarily used for PostgreSQL high availability so can be ignored when using a PostgreSQL PaaS setup. However it is also used optionally by Prometheus for Omnibus auto host discovery.
|
1. Can be optionally run on reputable third-party external PaaS PostgreSQL solutions. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work, however Azure Database for PostgreSQL is **not recommended** due to [performance issues](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61). Consul is primarily used for PostgreSQL high availability so can be ignored when using a PostgreSQL PaaS setup. However it is also used optionally by Prometheus for Omnibus auto host discovery.
|
||||||
2. Can be optionally run on reputable third-party external PaaS Redis solutions. Google Memorystore and AWS Elasticache are known to work.
|
2. Can be optionally run on reputable third-party external PaaS Redis solutions. Google Memorystore and AWS Elasticache are known to work.
|
||||||
3. Should be run on reputable third-party object storage (storage PaaS) for cloud implementations. Google Cloud Storage and AWS S3 are known to work.
|
3. Should be run on reputable third-party object storage (storage PaaS) for cloud implementations. Google Cloud Storage and AWS S3 are known to work.
|
||||||
<!-- markdownlint-enable MD029 -->
|
<!-- markdownlint-enable MD029 -->
|
||||||
|
|
|
@ -46,7 +46,7 @@ For a full list of reference architectures, see
|
||||||
|
|
||||||
<!-- Disable ordered list rule https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md029---ordered-list-item-prefix -->
|
<!-- Disable ordered list rule https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md029---ordered-list-item-prefix -->
|
||||||
<!-- markdownlint-disable MD029 -->
|
<!-- markdownlint-disable MD029 -->
|
||||||
1. Can be optionally run on reputable third-party external PaaS PostgreSQL solutions. Google Cloud SQL and Amazon RDS are known to work, however Azure Database for PostgreSQL is [not recommended](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61) due to performance issues. Consul is primarily used for PostgreSQL high availability so can be ignored when using a PostgreSQL PaaS setup. However it is also used optionally by Prometheus for Omnibus auto host discovery.
|
1. Can be optionally run on reputable third-party external PaaS PostgreSQL solutions. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work, however Azure Database for PostgreSQL is **not recommended** due to [performance issues](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61). Consul is primarily used for PostgreSQL high availability so can be ignored when using a PostgreSQL PaaS setup. However it is also used optionally by Prometheus for Omnibus auto host discovery.
|
||||||
2. Can be optionally run on reputable third-party external PaaS Redis solutions. Google Memorystore and AWS Elasticache are known to work.
|
2. Can be optionally run on reputable third-party external PaaS Redis solutions. Google Memorystore and AWS Elasticache are known to work.
|
||||||
3. Can be optionally run on reputable third-party load balancing services (LB PaaS). AWS ELB is known to work.
|
3. Can be optionally run on reputable third-party load balancing services (LB PaaS). AWS ELB is known to work.
|
||||||
4. Should be run on reputable third-party object storage (storage PaaS) for cloud implementations. Google Cloud Storage and AWS S3 are known to work.
|
4. Should be run on reputable third-party object storage (storage PaaS) for cloud implementations. Google Cloud Storage and AWS S3 are known to work.
|
||||||
|
@ -777,8 +777,9 @@ cluster to be used with GitLab.
|
||||||
### Provide your own PostgreSQL instance
|
### Provide your own PostgreSQL instance
|
||||||
|
|
||||||
If you're hosting GitLab on a cloud provider, you can optionally use a
|
If you're hosting GitLab on a cloud provider, you can optionally use a
|
||||||
managed service for PostgreSQL. For example, AWS offers a managed Relational
|
managed service for PostgreSQL.
|
||||||
Database Service (RDS) that runs PostgreSQL.
|
|
||||||
|
A reputable provider or solution should be used for this. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work, however Azure Database for PostgreSQL is **not recommended** due to [performance issues](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61).
|
||||||
|
|
||||||
If you use a cloud-managed service, or provide your own PostgreSQL:
|
If you use a cloud-managed service, or provide your own PostgreSQL:
|
||||||
|
|
||||||
|
@ -1201,7 +1202,14 @@ There are many third-party solutions for PostgreSQL HA. The solution selected mu
|
||||||
- A static IP for all connections that doesn't change on failover.
|
- A static IP for all connections that doesn't change on failover.
|
||||||
- [`LISTEN`](https://www.postgresql.org/docs/12/sql-listen.html) SQL functionality must be supported.
|
- [`LISTEN`](https://www.postgresql.org/docs/12/sql-listen.html) SQL functionality must be supported.
|
||||||
|
|
||||||
Examples of the above could include [Google's Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) or [Amazon RDS](https://aws.amazon.com/rds/).
|
NOTE:
|
||||||
|
With a third-party setup, it's possible to colocate Praefect's database on the same server as
|
||||||
|
the main [GitLab](#provide-your-own-postgresql-instance) database as a convenience unless
|
||||||
|
you are using Geo, where separate database instances are required for handling replication correctly.
|
||||||
|
In this setup, the specs of the main database setup shouldn't need to be changed as the impact should be
|
||||||
|
minimal.
|
||||||
|
|
||||||
|
A reputable provider or solution should be used for this. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work, however Azure Database for PostgreSQL is **not recommended** due to [performance issues](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61).
|
||||||
|
|
||||||
Once the database is set up, follow the [post configuration](#praefect-postgresql-post-configuration).
|
Once the database is set up, follow the [post configuration](#praefect-postgresql-post-configuration).
|
||||||
|
|
||||||
|
@ -2198,7 +2206,7 @@ services where applicable):
|
||||||
|
|
||||||
<!-- Disable ordered list rule https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md029---ordered-list-item-prefix -->
|
<!-- Disable ordered list rule https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md029---ordered-list-item-prefix -->
|
||||||
<!-- markdownlint-disable MD029 -->
|
<!-- markdownlint-disable MD029 -->
|
||||||
1. Can be optionally run on reputable third-party external PaaS PostgreSQL solutions. Google Cloud SQL and Amazon RDS are known to work, however Azure Database for PostgreSQL is [not recommended](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61) due to performance issues. Consul is primarily used for PostgreSQL high availability so can be ignored when using a PostgreSQL PaaS setup. However it is also used optionally by Prometheus for Omnibus auto host discovery.
|
1. Can be optionally run on reputable third-party external PaaS PostgreSQL solutions. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work, however Azure Database for PostgreSQL is **not recommended** due to [performance issues](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61). Consul is primarily used for PostgreSQL high availability so can be ignored when using a PostgreSQL PaaS setup. However it is also used optionally by Prometheus for Omnibus auto host discovery.
|
||||||
2. Can be optionally run on reputable third-party external PaaS Redis solutions. Google Memorystore and AWS Elasticache are known to work.
|
2. Can be optionally run on reputable third-party external PaaS Redis solutions. Google Memorystore and AWS Elasticache are known to work.
|
||||||
3. Can be optionally run on reputable third-party load balancing services (LB PaaS). AWS ELB is known to work.
|
3. Can be optionally run on reputable third-party load balancing services (LB PaaS). AWS ELB is known to work.
|
||||||
4. Should be run on reputable third-party object storage (storage PaaS) for cloud implementations. Google Cloud Storage and AWS S3 are known to work.
|
4. Should be run on reputable third-party object storage (storage PaaS) for cloud implementations. Google Cloud Storage and AWS S3 are known to work.
|
||||||
|
|
|
@ -37,7 +37,7 @@ full list of reference architectures, see
|
||||||
|
|
||||||
<!-- Disable ordered list rule https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md029---ordered-list-item-prefix -->
|
<!-- Disable ordered list rule https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md029---ordered-list-item-prefix -->
|
||||||
<!-- markdownlint-disable MD029 -->
|
<!-- markdownlint-disable MD029 -->
|
||||||
1. Can be optionally run on reputable third-party external PaaS PostgreSQL solutions. Google Cloud SQL and Amazon RDS are known to work, however Azure Database for PostgreSQL is [not recommended](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61) due to performance issues. Consul is primarily used for PostgreSQL high availability so can be ignored when using a PostgreSQL PaaS setup. However it is also used optionally by Prometheus for Omnibus auto host discovery.
|
1. Can be optionally run on reputable third-party external PaaS PostgreSQL solutions. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work, however Azure Database for PostgreSQL is **not recommended** due to [performance issues](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61). Consul is primarily used for PostgreSQL high availability so can be ignored when using a PostgreSQL PaaS setup. However it is also used optionally by Prometheus for Omnibus auto host discovery.
|
||||||
2. Can be optionally run on reputable third-party external PaaS Redis solutions. Google Memorystore and AWS Elasticache are known to work.
|
2. Can be optionally run on reputable third-party external PaaS Redis solutions. Google Memorystore and AWS Elasticache are known to work.
|
||||||
3. Can be optionally run on reputable third-party load balancing services (LB PaaS). AWS ELB is known to work.
|
3. Can be optionally run on reputable third-party load balancing services (LB PaaS). AWS ELB is known to work.
|
||||||
4. Should be run on reputable third-party object storage (storage PaaS) for cloud implementations. Google Cloud Storage and AWS S3 are known to work.
|
4. Should be run on reputable third-party object storage (storage PaaS) for cloud implementations. Google Cloud Storage and AWS S3 are known to work.
|
||||||
|
@ -495,8 +495,9 @@ cluster to be used with GitLab.
|
||||||
### Provide your own PostgreSQL instance
|
### Provide your own PostgreSQL instance
|
||||||
|
|
||||||
If you're hosting GitLab on a cloud provider, you can optionally use a
|
If you're hosting GitLab on a cloud provider, you can optionally use a
|
||||||
managed service for PostgreSQL. For example, AWS offers a managed Relational
|
managed service for PostgreSQL.
|
||||||
Database Service (RDS) that runs PostgreSQL.
|
|
||||||
|
A reputable provider or solution should be used for this. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work, however Azure Database for PostgreSQL is **not recommended** due to [performance issues](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61).
|
||||||
|
|
||||||
If you use a cloud-managed service, or provide your own PostgreSQL:
|
If you use a cloud-managed service, or provide your own PostgreSQL:
|
||||||
|
|
||||||
|
@ -1262,6 +1263,15 @@ There are many third-party solutions for PostgreSQL HA. The solution selected mu
|
||||||
- A static IP for all connections that doesn't change on failover.
|
- A static IP for all connections that doesn't change on failover.
|
||||||
- [`LISTEN`](https://www.postgresql.org/docs/12/sql-listen.html) SQL functionality must be supported.
|
- [`LISTEN`](https://www.postgresql.org/docs/12/sql-listen.html) SQL functionality must be supported.
|
||||||
|
|
||||||
|
NOTE:
|
||||||
|
With a third-party setup, it's possible to colocate Praefect's database on the same server as
|
||||||
|
the main [GitLab](#provide-your-own-postgresql-instance) database as a convenience unless
|
||||||
|
you are using Geo, where separate database instances are required for handling replication correctly.
|
||||||
|
In this setup, the specs of the main database setup shouldn't need to be changed as the impact should be
|
||||||
|
minimal.
|
||||||
|
|
||||||
|
A reputable provider or solution should be used for this. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work, however Azure Database for PostgreSQL is **not recommended** due to [performance issues](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61).
|
||||||
|
|
||||||
Examples of the above could include [Google's Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) or [Amazon RDS](https://aws.amazon.com/rds/).
|
Examples of the above could include [Google's Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) or [Amazon RDS](https://aws.amazon.com/rds/).
|
||||||
|
|
||||||
Once the database is set up, follow the [post configuration](#praefect-postgresql-post-configuration).
|
Once the database is set up, follow the [post configuration](#praefect-postgresql-post-configuration).
|
||||||
|
@ -2248,7 +2258,7 @@ services where applicable):
|
||||||
|
|
||||||
<!-- Disable ordered list rule https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md029---ordered-list-item-prefix -->
|
<!-- Disable ordered list rule https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md029---ordered-list-item-prefix -->
|
||||||
<!-- markdownlint-disable MD029 -->
|
<!-- markdownlint-disable MD029 -->
|
||||||
1. Can be optionally run on reputable third-party external PaaS PostgreSQL solutions. Google Cloud SQL and Amazon RDS are known to work, however Azure Database for PostgreSQL is [not recommended](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61) due to performance issues. Consul is primarily used for PostgreSQL high availability so can be ignored when using a PostgreSQL PaaS setup. However it is also used optionally by Prometheus for Omnibus auto host discovery.
|
1. Can be optionally run on reputable third-party external PaaS PostgreSQL solutions. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work, however Azure Database for PostgreSQL is **not recommended** due to [performance issues](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61). Consul is primarily used for PostgreSQL high availability so can be ignored when using a PostgreSQL PaaS setup. However it is also used optionally by Prometheus for Omnibus auto host discovery.
|
||||||
2. Can be optionally run on reputable third-party external PaaS Redis solutions. Google Memorystore and AWS Elasticache are known to work.
|
2. Can be optionally run on reputable third-party external PaaS Redis solutions. Google Memorystore and AWS Elasticache are known to work.
|
||||||
3. Can be optionally run on reputable third-party load balancing services (LB PaaS). AWS ELB is known to work.
|
3. Can be optionally run on reputable third-party load balancing services (LB PaaS). AWS ELB is known to work.
|
||||||
4. Should be run on reputable third-party object storage (storage PaaS) for cloud implementations. Google Cloud Storage and AWS S3 are known to work.
|
4. Should be run on reputable third-party object storage (storage PaaS) for cloud implementations. Google Cloud Storage and AWS S3 are known to work.
|
||||||
|
|
|
@ -43,7 +43,7 @@ costly-to-operate environment by using the
|
||||||
|
|
||||||
<!-- Disable ordered list rule https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md029---ordered-list-item-prefix -->
|
<!-- Disable ordered list rule https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md029---ordered-list-item-prefix -->
|
||||||
<!-- markdownlint-disable MD029 -->
|
<!-- markdownlint-disable MD029 -->
|
||||||
1. Can be optionally run on reputable third-party external PaaS PostgreSQL solutions. Google Cloud SQL and AWS RDS are known to work, however Azure Database for PostgreSQL is [not recommended](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61) due to performance issues. Consul is primarily used for PostgreSQL high availability so can be ignored when using a PostgreSQL PaaS setup. However it is also used optionally by Prometheus for Omnibus auto host discovery.
|
1. Can be optionally run on reputable third-party external PaaS PostgreSQL solutions. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work, however Azure Database for PostgreSQL is **not recommended** due to [performance issues](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61). Consul is primarily used for PostgreSQL high availability so can be ignored when using a PostgreSQL PaaS setup. However it is also used optionally by Prometheus for Omnibus auto host discovery.
|
||||||
2. Can be optionally run on reputable third-party external PaaS Redis solutions. Google Memorystore and AWS Elasticache are known to work.
|
2. Can be optionally run on reputable third-party external PaaS Redis solutions. Google Memorystore and AWS Elasticache are known to work.
|
||||||
3. Can be optionally run on reputable third-party load balancing services (LB PaaS). AWS ELB is known to work.
|
3. Can be optionally run on reputable third-party load balancing services (LB PaaS). AWS ELB is known to work.
|
||||||
4. Should be run on reputable third-party object storage (storage PaaS) for cloud implementations. Google Cloud Storage and AWS S3 are known to work.
|
4. Should be run on reputable third-party object storage (storage PaaS) for cloud implementations. Google Cloud Storage and AWS S3 are known to work.
|
||||||
|
@ -769,8 +769,9 @@ cluster to be used with GitLab.
|
||||||
### Provide your own PostgreSQL instance
|
### Provide your own PostgreSQL instance
|
||||||
|
|
||||||
If you're hosting GitLab on a cloud provider, you can optionally use a
|
If you're hosting GitLab on a cloud provider, you can optionally use a
|
||||||
managed service for PostgreSQL. For example, AWS offers a managed Relational
|
managed service for PostgreSQL.
|
||||||
Database Service (RDS) that runs PostgreSQL.
|
|
||||||
|
A reputable provider or solution should be used for this. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work, however Azure Database for PostgreSQL is **not recommended** due to [performance issues](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61).
|
||||||
|
|
||||||
If you use a cloud-managed service, or provide your own PostgreSQL:
|
If you use a cloud-managed service, or provide your own PostgreSQL:
|
||||||
|
|
||||||
|
@ -1194,7 +1195,14 @@ There are many third-party solutions for PostgreSQL HA. The solution selected mu
|
||||||
- A static IP for all connections that doesn't change on failover.
|
- A static IP for all connections that doesn't change on failover.
|
||||||
- [`LISTEN`](https://www.postgresql.org/docs/12/sql-listen.html) SQL functionality must be supported.
|
- [`LISTEN`](https://www.postgresql.org/docs/12/sql-listen.html) SQL functionality must be supported.
|
||||||
|
|
||||||
Examples of the above could include [Google's Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) or [Amazon RDS](https://aws.amazon.com/rds/).
|
NOTE:
|
||||||
|
With a third-party setup, it's possible to colocate Praefect's database on the same server as
|
||||||
|
the main [GitLab](#provide-your-own-postgresql-instance) database as a convenience unless
|
||||||
|
you are using Geo, where separate database instances are required for handling replication correctly.
|
||||||
|
In this setup, the specs of the main database setup shouldn't need to be changed as the impact should be
|
||||||
|
minimal.
|
||||||
|
|
||||||
|
A reputable provider or solution should be used for this. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work, however Azure Database for PostgreSQL is **not recommended** due to [performance issues](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61).
|
||||||
|
|
||||||
Once the database is set up, follow the [post configuration](#praefect-postgresql-post-configuration).
|
Once the database is set up, follow the [post configuration](#praefect-postgresql-post-configuration).
|
||||||
|
|
||||||
|
@ -2169,7 +2177,7 @@ services where applicable):
|
||||||
|
|
||||||
<!-- Disable ordered list rule https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md029---ordered-list-item-prefix -->
|
<!-- Disable ordered list rule https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md029---ordered-list-item-prefix -->
|
||||||
<!-- markdownlint-disable MD029 -->
|
<!-- markdownlint-disable MD029 -->
|
||||||
1. Can be optionally run on reputable third-party external PaaS PostgreSQL solutions. Google Cloud SQL and AWS RDS are known to work, however Azure Database for PostgreSQL is [not recommended](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61) due to performance issues. Consul is primarily used for PostgreSQL high availability so can be ignored when using a PostgreSQL PaaS setup. However it is also used optionally by Prometheus for Omnibus auto host discovery.
|
1. Can be optionally run on reputable third-party external PaaS PostgreSQL solutions. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work, however Azure Database for PostgreSQL is **not recommended** due to [performance issues](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61). Consul is primarily used for PostgreSQL high availability so can be ignored when using a PostgreSQL PaaS setup. However it is also used optionally by Prometheus for Omnibus auto host discovery.
|
||||||
2. Can be optionally run on reputable third-party external PaaS Redis solutions. Google Memorystore and AWS Elasticache are known to work.
|
2. Can be optionally run on reputable third-party external PaaS Redis solutions. Google Memorystore and AWS Elasticache are known to work.
|
||||||
3. Can be optionally run on reputable third-party load balancing services (LB PaaS). AWS ELB is known to work.
|
3. Can be optionally run on reputable third-party load balancing services (LB PaaS). AWS ELB is known to work.
|
||||||
4. Should be run on reputable third-party object storage (storage PaaS) for cloud implementations. Google Cloud Storage and AWS S3 are known to work.
|
4. Should be run on reputable third-party object storage (storage PaaS) for cloud implementations. Google Cloud Storage and AWS S3 are known to work.
|
||||||
|
|
|
@ -15,6 +15,8 @@ Read more on [pagination](index.md#pagination).
|
||||||
|
|
||||||
## List project pipelines
|
## List project pipelines
|
||||||
|
|
||||||
|
> `iid` in response [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/342223) in GitLab 14.6.
|
||||||
|
|
||||||
List pipelines in a project. Child pipelines are not included in the results,
|
List pipelines in a project. Child pipelines are not included in the results,
|
||||||
but you can [get child pipeline](pipelines.md#get-a-single-pipeline) individually.
|
but you can [get child pipeline](pipelines.md#get-a-single-pipeline) individually.
|
||||||
|
|
||||||
|
@ -74,6 +76,8 @@ Example of response
|
||||||
|
|
||||||
## Get a single pipeline
|
## Get a single pipeline
|
||||||
|
|
||||||
|
> `iid` in response [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/342223) in GitLab 14.6.
|
||||||
|
|
||||||
Get one pipeline from a project.
|
Get one pipeline from a project.
|
||||||
|
|
||||||
You can also get a single [child pipeline](../ci/pipelines/parent_child_pipelines.md).
|
You can also get a single [child pipeline](../ci/pipelines/parent_child_pipelines.md).
|
||||||
|
@ -267,6 +271,8 @@ Sample response:
|
||||||
|
|
||||||
## Create a new pipeline
|
## Create a new pipeline
|
||||||
|
|
||||||
|
> `iid` in response [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/342223) in GitLab 14.6.
|
||||||
|
|
||||||
```plaintext
|
```plaintext
|
||||||
POST /projects/:id/pipeline
|
POST /projects/:id/pipeline
|
||||||
```
|
```
|
||||||
|
@ -316,6 +322,8 @@ Example of response
|
||||||
|
|
||||||
## Retry jobs in a pipeline
|
## Retry jobs in a pipeline
|
||||||
|
|
||||||
|
> `iid` in response [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/342223) in GitLab 14.6.
|
||||||
|
|
||||||
```plaintext
|
```plaintext
|
||||||
POST /projects/:id/pipelines/:pipeline_id/retry
|
POST /projects/:id/pipelines/:pipeline_id/retry
|
||||||
```
|
```
|
||||||
|
|
|
@ -58,8 +58,7 @@ it was originally composed for, if it is helpful to any of our audiences, we can
|
||||||
include it.
|
include it.
|
||||||
|
|
||||||
- If you use an image that has a separate source file (for example, a vector or
|
- If you use an image that has a separate source file (for example, a vector or
|
||||||
diagram format), link the image to the source file so that it may be reused or
|
diagram format), link the image to the source file so that anyone can update or reuse it.
|
||||||
updated by anyone.
|
|
||||||
- Do not copy and paste content from other sources unless it is a limited
|
- Do not copy and paste content from other sources unless it is a limited
|
||||||
quotation with the source cited. Typically it is better to either rephrase
|
quotation with the source cited. Typically it is better to either rephrase
|
||||||
relevant information in your own words or link out to the other source.
|
relevant information in your own words or link out to the other source.
|
||||||
|
|
|
@ -4,31 +4,39 @@ group: Integrations
|
||||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
|
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
|
||||||
---
|
---
|
||||||
|
|
||||||
# Sign into GitLab with (almost) any OAuth2 provider **(FREE SELF)**
|
# Generic OAuth2 provider **(FREE SELF)**
|
||||||
|
|
||||||
The `omniauth-oauth2-generic` gem allows Single Sign-On between GitLab and your own OAuth2 provider
|
The `omniauth-oauth2-generic` gem allows single sign-on (SSO) between GitLab
|
||||||
(or any OAuth2 provider compatible with this gem)
|
and your OAuth2 provider (or any OAuth2 provider compatible with this gem).
|
||||||
|
|
||||||
This strategy is designed to allow configuration of the simple OmniAuth SSO process outlined below:
|
This strategy allows for the configuration of this OmniAuth SSO process:
|
||||||
|
|
||||||
1. Strategy directs client to your authorization URL (**configurable**), with specified ID and key
|
1. Strategy directs the client to your authorization URL (**configurable**), with
|
||||||
1. OAuth provider handles authentication of request, user, and (optionally) authorization to access user's profile
|
the specified ID and key.
|
||||||
1. OAuth provider directs client back to GitLab where Strategy handles retrieval of access token
|
1. The OAuth2 provider handles authentication of the request, user, and (optionally)
|
||||||
1. Strategy requests user information from a **configurable** "user profile" URL (using the access token)
|
authorization to access user's profile.
|
||||||
1. Strategy parses user information from the response, using a **configurable** format
|
1. The OAuth2 provider directs the client back to GitLab where Strategy handles
|
||||||
1. GitLab finds or creates the returned user and logs them in
|
the retrieval of the access token.
|
||||||
|
1. Strategy requests user information from a **configurable** "user profile"
|
||||||
|
URL (using the access token).
|
||||||
|
1. Strategy parses user information from the response, using a **configurable**
|
||||||
|
format.
|
||||||
|
1. GitLab finds or creates the returned user and signs them in.
|
||||||
|
|
||||||
## Limitations of this Strategy
|
## Limitations of this strategy
|
||||||
|
|
||||||
- It can only be used for Single Sign on, and doesn't provide any other access granted by any OAuth provider
|
- It can only be used for single sign-on, and doesn't provide any other access
|
||||||
(importing projects or users, etc)
|
granted by any OAuth2 provider (like importing projects or users).
|
||||||
- It only supports the Authorization Grant flow (most common for client-server applications, like GitLab)
|
- It supports only the Authorization Grant flow (most common for client-server
|
||||||
- It is not able to fetch user information from more than one URL
|
applications, like GitLab).
|
||||||
- It has not been tested with user information formats other than JSON
|
- It can't fetch user information from more than one URL.
|
||||||
|
- It hasn't been tested with user information formats, other than JSON.
|
||||||
|
|
||||||
## Configuration Instructions
|
## Configure the OAuth2 provider
|
||||||
|
|
||||||
1. Register your application in the OAuth2 provider you wish to authenticate with.
|
To configure the provider:
|
||||||
|
|
||||||
|
1. Register your application in the OAuth2 provider you want to authenticate with.
|
||||||
|
|
||||||
The redirect URI you provide when registering the application should be:
|
The redirect URI you provide when registering the application should be:
|
||||||
|
|
||||||
|
@ -36,13 +44,13 @@ This strategy is designed to allow configuration of the simple OmniAuth SSO proc
|
||||||
http://your-gitlab.host.com/users/auth/oauth2_generic/callback
|
http://your-gitlab.host.com/users/auth/oauth2_generic/callback
|
||||||
```
|
```
|
||||||
|
|
||||||
1. You should now be able to get a Client ID and Client Secret.
|
You should now be able to get a Client ID and Client Secret. Where this
|
||||||
Where this shows up differs for each provider.
|
appears differs for each provider. This may also be called Application ID
|
||||||
This may also be called Application ID and Secret
|
and Secret.
|
||||||
|
|
||||||
1. On your GitLab server, open the configuration file.
|
1. On your GitLab server, open the appropriate configuration file.
|
||||||
|
|
||||||
For Omnibus package:
|
For Omnibus GitLab:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
sudo editor /etc/gitlab/gitlab.rb
|
sudo editor /etc/gitlab/gitlab.rb
|
||||||
|
@ -55,9 +63,10 @@ This strategy is designed to allow configuration of the simple OmniAuth SSO proc
|
||||||
sudo -u git -H editor config/gitlab.yml
|
sudo -u git -H editor config/gitlab.yml
|
||||||
```
|
```
|
||||||
|
|
||||||
1. See [Configure initial settings](omniauth.md#configure-initial-settings) for initial settings
|
1. See [Configure initial settings](omniauth.md#configure-initial-settings) for
|
||||||
|
initial settings.
|
||||||
|
|
||||||
1. Add the provider-specific configuration for your provider, for example:
|
1. Add the provider-specific configuration for your provider. For example:
|
||||||
|
|
||||||
```ruby
|
```ruby
|
||||||
gitlab_rails['omniauth_providers'] = [
|
gitlab_rails['omniauth_providers'] = [
|
||||||
|
@ -92,11 +101,13 @@ This strategy is designed to allow configuration of the simple OmniAuth SSO proc
|
||||||
|
|
||||||
For more information about these settings, see [the gem's README](https://gitlab.com/satorix/omniauth-oauth2-generic#gitlab-config-example).
|
For more information about these settings, see [the gem's README](https://gitlab.com/satorix/omniauth-oauth2-generic#gitlab-config-example).
|
||||||
|
|
||||||
1. Save the configuration file
|
1. Save the configuration file.
|
||||||
|
|
||||||
1. Restart GitLab for the changes to take effect
|
1. [Restart](../administration/restart_gitlab.md#installations-from-source)
|
||||||
|
GitLab for the changes to take effect.
|
||||||
|
|
||||||
On the sign in page there should now be a new button below the regular sign in form.
|
On the sign-in page there should now be a new button below the regular sign-in
|
||||||
Click the button to begin your provider's authentication process. This directs
|
form. Select the button to begin your provider's authentication process. This
|
||||||
the browser to your OAuth2 Provider's authentication page. If everything goes well
|
directs the browser to your OAuth2 provider's authentication page. If
|
||||||
the user is returned to your GitLab instance and is signed in.
|
everything goes well, you are returned to your GitLab instance and are
|
||||||
|
signed in.
|
||||||
|
|
|
@ -4,7 +4,7 @@ module API
|
||||||
module Entities
|
module Entities
|
||||||
module Ci
|
module Ci
|
||||||
class PipelineBasic < Grape::Entity
|
class PipelineBasic < Grape::Entity
|
||||||
expose :id, :project_id, :sha, :ref, :status, :source
|
expose :id, :iid, :project_id, :sha, :ref, :status, :source
|
||||||
expose :created_at, :updated_at
|
expose :created_at, :updated_at
|
||||||
|
|
||||||
expose :web_url do |pipeline, _options|
|
expose :web_url do |pipeline, _options|
|
||||||
|
|
|
@ -39,7 +39,7 @@ module Banzai
|
||||||
|
|
||||||
code[:class] = INLINE_CLASSES
|
code[:class] = INLINE_CLASSES
|
||||||
code[STYLE_ATTRIBUTE] = 'inline'
|
code[STYLE_ATTRIBUTE] = 'inline'
|
||||||
closing.content = closing.content[1..-1]
|
closing.content = closing.content[1..]
|
||||||
opening.content = opening.content[0..-2]
|
opening.content = opening.content[0..-2]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -174,7 +174,7 @@ module Banzai
|
||||||
def build_relative_path(path, request_path)
|
def build_relative_path(path, request_path)
|
||||||
return request_path if path.empty?
|
return request_path if path.empty?
|
||||||
return path unless request_path
|
return path unless request_path
|
||||||
return path[1..-1] if path.start_with?('/')
|
return path[1..] if path.start_with?('/')
|
||||||
|
|
||||||
parts = request_path.split('/')
|
parts = request_path.split('/')
|
||||||
|
|
||||||
|
|
|
@ -113,7 +113,7 @@ module ExtractsRef
|
||||||
best_match = valid_refs.max_by(&:length)
|
best_match = valid_refs.max_by(&:length)
|
||||||
|
|
||||||
# Partition the string into the ref and the path, ignoring the empty first value
|
# Partition the string into the ref and the path, ignoring the empty first value
|
||||||
id.partition(best_match)[1..-1]
|
id.partition(best_match)[1..]
|
||||||
end
|
end
|
||||||
|
|
||||||
def use_first_path_segment?(ref)
|
def use_first_path_segment?(ref)
|
||||||
|
|
|
@ -51,7 +51,7 @@ module Flowdock
|
||||||
end
|
end
|
||||||
|
|
||||||
def body
|
def body
|
||||||
content = @commit[:message][first_line.size..-1]
|
content = @commit[:message][first_line.size..]
|
||||||
content.strip! if content
|
content.strip! if content
|
||||||
"<pre>#{content}</pre>" unless content.empty?
|
"<pre>#{content}</pre>" unless content.empty?
|
||||||
end
|
end
|
||||||
|
|
|
@ -48,10 +48,10 @@ module Gitlab
|
||||||
# follows it will produce a nil. For example:
|
# follows it will produce a nil. For example:
|
||||||
#
|
#
|
||||||
# "\n".split("\n") # => []
|
# "\n".split("\n") # => []
|
||||||
# "\n".split("\n")[1..-1] # => nil
|
# "\n".split("\n")[1..] # => nil
|
||||||
#
|
#
|
||||||
# To work around this we only "join" if we're given an Array.
|
# To work around this we only "join" if we're given an Array.
|
||||||
if (converted = output.split("\n")[1..-1])
|
if (converted = output.split("\n")[1..])
|
||||||
converted.join("\n")
|
converted.join("\n")
|
||||||
else
|
else
|
||||||
''
|
''
|
||||||
|
|
|
@ -51,7 +51,7 @@ module Gitlab
|
||||||
|
|
||||||
def replace_with!(other)
|
def replace_with!(other)
|
||||||
instance_variables.each do |ivar|
|
instance_variables.each do |ivar|
|
||||||
instance_variable_set(ivar, other.public_send(ivar.to_s[1..-1])) # rubocop:disable GitlabSecurity/PublicSend
|
instance_variable_set(ivar, other.public_send(ivar.to_s[1..])) # rubocop:disable GitlabSecurity/PublicSend
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@ module Gitlab
|
||||||
end
|
end
|
||||||
|
|
||||||
def strip_diff_frontmatter(diff_content)
|
def strip_diff_frontmatter(diff_content)
|
||||||
diff_content.scan(/.*\n/)[2..-1]&.join('') if diff_content.present?
|
diff_content.scan(/.*\n/)[2..]&.join('') if diff_content.present?
|
||||||
end
|
end
|
||||||
|
|
||||||
def blobs_with_transformed_diffs
|
def blobs_with_transformed_diffs
|
||||||
|
|
|
@ -6,8 +6,8 @@ module Gitlab
|
||||||
attr_accessor :old_line, :new_line, :offset
|
attr_accessor :old_line, :new_line, :offset
|
||||||
|
|
||||||
def initialize(old_line, new_line, offset: 0)
|
def initialize(old_line, new_line, offset: 0)
|
||||||
@old_line = old_line[offset..-1]
|
@old_line = old_line[offset..]
|
||||||
@new_line = new_line[offset..-1]
|
@new_line = new_line[offset..]
|
||||||
@offset = offset
|
@offset = offset
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,7 @@ module Gitlab
|
||||||
|
|
||||||
def unfold_reference(reference, match, target_parent)
|
def unfold_reference(reference, match, target_parent)
|
||||||
before = @text[0...match.begin(0)]
|
before = @text[0...match.begin(0)]
|
||||||
after = @text[match.end(0)..-1]
|
after = @text[match.end(0)..]
|
||||||
|
|
||||||
referable = find_referable(reference)
|
referable = find_referable(reference)
|
||||||
return reference unless referable
|
return reference unless referable
|
||||||
|
|
|
@ -48,7 +48,7 @@ module Gitlab
|
||||||
raw_keys.each_with_object({}) do |raw_key, grouped_subkeys|
|
raw_keys.each_with_object({}) do |raw_key, grouped_subkeys|
|
||||||
primary_subkey_id = raw_key.primary_subkey.keyid
|
primary_subkey_id = raw_key.primary_subkey.keyid
|
||||||
|
|
||||||
grouped_subkeys[primary_subkey_id] = raw_key.subkeys[1..-1].map do |s|
|
grouped_subkeys[primary_subkey_id] = raw_key.subkeys[1..].map do |s|
|
||||||
{ keyid: s.keyid, fingerprint: s.fingerprint }
|
{ keyid: s.keyid, fingerprint: s.fingerprint }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -44,7 +44,7 @@ module Gitlab
|
||||||
|
|
||||||
next unless match
|
next unless match
|
||||||
|
|
||||||
input = match.split(':')[1..-1].join
|
input = match.split(':')[1..].join
|
||||||
next if input.empty?
|
next if input.empty?
|
||||||
|
|
||||||
filter[:negated] = match.start_with?("-")
|
filter[:negated] = match.start_with?("-")
|
||||||
|
|
|
@ -70,7 +70,7 @@ module Gitlab
|
||||||
|
|
||||||
next if total_duration <= MINIMUM_DURATION
|
next if total_duration <= MINIMUM_DURATION
|
||||||
|
|
||||||
stats[1..-1].each_with_index do |data, index|
|
stats[1..].each_with_index do |data, index|
|
||||||
next unless source_lines[index]
|
next unless source_lines[index]
|
||||||
|
|
||||||
duration = microsec_to_millisec(data[0])
|
duration = microsec_to_millisec(data[0])
|
||||||
|
|
|
@ -99,7 +99,7 @@ module Gitlab
|
||||||
|
|
||||||
start = prev = positions[0]
|
start = prev = positions[0]
|
||||||
range = MarkerRange.new(start, prev, mode: mode)
|
range = MarkerRange.new(start, prev, mode: mode)
|
||||||
positions[1..-1].each do |pos|
|
positions[1..].each do |pos|
|
||||||
if pos == prev + 1
|
if pos == prev + 1
|
||||||
range = MarkerRange.new(start, pos, mode: mode)
|
range = MarkerRange.new(start, pos, mode: mode)
|
||||||
prev = pos
|
prev = pos
|
||||||
|
|
|
@ -16,7 +16,7 @@ module Gitlab
|
||||||
# we remove the leading `//` and add `descendant-or-self::`
|
# we remove the leading `//` and add `descendant-or-self::`
|
||||||
# in order to ensure we're searching from this node and all
|
# in order to ensure we're searching from this node and all
|
||||||
# descendants.
|
# descendants.
|
||||||
xpath.map { |t| "descendant-or-self::#{t[2..-1]}" }.join('|')
|
xpath.map { |t| "descendant-or-self::#{t[2..]}" }.join('|')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -184,7 +184,7 @@ class GroupSeeder
|
||||||
group = Group.find(group_id)
|
group = Group.find(group_id)
|
||||||
|
|
||||||
@resource_count.times do |i|
|
@resource_count.times do |i|
|
||||||
_, project_path = PROJECT_URL.split('/')[-2..-1]
|
_, project_path = PROJECT_URL.split('/')[-2..]
|
||||||
|
|
||||||
project_path.gsub!('.git', '')
|
project_path.gsub!('.git', '')
|
||||||
|
|
||||||
|
|
|
@ -168,6 +168,41 @@ module QA
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Object comparison
|
||||||
|
#
|
||||||
|
# @param [QA::Resource::MergeRequest] other
|
||||||
|
# @return [Boolean]
|
||||||
|
def ==(other)
|
||||||
|
other.is_a?(MergeRequest) && comparable_mr == other.comparable_mr
|
||||||
|
end
|
||||||
|
|
||||||
|
# Override inspect for a better rspec failure diff output
|
||||||
|
#
|
||||||
|
# @return [String]
|
||||||
|
def inspect
|
||||||
|
JSON.pretty_generate(comparable_mr)
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
# Return subset of fields for comparing merge requests
|
||||||
|
#
|
||||||
|
# @return [Hash]
|
||||||
|
def comparable_mr
|
||||||
|
reload! if api_response.nil?
|
||||||
|
|
||||||
|
api_resource.except(
|
||||||
|
:id,
|
||||||
|
:web_url,
|
||||||
|
:project_id,
|
||||||
|
:source_project_id,
|
||||||
|
:target_project_id,
|
||||||
|
# these can differ depending on user fetching mr
|
||||||
|
:subscribed,
|
||||||
|
:first_contribution
|
||||||
|
).merge({ references: api_resource[:references].except(:full) })
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def transform_api_resource(api_resource)
|
def transform_api_resource(api_resource)
|
||||||
|
|
|
@ -46,7 +46,7 @@ module RuboCop
|
||||||
end
|
end
|
||||||
|
|
||||||
def arguments(node)
|
def arguments(node)
|
||||||
node.children[2..-1]
|
node.children[2..]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -46,7 +46,7 @@ module RuboCop
|
||||||
end
|
end
|
||||||
|
|
||||||
def arguments(node)
|
def arguments(node)
|
||||||
node.children[2..-1]
|
node.children[2..]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -215,9 +215,13 @@ RSpec.describe Import::BulkImportsController do
|
||||||
let(:pat) { "fake-pat" }
|
let(:pat) { "fake-pat" }
|
||||||
let(:bulk_import_params) do
|
let(:bulk_import_params) do
|
||||||
[{ "source_type" => "group_entity",
|
[{ "source_type" => "group_entity",
|
||||||
"source_full_path" => "full_path",
|
"source_full_path" => "full_path",
|
||||||
"destination_name" => "destination_name",
|
"destination_name" => "destination_name",
|
||||||
"destination_namespace" => "root" }]
|
"destination_namespace" => "root" },
|
||||||
|
{ "source_type" => "group_entity2",
|
||||||
|
"source_full_path" => "full_path2",
|
||||||
|
"destination_name" => "destination_name2",
|
||||||
|
"destination_namespace" => "root" }]
|
||||||
end
|
end
|
||||||
|
|
||||||
before do
|
before do
|
||||||
|
@ -225,29 +229,23 @@ RSpec.describe Import::BulkImportsController do
|
||||||
session[:bulk_import_gitlab_url] = instance_url
|
session[:bulk_import_gitlab_url] = instance_url
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'executes BulkImpors::CreatetService' do
|
it 'executes BulkImpors::CreateService' do
|
||||||
|
error_response = ServiceResponse.error(message: 'Record invalid', http_status: :unprocessable_entity)
|
||||||
|
|
||||||
expect_next_instance_of(
|
expect_next_instance_of(
|
||||||
::BulkImports::CreateService, user, bulk_import_params, { url: instance_url, access_token: pat }) do |service|
|
::BulkImports::CreateService, user, bulk_import_params[0], { url: instance_url, access_token: pat }) do |service|
|
||||||
allow(service).to receive(:execute).and_return(ServiceResponse.success(payload: bulk_import))
|
allow(service).to receive(:execute).and_return(ServiceResponse.success(payload: bulk_import))
|
||||||
end
|
end
|
||||||
|
|
||||||
post :create, params: { bulk_import: bulk_import_params }
|
|
||||||
|
|
||||||
expect(response).to have_gitlab_http_status(:ok)
|
|
||||||
expect(response.body).to eq({ id: bulk_import.id }.to_json)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns error when validation fails' do
|
|
||||||
error_response = ServiceResponse.error(message: 'Record invalid', http_status: :unprocessable_entity)
|
|
||||||
expect_next_instance_of(
|
expect_next_instance_of(
|
||||||
::BulkImports::CreateService, user, bulk_import_params, { url: instance_url, access_token: pat }) do |service|
|
::BulkImports::CreateService, user, bulk_import_params[1], { url: instance_url, access_token: pat }) do |service|
|
||||||
allow(service).to receive(:execute).and_return(error_response)
|
allow(service).to receive(:execute).and_return(error_response)
|
||||||
end
|
end
|
||||||
|
|
||||||
post :create, params: { bulk_import: bulk_import_params }
|
post :create, params: { bulk_import: bulk_import_params }
|
||||||
|
|
||||||
expect(response).to have_gitlab_http_status(:unprocessable_entity)
|
expect(response).to have_gitlab_http_status(:ok)
|
||||||
expect(response.body).to eq({ error: 'Record invalid' }.to_json)
|
expect(json_response).to eq([{ "success" => true, "id" => bulk_import.id, "message" => nil },
|
||||||
|
{ "success" => false, "id" => nil, "message" => "Record invalid" }])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -128,7 +128,7 @@ RSpec.describe Projects::Serverless::FunctionsController do
|
||||||
|
|
||||||
expect(json_response["functions"]).to all(
|
expect(json_response["functions"]).to all(
|
||||||
include(
|
include(
|
||||||
'url' => "https://#{function_name}-#{serverless_domain_cluster.uuid[0..1]}a1#{serverless_domain_cluster.uuid[2..-3]}f2#{serverless_domain_cluster.uuid[-2..-1]}#{"%x" % environment.id}-#{environment.slug}.#{serverless_domain_cluster.domain}"
|
'url' => "https://#{function_name}-#{serverless_domain_cluster.uuid[0..1]}a1#{serverless_domain_cluster.uuid[2..-3]}f2#{serverless_domain_cluster.uuid[-2..]}#{"%x" % environment.id}-#{environment.slug}.#{serverless_domain_cluster.domain}"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
@ -166,7 +166,7 @@ RSpec.describe Projects::Serverless::FunctionsController do
|
||||||
expect(response).to have_gitlab_http_status(:ok)
|
expect(response).to have_gitlab_http_status(:ok)
|
||||||
|
|
||||||
expect(json_response).to include(
|
expect(json_response).to include(
|
||||||
'url' => "https://#{function_name}-#{serverless_domain_cluster.uuid[0..1]}a1#{serverless_domain_cluster.uuid[2..-3]}f2#{serverless_domain_cluster.uuid[-2..-1]}#{"%x" % environment.id}-#{environment.slug}.#{serverless_domain_cluster.domain}"
|
'url' => "https://#{function_name}-#{serverless_domain_cluster.uuid[0..1]}a1#{serverless_domain_cluster.uuid[2..-3]}f2#{serverless_domain_cluster.uuid[-2..]}#{"%x" % environment.id}-#{environment.slug}.#{serverless_domain_cluster.domain}"
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ RSpec.describe 'User views an open merge request' do
|
||||||
|
|
||||||
# Work around a weird Capybara behavior where calling `parent` on a node
|
# Work around a weird Capybara behavior where calling `parent` on a node
|
||||||
# returns the whole document, not the node's actual parent element
|
# returns the whole document, not the node's actual parent element
|
||||||
expect(find(:xpath, "#{node.path}/..").text).to eq(merge_request.description[2..-1])
|
expect(find(:xpath, "#{node.path}/..").text).to eq(merge_request.description[2..])
|
||||||
|
|
||||||
expect(page).to have_content(merge_request.title)
|
expect(page).to have_content(merge_request.title)
|
||||||
end
|
end
|
||||||
|
|
|
@ -80,7 +80,7 @@ RSpec.describe 'Issue prioritization' do
|
||||||
|
|
||||||
expect(issue_titles[0..1]).to contain_exactly('issue_5', 'issue_8')
|
expect(issue_titles[0..1]).to contain_exactly('issue_5', 'issue_8')
|
||||||
expect(issue_titles[2..4]).to contain_exactly('issue_1', 'issue_3', 'issue_7')
|
expect(issue_titles[2..4]).to contain_exactly('issue_1', 'issue_3', 'issue_7')
|
||||||
expect(issue_titles[5..-1]).to eq(%w(issue_2 issue_4 issue_6))
|
expect(issue_titles[5..]).to eq(%w(issue_2 issue_4 issue_6))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -71,7 +71,7 @@ RSpec.describe Packages::Nuget::PackageFinder do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with prefix wildcard' do
|
context 'with prefix wildcard' do
|
||||||
let(:package_name) { "%#{package1.name[3..-1]}" }
|
let(:package_name) { "%#{package1.name[3..]}" }
|
||||||
|
|
||||||
it { is_expected.to match_array([package1, package2]) }
|
it { is_expected.to match_array([package1, package2]) }
|
||||||
end
|
end
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
"type": ["object", "null"],
|
"type": ["object", "null"],
|
||||||
"properties": {
|
"properties": {
|
||||||
"id": { "type": "integer" },
|
"id": { "type": "integer" },
|
||||||
|
"iid": { "type": "integer" },
|
||||||
"project_id": { "type": "integer" },
|
"project_id": { "type": "integer" },
|
||||||
"sha": { "type": "string" },
|
"sha": { "type": "string" },
|
||||||
"ref": { "type": "string" },
|
"ref": { "type": "string" },
|
||||||
|
|
|
@ -123,13 +123,22 @@ describe('import target cell', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('when entity is available for import', () => {
|
describe('when entity is available for import', () => {
|
||||||
|
const FAKE_PROGRESS_MESSAGE = 'progress message';
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
group = generateFakeTableEntry({ id: 1, flags: { isAvailableForImport: true } });
|
group = generateFakeTableEntry({
|
||||||
|
id: 1,
|
||||||
|
flags: { isAvailableForImport: true },
|
||||||
|
progress: { message: FAKE_PROGRESS_MESSAGE },
|
||||||
|
});
|
||||||
createComponent({ group });
|
createComponent({ group });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders namespace dropdown as enabled', () => {
|
it('renders namespace dropdown as enabled', () => {
|
||||||
expect(findNamespaceDropdown().attributes('disabled')).toBe(undefined);
|
expect(findNamespaceDropdown().attributes('disabled')).toBe(undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('renders progress message as error if it exists', () => {
|
||||||
|
expect(wrapper.find('[role=alert]').text()).toBe(FAKE_PROGRESS_MESSAGE);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -163,12 +163,14 @@ describe('Bulk import resolvers', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('mutations', () => {
|
describe('mutations', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {});
|
||||||
axiosMockAdapter.onPost(FAKE_ENDPOINTS.createBulkImport).reply(httpStatus.OK, { id: 1 });
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('importGroup', () => {
|
describe('importGroup', () => {
|
||||||
it('sets import status to CREATED when request completes', async () => {
|
it('sets import status to CREATED for successful groups when request completes', async () => {
|
||||||
|
axiosMockAdapter
|
||||||
|
.onPost(FAKE_ENDPOINTS.createBulkImport)
|
||||||
|
.reply(httpStatus.OK, [{ success: true, id: 1 }]);
|
||||||
|
|
||||||
await client.mutate({
|
await client.mutate({
|
||||||
mutation: importGroupsMutation,
|
mutation: importGroupsMutation,
|
||||||
variables: {
|
variables: {
|
||||||
|
@ -185,9 +187,57 @@ describe('Bulk import resolvers', () => {
|
||||||
await axios.waitForAll();
|
await axios.waitForAll();
|
||||||
expect(results[0].progress.status).toBe(STATUSES.CREATED);
|
expect(results[0].progress.status).toBe(STATUSES.CREATED);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('sets import status to CREATED for successful groups when request completes with legacy response', async () => {
|
||||||
|
axiosMockAdapter.onPost(FAKE_ENDPOINTS.createBulkImport).reply(httpStatus.OK, { id: 1 });
|
||||||
|
|
||||||
|
await client.mutate({
|
||||||
|
mutation: importGroupsMutation,
|
||||||
|
variables: {
|
||||||
|
importRequests: [
|
||||||
|
{
|
||||||
|
sourceGroupId: statusEndpointFixture.importable_data[0].id,
|
||||||
|
newName: 'test',
|
||||||
|
targetNamespace: 'root',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await axios.waitForAll();
|
||||||
|
expect(results[0].progress.status).toBe(STATUSES.CREATED);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sets import status to FAILED and sets progress message for failed groups when request completes', async () => {
|
||||||
|
const FAKE_ERROR_MESSAGE = 'foo';
|
||||||
|
axiosMockAdapter
|
||||||
|
.onPost(FAKE_ENDPOINTS.createBulkImport)
|
||||||
|
.reply(httpStatus.OK, [{ success: false, id: 1, message: FAKE_ERROR_MESSAGE }]);
|
||||||
|
|
||||||
|
await client.mutate({
|
||||||
|
mutation: importGroupsMutation,
|
||||||
|
variables: {
|
||||||
|
importRequests: [
|
||||||
|
{
|
||||||
|
sourceGroupId: statusEndpointFixture.importable_data[0].id,
|
||||||
|
newName: 'test',
|
||||||
|
targetNamespace: 'root',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await axios.waitForAll();
|
||||||
|
expect(results[0].progress.status).toBe(STATUSES.FAILED);
|
||||||
|
expect(results[0].progress.message).toBe(FAKE_ERROR_MESSAGE);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('updateImportStatus updates status', async () => {
|
it('updateImportStatus updates status', async () => {
|
||||||
|
axiosMockAdapter
|
||||||
|
.onPost(FAKE_ENDPOINTS.createBulkImport)
|
||||||
|
.reply(httpStatus.OK, [{ success: true, id: 1 }]);
|
||||||
|
|
||||||
const NEW_STATUS = 'dummy';
|
const NEW_STATUS = 'dummy';
|
||||||
await client.mutate({
|
await client.mutate({
|
||||||
mutation: importGroupsMutation,
|
mutation: importGroupsMutation,
|
||||||
|
@ -216,6 +266,7 @@ describe('Bulk import resolvers', () => {
|
||||||
expect(statusInResponse).toStrictEqual({
|
expect(statusInResponse).toStrictEqual({
|
||||||
__typename: clientTypenames.BulkImportProgress,
|
__typename: clientTypenames.BulkImportProgress,
|
||||||
id,
|
id,
|
||||||
|
message: null,
|
||||||
status: NEW_STATUS,
|
status: NEW_STATUS,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { STATUSES } from '~/import_entities/constants';
|
import { STATUSES } from '~/import_entities/constants';
|
||||||
import { clientTypenames } from '~/import_entities/import_groups/graphql/client_factory';
|
import { clientTypenames } from '~/import_entities/import_groups/graphql/client_factory';
|
||||||
|
|
||||||
export const generateFakeEntry = ({ id, status, ...rest }) => ({
|
export const generateFakeEntry = ({ id, status, message, ...rest }) => ({
|
||||||
__typename: clientTypenames.BulkImportSourceGroup,
|
__typename: clientTypenames.BulkImportSourceGroup,
|
||||||
webUrl: `https://fake.host/${id}`,
|
webUrl: `https://fake.host/${id}`,
|
||||||
fullPath: `fake_group_${id}`,
|
fullPath: `fake_group_${id}`,
|
||||||
|
@ -18,6 +18,7 @@ export const generateFakeEntry = ({ id, status, ...rest }) => ({
|
||||||
: {
|
: {
|
||||||
id,
|
id,
|
||||||
status,
|
status,
|
||||||
|
message: message || '',
|
||||||
},
|
},
|
||||||
...rest,
|
...rest,
|
||||||
});
|
});
|
||||||
|
|
|
@ -4,7 +4,7 @@ exports[`PackagesListApp renders 1`] = `
|
||||||
<div>
|
<div>
|
||||||
<package-title-stub
|
<package-title-stub
|
||||||
count="2"
|
count="2"
|
||||||
helpurl="packageHelpUrl"
|
helpurl="/help/user/packages/index"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<package-search-stub />
|
<package-search-stub />
|
||||||
|
@ -49,7 +49,7 @@ exports[`PackagesListApp renders 1`] = `
|
||||||
<b-link-stub
|
<b-link-stub
|
||||||
class="gl-link"
|
class="gl-link"
|
||||||
event="click"
|
event="click"
|
||||||
href="emptyListHelpUrl"
|
href="/help/user/packages/package_registry/index"
|
||||||
routertag="a"
|
routertag="a"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
|
@ -6,7 +6,7 @@ import { nextTick } from 'vue';
|
||||||
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
||||||
import createMockApollo from 'helpers/mock_apollo_helper';
|
import createMockApollo from 'helpers/mock_apollo_helper';
|
||||||
import waitForPromises from 'helpers/wait_for_promises';
|
import waitForPromises from 'helpers/wait_for_promises';
|
||||||
import PackageListApp from '~/packages_and_registries/package_registry/components/list/app.vue';
|
import ListPage from '~/packages_and_registries/package_registry/pages/list.vue';
|
||||||
import PackageTitle from '~/packages_and_registries/package_registry/components/list/package_title.vue';
|
import PackageTitle from '~/packages_and_registries/package_registry/components/list/package_title.vue';
|
||||||
import PackageSearch from '~/packages_and_registries/package_registry/components/list/package_search.vue';
|
import PackageSearch from '~/packages_and_registries/package_registry/components/list/package_search.vue';
|
||||||
import OriginalPackageList from '~/packages_and_registries/package_registry/components/list/packages_list.vue';
|
import OriginalPackageList from '~/packages_and_registries/package_registry/components/list/packages_list.vue';
|
||||||
|
@ -16,11 +16,13 @@ import {
|
||||||
PROJECT_RESOURCE_TYPE,
|
PROJECT_RESOURCE_TYPE,
|
||||||
GROUP_RESOURCE_TYPE,
|
GROUP_RESOURCE_TYPE,
|
||||||
GRAPHQL_PAGE_SIZE,
|
GRAPHQL_PAGE_SIZE,
|
||||||
|
EMPTY_LIST_HELP_URL,
|
||||||
|
PACKAGE_HELP_URL,
|
||||||
} from '~/packages_and_registries/package_registry/constants';
|
} from '~/packages_and_registries/package_registry/constants';
|
||||||
|
|
||||||
import getPackagesQuery from '~/packages_and_registries/package_registry/graphql/queries/get_packages.query.graphql';
|
import getPackagesQuery from '~/packages_and_registries/package_registry/graphql/queries/get_packages.query.graphql';
|
||||||
|
|
||||||
import { packagesListQuery, packageData, pagination } from '../../mock_data';
|
import { packagesListQuery, packageData, pagination } from '../mock_data';
|
||||||
|
|
||||||
jest.mock('~/lib/utils/common_utils');
|
jest.mock('~/lib/utils/common_utils');
|
||||||
jest.mock('~/flash');
|
jest.mock('~/flash');
|
||||||
|
@ -32,9 +34,7 @@ describe('PackagesListApp', () => {
|
||||||
let apolloProvider;
|
let apolloProvider;
|
||||||
|
|
||||||
const defaultProvide = {
|
const defaultProvide = {
|
||||||
packageHelpUrl: 'packageHelpUrl',
|
|
||||||
emptyListIllustration: 'emptyListIllustration',
|
emptyListIllustration: 'emptyListIllustration',
|
||||||
emptyListHelpUrl: 'emptyListHelpUrl',
|
|
||||||
isGroupPage: true,
|
isGroupPage: true,
|
||||||
fullPath: 'gitlab-org',
|
fullPath: 'gitlab-org',
|
||||||
};
|
};
|
||||||
|
@ -66,7 +66,7 @@ describe('PackagesListApp', () => {
|
||||||
const requestHandlers = [[getPackagesQuery, resolver]];
|
const requestHandlers = [[getPackagesQuery, resolver]];
|
||||||
apolloProvider = createMockApollo(requestHandlers);
|
apolloProvider = createMockApollo(requestHandlers);
|
||||||
|
|
||||||
wrapper = shallowMountExtended(PackageListApp, {
|
wrapper = shallowMountExtended(ListPage, {
|
||||||
localVue,
|
localVue,
|
||||||
apolloProvider,
|
apolloProvider,
|
||||||
provide,
|
provide,
|
||||||
|
@ -113,7 +113,10 @@ describe('PackagesListApp', () => {
|
||||||
await waitForFirstRequest();
|
await waitForFirstRequest();
|
||||||
|
|
||||||
expect(findPackageTitle().exists()).toBe(true);
|
expect(findPackageTitle().exists()).toBe(true);
|
||||||
expect(findPackageTitle().props('count')).toBe(2);
|
expect(findPackageTitle().props()).toMatchObject({
|
||||||
|
count: 2,
|
||||||
|
helpUrl: PACKAGE_HELP_URL,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('search component', () => {
|
describe('search component', () => {
|
||||||
|
@ -213,12 +216,12 @@ describe('PackagesListApp', () => {
|
||||||
it('generate the correct empty list link', () => {
|
it('generate the correct empty list link', () => {
|
||||||
const link = findListComponent().findComponent(GlLink);
|
const link = findListComponent().findComponent(GlLink);
|
||||||
|
|
||||||
expect(link.attributes('href')).toBe(defaultProvide.emptyListHelpUrl);
|
expect(link.attributes('href')).toBe(EMPTY_LIST_HELP_URL);
|
||||||
expect(link.text()).toBe('publish and share your packages');
|
expect(link.text()).toBe('publish and share your packages');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('includes the right content on the default tab', () => {
|
it('includes the right content on the default tab', () => {
|
||||||
expect(findEmptyState().text()).toContain(PackageListApp.i18n.emptyPageTitle);
|
expect(findEmptyState().text()).toContain(ListPage.i18n.emptyPageTitle);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -234,8 +237,8 @@ describe('PackagesListApp', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should show specific empty message', () => {
|
it('should show specific empty message', () => {
|
||||||
expect(findEmptyState().text()).toContain(PackageListApp.i18n.noResultsTitle);
|
expect(findEmptyState().text()).toContain(ListPage.i18n.noResultsTitle);
|
||||||
expect(findEmptyState().text()).toContain(PackageListApp.i18n.widenFilters);
|
expect(findEmptyState().text()).toContain(ListPage.i18n.widenFilters);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -260,34 +260,4 @@ RSpec.describe PackagesHelper do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#packages_list_data' do
|
|
||||||
let_it_be(:resource) { project }
|
|
||||||
let_it_be(:type) { 'project' }
|
|
||||||
|
|
||||||
let(:expected_result) do
|
|
||||||
{
|
|
||||||
resource_id: resource.id,
|
|
||||||
full_path: resource.full_path,
|
|
||||||
page_type: type
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
subject(:result) { helper.packages_list_data(type, resource) }
|
|
||||||
|
|
||||||
context 'at a project level' do
|
|
||||||
it 'populates presenter data' do
|
|
||||||
expect(result).to match(hash_including(expected_result))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'at a group level' do
|
|
||||||
let_it_be(:resource) { create(:group) }
|
|
||||||
let_it_be(:type) { 'group' }
|
|
||||||
|
|
||||||
it 'populates presenter data' do
|
|
||||||
expect(result).to match(hash_including(expected_result))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -43,7 +43,7 @@ RSpec.describe Gitlab::Git::Tree, :seed_helper do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#dir?' do
|
describe '#dir?' do
|
||||||
let(:dir) { entries.select(&:dir?).first }
|
let(:dir) { entries.find(&:dir?) }
|
||||||
|
|
||||||
it { expect(dir).to be_kind_of Gitlab::Git::Tree }
|
it { expect(dir).to be_kind_of Gitlab::Git::Tree }
|
||||||
it { expect(dir.id).to eq('3c122d2b7830eca25235131070602575cf8b41a1') }
|
it { expect(dir.id).to eq('3c122d2b7830eca25235131070602575cf8b41a1') }
|
||||||
|
@ -134,7 +134,7 @@ RSpec.describe Gitlab::Git::Tree, :seed_helper do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#file?' do
|
describe '#file?' do
|
||||||
let(:file) { entries.select(&:file?).first }
|
let(:file) { entries.find(&:file?) }
|
||||||
|
|
||||||
it { expect(file).to be_kind_of Gitlab::Git::Tree }
|
it { expect(file).to be_kind_of Gitlab::Git::Tree }
|
||||||
it { expect(file.id).to eq('dfaa3f97ca337e20154a98ac9d0be76ddd1fcc82') }
|
it { expect(file.id).to eq('dfaa3f97ca337e20154a98ac9d0be76ddd1fcc82') }
|
||||||
|
@ -143,21 +143,21 @@ RSpec.describe Gitlab::Git::Tree, :seed_helper do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#readme?' do
|
describe '#readme?' do
|
||||||
let(:file) { entries.select(&:readme?).first }
|
let(:file) { entries.find(&:readme?) }
|
||||||
|
|
||||||
it { expect(file).to be_kind_of Gitlab::Git::Tree }
|
it { expect(file).to be_kind_of Gitlab::Git::Tree }
|
||||||
it { expect(file.name).to eq('README.md') }
|
it { expect(file.name).to eq('README.md') }
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#contributing?' do
|
describe '#contributing?' do
|
||||||
let(:file) { entries.select(&:contributing?).first }
|
let(:file) { entries.find(&:contributing?) }
|
||||||
|
|
||||||
it { expect(file).to be_kind_of Gitlab::Git::Tree }
|
it { expect(file).to be_kind_of Gitlab::Git::Tree }
|
||||||
it { expect(file.name).to eq('CONTRIBUTING.md') }
|
it { expect(file.name).to eq('CONTRIBUTING.md') }
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#submodule?' do
|
describe '#submodule?' do
|
||||||
let(:submodule) { entries.select(&:submodule?).first }
|
let(:submodule) { entries.find(&:submodule?) }
|
||||||
|
|
||||||
it { expect(submodule).to be_kind_of Gitlab::Git::Tree }
|
it { expect(submodule).to be_kind_of Gitlab::Git::Tree }
|
||||||
it { expect(submodule.id).to eq('79bceae69cb5750d6567b223597999bfa91cb3b9') }
|
it { expect(submodule.id).to eq('79bceae69cb5750d6567b223597999bfa91cb3b9') }
|
||||||
|
|
|
@ -43,10 +43,10 @@ RSpec.describe Gitlab::GitalyClient::ConflictFilesStitcher do
|
||||||
|
|
||||||
messages = [
|
messages = [
|
||||||
double(files: [double(header: header_1), double(header: nil, content: content_1[0..5])]),
|
double(files: [double(header: header_1), double(header: nil, content: content_1[0..5])]),
|
||||||
double(files: [double(header: nil, content: content_1[6..-1])]),
|
double(files: [double(header: nil, content: content_1[6..])]),
|
||||||
double(files: [double(header: header_2)]),
|
double(files: [double(header: header_2)]),
|
||||||
double(files: [double(header: nil, content: content_2[0..5]), double(header: nil, content: content_2[6..10])]),
|
double(files: [double(header: nil, content: content_2[0..5]), double(header: nil, content: content_2[6..10])]),
|
||||||
double(files: [double(header: nil, content: content_2[11..-1])])
|
double(files: [double(header: nil, content: content_2[11..])])
|
||||||
]
|
]
|
||||||
|
|
||||||
conflict_files = described_class.new(messages, target_repository.gitaly_repository).to_a
|
conflict_files = described_class.new(messages, target_repository.gitaly_repository).to_a
|
||||||
|
|
|
@ -41,7 +41,7 @@ RSpec.describe Gitlab::GitalyClient::DiffStitcher do
|
||||||
msg_2.raw_patch_data = diff_2.patch[0..100]
|
msg_2.raw_patch_data = diff_2.patch[0..100]
|
||||||
msg_2.end_of_patch = false
|
msg_2.end_of_patch = false
|
||||||
|
|
||||||
msg_3 = OpenStruct.new(raw_patch_data: diff_2.patch[101..-1], end_of_patch: true)
|
msg_3 = OpenStruct.new(raw_patch_data: diff_2.patch[101..], end_of_patch: true)
|
||||||
|
|
||||||
msg_4 = OpenStruct.new(diff_3.to_h.except(:patch))
|
msg_4 = OpenStruct.new(diff_3.to_h.except(:patch))
|
||||||
msg_4.raw_patch_data = diff_3.patch
|
msg_4.raw_patch_data = diff_3.patch
|
||||||
|
|
|
@ -192,7 +192,7 @@ RSpec.describe Gitlab::Gpg::InvalidGpgSignatureUpdater do
|
||||||
project: project,
|
project: project,
|
||||||
commit_sha: commit_sha,
|
commit_sha: commit_sha,
|
||||||
gpg_key: nil,
|
gpg_key: nil,
|
||||||
gpg_key_primary_keyid: GpgHelpers::User3.subkey_fingerprints.last[24..-1],
|
gpg_key_primary_keyid: GpgHelpers::User3.subkey_fingerprints.last[24..],
|
||||||
verification_status: 'unknown_key'
|
verification_status: 'unknown_key'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -98,7 +98,7 @@ RSpec.describe Gitlab::Graphql::Pagination::Keyset::Connection do
|
||||||
let(:nodes) { Project.all.order(Gitlab::Pagination::Keyset::Order.build([column_order_id_desc])) }
|
let(:nodes) { Project.all.order(Gitlab::Pagination::Keyset::Order.build([column_order_id_desc])) }
|
||||||
|
|
||||||
it 'returns the correct nodes' do
|
it 'returns the correct nodes' do
|
||||||
expect(subject.sliced_nodes).to contain_exactly(*projects[2..-1])
|
expect(subject.sliced_nodes).to contain_exactly(*projects[2..])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -107,7 +107,7 @@ RSpec.describe Gitlab::Graphql::Pagination::Keyset::Connection do
|
||||||
let(:arguments) { { after: encoded_cursor(projects[1]) } }
|
let(:arguments) { { after: encoded_cursor(projects[1]) } }
|
||||||
|
|
||||||
it 'only returns the project before the selected one' do
|
it 'only returns the project before the selected one' do
|
||||||
expect(subject.sliced_nodes).to contain_exactly(*projects[2..-1])
|
expect(subject.sliced_nodes).to contain_exactly(*projects[2..])
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when the sort order is descending' do
|
context 'when the sort order is descending' do
|
||||||
|
|
|
@ -120,7 +120,7 @@ RSpec.describe Gitlab::Graphql::Pagination::Keyset::Connection do
|
||||||
let(:nodes) { Project.all.order(id: :desc) }
|
let(:nodes) { Project.all.order(id: :desc) }
|
||||||
|
|
||||||
it 'returns the correct nodes' do
|
it 'returns the correct nodes' do
|
||||||
expect(subject.sliced_nodes).to contain_exactly(*projects[2..-1])
|
expect(subject.sliced_nodes).to contain_exactly(*projects[2..])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -129,7 +129,7 @@ RSpec.describe Gitlab::Graphql::Pagination::Keyset::Connection do
|
||||||
let(:arguments) { { after: encoded_cursor(projects[1]) } }
|
let(:arguments) { { after: encoded_cursor(projects[1]) } }
|
||||||
|
|
||||||
it 'only returns the project before the selected one' do
|
it 'only returns the project before the selected one' do
|
||||||
expect(subject.sliced_nodes).to contain_exactly(*projects[2..-1])
|
expect(subject.sliced_nodes).to contain_exactly(*projects[2..])
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when the sort order is descending' do
|
context 'when the sort order is descending' do
|
||||||
|
|
|
@ -224,6 +224,7 @@ ci_pipelines:
|
||||||
- ci_ref
|
- ci_ref
|
||||||
- stages
|
- stages
|
||||||
- statuses
|
- statuses
|
||||||
|
- statuses_order_id_desc
|
||||||
- latest_statuses_ordered_by_stage
|
- latest_statuses_ordered_by_stage
|
||||||
- builds
|
- builds
|
||||||
- bridges
|
- bridges
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
|
||||||
def match_mr1_note(content_regex)
|
def match_mr1_note(content_regex)
|
||||||
MergeRequest.find_by(title: 'MR1').notes.select { |n| n.note.match(/#{content_regex}/)}.first
|
MergeRequest.find_by(title: 'MR1').notes.find { |n| n.note.match(/#{content_regex}/) }
|
||||||
end
|
end
|
||||||
|
|
||||||
RSpec.describe Gitlab::ImportExport::Project::TreeRestorer do
|
RSpec.describe Gitlab::ImportExport::Project::TreeRestorer do
|
||||||
|
@ -75,7 +75,7 @@ RSpec.describe Gitlab::ImportExport::Project::TreeRestorer do
|
||||||
context 'for an Issue' do
|
context 'for an Issue' do
|
||||||
it 'does not import note_html' do
|
it 'does not import note_html' do
|
||||||
note_content = 'Quo reprehenderit aliquam qui dicta impedit cupiditate eligendi'
|
note_content = 'Quo reprehenderit aliquam qui dicta impedit cupiditate eligendi'
|
||||||
issue_note = Issue.find_by(description: 'Aliquam enim illo et possimus.').notes.select { |n| n.note.match(/#{note_content}/)}.first
|
issue_note = Issue.find_by(description: 'Aliquam enim illo et possimus.').notes.find { |n| n.note.match(/#{note_content}/) }
|
||||||
|
|
||||||
expect(issue_note.note_html).to match(/#{note_content}/)
|
expect(issue_note.note_html).to match(/#{note_content}/)
|
||||||
end
|
end
|
||||||
|
@ -552,7 +552,7 @@ RSpec.describe Gitlab::ImportExport::Project::TreeRestorer do
|
||||||
|
|
||||||
it 'issue system note metadata restored successfully' do
|
it 'issue system note metadata restored successfully' do
|
||||||
note_content = 'created merge request !1 to address this issue'
|
note_content = 'created merge request !1 to address this issue'
|
||||||
note = project.issues.first.notes.select { |n| n.note.match(/#{note_content}/)}.first
|
note = project.issues.first.notes.find { |n| n.note.match(/#{note_content}/)}
|
||||||
|
|
||||||
expect(note.noteable_type).to eq('Issue')
|
expect(note.noteable_type).to eq('Issue')
|
||||||
expect(note.system).to eq(true)
|
expect(note.system).to eq(true)
|
||||||
|
|
|
@ -40,7 +40,7 @@ RSpec.describe Gitlab::MultiCollectionPaginator do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'fils the last page with elements from the second collection' do
|
it 'fils the last page with elements from the second collection' do
|
||||||
expected_collection = all_groups[-2..-1]
|
expected_collection = all_groups[-2..]
|
||||||
|
|
||||||
expect(paginator.paginate(3)).to eq(expected_collection)
|
expect(paginator.paginate(3)).to eq(expected_collection)
|
||||||
end
|
end
|
||||||
|
|
|
@ -127,7 +127,7 @@ RSpec.describe Gitlab::Pagination::Keyset::Order do
|
||||||
end
|
end
|
||||||
|
|
||||||
it do
|
it do
|
||||||
expect(subject).to eq(expected.reverse[1..-1]) # removing one item because we used it to calculate cursor data for the "last" page in subject
|
expect(subject).to eq(expected.reverse[1..]) # removing one item because we used it to calculate cursor data for the "last" page in subject
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -78,7 +78,7 @@ RSpec.describe Gitlab::RackAttack, :aggregate_failures do
|
||||||
|
|
||||||
it 'configures tracks and throttles with a selected set of dry-runs' do
|
it 'configures tracks and throttles with a selected set of dry-runs' do
|
||||||
dry_run_throttles = throttles.each_key.first(2)
|
dry_run_throttles = throttles.each_key.first(2)
|
||||||
regular_throttles = throttles.keys[2..-1]
|
regular_throttles = throttles.keys[2..]
|
||||||
stub_env('GITLAB_THROTTLE_DRY_RUN', dry_run_throttles.join(','))
|
stub_env('GITLAB_THROTTLE_DRY_RUN', dry_run_throttles.join(','))
|
||||||
|
|
||||||
described_class.configure(fake_rack_attack)
|
described_class.configure(fake_rack_attack)
|
||||||
|
|
|
@ -44,20 +44,23 @@ RSpec.describe Gitlab::Redis::Sessions do
|
||||||
describe '#store' do
|
describe '#store' do
|
||||||
subject { described_class.store(namespace: described_class::SESSION_NAMESPACE) }
|
subject { described_class.store(namespace: described_class::SESSION_NAMESPACE) }
|
||||||
|
|
||||||
context 'when redis.sessions configuration is provided' do
|
context 'when redis.sessions configuration is NOT provided' do
|
||||||
it 'instantiates ::Redis instance' do
|
it 'instantiates ::Redis instance' do
|
||||||
expect(described_class).to receive(:config_fallback?).and_return(true)
|
expect(described_class).to receive(:config_fallback?).and_return(true)
|
||||||
expect(subject).to be_instance_of(::Redis::Store)
|
expect(subject).to be_instance_of(::Redis::Store)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when redis.sessions configuration is not provided' do
|
context 'when redis.sessions configuration is provided' do
|
||||||
|
before do
|
||||||
|
allow(described_class).to receive(:config_fallback?).and_return(false)
|
||||||
|
end
|
||||||
|
|
||||||
it 'instantiates an instance of MultiStore' do
|
it 'instantiates an instance of MultiStore' do
|
||||||
expect(described_class).to receive(:config_fallback?).and_return(false)
|
|
||||||
expect(subject).to be_instance_of(::Gitlab::Redis::MultiStore)
|
expect(subject).to be_instance_of(::Gitlab::Redis::MultiStore)
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
it_behaves_like 'multi store feature flags', :use_primary_and_secondary_stores_for_sessions, :use_primary_store_as_default_for_sessions
|
it_behaves_like 'multi store feature flags', :use_primary_and_secondary_stores_for_sessions, :use_primary_store_as_default_for_sessions
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -2506,7 +2506,7 @@ RSpec.describe Ci::Build do
|
||||||
it { is_expected.to start_with(project.web_url[0..6]) }
|
it { is_expected.to start_with(project.web_url[0..6]) }
|
||||||
it { is_expected.to include(build.token) }
|
it { is_expected.to include(build.token) }
|
||||||
it { is_expected.to include('gitlab-ci-token') }
|
it { is_expected.to include('gitlab-ci-token') }
|
||||||
it { is_expected.to include(project.web_url[7..-1]) }
|
it { is_expected.to include(project.web_url[7..]) }
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when token is empty' do
|
context 'when token is empty' do
|
||||||
|
|
|
@ -28,6 +28,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
|
||||||
it { is_expected.to have_many(:trigger_requests) }
|
it { is_expected.to have_many(:trigger_requests) }
|
||||||
it { is_expected.to have_many(:variables) }
|
it { is_expected.to have_many(:variables) }
|
||||||
it { is_expected.to have_many(:builds) }
|
it { is_expected.to have_many(:builds) }
|
||||||
|
it { is_expected.to have_many(:statuses_order_id_desc) }
|
||||||
it { is_expected.to have_many(:bridges) }
|
it { is_expected.to have_many(:bridges) }
|
||||||
it { is_expected.to have_many(:job_artifacts).through(:builds) }
|
it { is_expected.to have_many(:job_artifacts).through(:builds) }
|
||||||
it { is_expected.to have_many(:auto_canceled_pipelines) }
|
it { is_expected.to have_many(:auto_canceled_pipelines) }
|
||||||
|
|
|
@ -706,7 +706,7 @@ RSpec.describe Event do
|
||||||
|
|
||||||
describe '.for_wiki_meta' do
|
describe '.for_wiki_meta' do
|
||||||
it 'finds events for a given wiki page metadata object' do
|
it 'finds events for a given wiki page metadata object' do
|
||||||
event = events.select(&:wiki_page?).first
|
event = events.find(&:wiki_page?)
|
||||||
|
|
||||||
expect(described_class.for_wiki_meta(event.target)).to contain_exactly(event)
|
expect(described_class.for_wiki_meta(event.target)).to contain_exactly(event)
|
||||||
end
|
end
|
||||||
|
|
|
@ -330,6 +330,20 @@ RSpec.describe WebHook do
|
||||||
expect { hook.backoff! }.to change(hook, :backoff_count).by(1)
|
expect { hook.backoff! }.to change(hook, :backoff_count).by(1)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when the hook is permanently disabled' do
|
||||||
|
before do
|
||||||
|
allow(hook).to receive(:permanently_disabled?).and_return(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not set disabled_until' do
|
||||||
|
expect { hook.backoff! }.not_to change(hook, :disabled_until)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not increment the backoff count' do
|
||||||
|
expect { hook.backoff! }.not_to change(hook, :backoff_count)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context 'when we have backed off MAX_FAILURES times' do
|
context 'when we have backed off MAX_FAILURES times' do
|
||||||
before do
|
before do
|
||||||
stub_const("#{described_class}::MAX_FAILURES", 5)
|
stub_const("#{described_class}::MAX_FAILURES", 5)
|
||||||
|
@ -392,4 +406,77 @@ RSpec.describe WebHook do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#temporarily_disabled?' do
|
||||||
|
it 'is false when not temporarily disabled' do
|
||||||
|
expect(hook).not_to be_temporarily_disabled
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when hook has been told to back off' do
|
||||||
|
before do
|
||||||
|
hook.backoff!
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'is true' do
|
||||||
|
expect(hook).to be_temporarily_disabled
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'is false when `web_hooks_disable_failed` flag is disabled' do
|
||||||
|
stub_feature_flags(web_hooks_disable_failed: false)
|
||||||
|
|
||||||
|
expect(hook).not_to be_temporarily_disabled
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#permanently_disabled?' do
|
||||||
|
it 'is false when not disabled' do
|
||||||
|
expect(hook).not_to be_permanently_disabled
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when hook has been disabled' do
|
||||||
|
before do
|
||||||
|
hook.disable!
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'is true' do
|
||||||
|
expect(hook).to be_permanently_disabled
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'is false when `web_hooks_disable_failed` flag is disabled' do
|
||||||
|
stub_feature_flags(web_hooks_disable_failed: false)
|
||||||
|
|
||||||
|
expect(hook).not_to be_permanently_disabled
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#rate_limited?' do
|
||||||
|
context 'when there are rate limits' do
|
||||||
|
before do
|
||||||
|
allow(hook).to receive(:rate_limit).and_return(3)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'is false when hook has not been rate limited' do
|
||||||
|
expect(Gitlab::ApplicationRateLimiter).to receive(:peek).and_return(false)
|
||||||
|
expect(hook).not_to be_rate_limited
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'is true when hook has been rate limited' do
|
||||||
|
expect(Gitlab::ApplicationRateLimiter).to receive(:peek).and_return(true)
|
||||||
|
expect(hook).to be_rate_limited
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when there are no rate limits' do
|
||||||
|
before do
|
||||||
|
allow(hook).to receive(:rate_limit).and_return(nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not call Gitlab::ApplicationRateLimiter, and is false' do
|
||||||
|
expect(Gitlab::ApplicationRateLimiter).not_to receive(:peek)
|
||||||
|
expect(hook).not_to be_rate_limited
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -33,6 +33,7 @@ RSpec.describe API::Ci::Pipelines do
|
||||||
expect(json_response).to be_an Array
|
expect(json_response).to be_an Array
|
||||||
expect(json_response.first['sha']).to match(/\A\h{40}\z/)
|
expect(json_response.first['sha']).to match(/\A\h{40}\z/)
|
||||||
expect(json_response.first['id']).to eq pipeline.id
|
expect(json_response.first['id']).to eq pipeline.id
|
||||||
|
expect(json_response.first['iid']).to eq pipeline.iid
|
||||||
expect(json_response.first['web_url']).to be_present
|
expect(json_response.first['web_url']).to be_present
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -40,7 +41,7 @@ RSpec.describe API::Ci::Pipelines do
|
||||||
it 'includes pipeline source' do
|
it 'includes pipeline source' do
|
||||||
get api("/projects/#{project.id}/pipelines", user)
|
get api("/projects/#{project.id}/pipelines", user)
|
||||||
|
|
||||||
expect(json_response.first.keys).to contain_exactly(*%w[id project_id sha ref status web_url created_at updated_at source])
|
expect(json_response.first.keys).to contain_exactly(*%w[id iid project_id sha ref status web_url created_at updated_at source])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,7 @@ RSpec.describe SystemNotes::CommitService do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with multiple existing commits' do
|
context 'with multiple existing commits' do
|
||||||
let(:old_commits) { noteable.commits[3..-1] }
|
let(:old_commits) { noteable.commits[3..] }
|
||||||
|
|
||||||
context 'with oldrev' do
|
context 'with oldrev' do
|
||||||
let(:oldrev) { noteable.commits[2].id }
|
let(:oldrev) { noteable.commits[2].id }
|
||||||
|
|
|
@ -138,7 +138,7 @@ module GpgHelpers
|
||||||
end
|
end
|
||||||
|
|
||||||
def primary_keyid
|
def primary_keyid
|
||||||
fingerprint[-16..-1]
|
fingerprint[-16..]
|
||||||
end
|
end
|
||||||
|
|
||||||
def fingerprint
|
def fingerprint
|
||||||
|
@ -281,7 +281,7 @@ module GpgHelpers
|
||||||
end
|
end
|
||||||
|
|
||||||
def primary_keyid2
|
def primary_keyid2
|
||||||
fingerprint2[-16..-1]
|
fingerprint2[-16..]
|
||||||
end
|
end
|
||||||
|
|
||||||
def fingerprint2
|
def fingerprint2
|
||||||
|
@ -374,7 +374,7 @@ module GpgHelpers
|
||||||
end
|
end
|
||||||
|
|
||||||
def primary_keyid
|
def primary_keyid
|
||||||
fingerprint[-16..-1]
|
fingerprint[-16..]
|
||||||
end
|
end
|
||||||
|
|
||||||
def fingerprint
|
def fingerprint
|
||||||
|
@ -776,7 +776,7 @@ module GpgHelpers
|
||||||
end
|
end
|
||||||
|
|
||||||
def primary_keyid
|
def primary_keyid
|
||||||
fingerprint[-16..-1]
|
fingerprint[-16..]
|
||||||
end
|
end
|
||||||
|
|
||||||
def fingerprint
|
def fingerprint
|
||||||
|
|
|
@ -23,7 +23,7 @@ module MemoryUsageHelper
|
||||||
output, status = Gitlab::Popen.popen(%w(free -m))
|
output, status = Gitlab::Popen.popen(%w(free -m))
|
||||||
abort "`free -m` return code is #{status}: #{output}" unless status == 0
|
abort "`free -m` return code is #{status}: #{output}" unless status == 0
|
||||||
|
|
||||||
result = output.split("\n")[1].split(" ")[1..-1]
|
result = output.split("\n")[1].split(" ")[1..]
|
||||||
attrs = %i(m_total m_used m_free m_shared m_buffers_cache m_available).freeze
|
attrs = %i(m_total m_used m_free m_shared m_buffers_cache m_available).freeze
|
||||||
|
|
||||||
attrs.zip(result).to_h
|
attrs.zip(result).to_h
|
||||||
|
|
|
@ -8,10 +8,16 @@ RSpec.shared_examples "redis_new_instance_shared_examples" do |name, fallback_cl
|
||||||
let(:fallback_config_file) { nil }
|
let(:fallback_config_file) { nil }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
|
fallback_class.remove_instance_variable(:@_raw_config) rescue nil
|
||||||
|
|
||||||
allow(fallback_class).to receive(:config_file_name).and_return(fallback_config_file)
|
allow(fallback_class).to receive(:config_file_name).and_return(fallback_config_file)
|
||||||
end
|
end
|
||||||
|
|
||||||
include_examples "redis_shared_examples"
|
after do
|
||||||
|
fallback_class.remove_instance_variable(:@_raw_config) rescue nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it_behaves_like "redis_shared_examples"
|
||||||
|
|
||||||
describe '.config_file_name' do
|
describe '.config_file_name' do
|
||||||
subject { described_class.config_file_name }
|
subject { described_class.config_file_name }
|
||||||
|
|
Loading…
Reference in New Issue