diff options
101 files changed, 812 insertions, 1341 deletions
diff --git a/.gitlab/ci/review.gitlab-ci.yml b/.gitlab/ci/review.gitlab-ci.yml index 2b8c0dce162..e8d6f9b6dd9 100644 --- a/.gitlab/ci/review.gitlab-ci.yml +++ b/.gitlab/ci/review.gitlab-ci.yml @@ -2,7 +2,7 @@ review-cleanup: extends: - .default-retry - .review:rules:review-cleanup - image: registry.gitlab.com/gitlab-org/gitlab-build-images:gitlab-helm3.5-kubectl1.17 + image: registry.gitlab.com/gitlab-org/gitlab-build-images:gitlab-helm3-kubectl1.14 stage: prepare environment: name: review/auto-cleanup diff --git a/.rubocop_manual_todo.yml b/.rubocop_manual_todo.yml index d18ec37935a..d52cf65a704 100644 --- a/.rubocop_manual_todo.yml +++ b/.rubocop_manual_todo.yml @@ -178,61 +178,6 @@ Graphql/OldTypes: - 'app/graphql/types/container_repository_type.rb' - 'app/graphql/types/countable_connection_type.rb' - 'app/graphql/types/custom_emoji_type.rb' - - 'app/graphql/types/design_management/design_fields.rb' - - 'app/graphql/types/design_management/version_type.rb' - - 'app/graphql/types/diff_paths_input_type.rb' - - 'app/graphql/types/diff_refs_type.rb' - - 'app/graphql/types/diff_stats_summary_type.rb' - - 'app/graphql/types/diff_stats_type.rb' - - 'app/graphql/types/environment_type.rb' - - 'app/graphql/types/error_tracking/sentry_detailed_error_type.rb' - - 'app/graphql/types/error_tracking/sentry_error_collection_type.rb' - - 'app/graphql/types/error_tracking/sentry_error_frequency_type.rb' - - 'app/graphql/types/error_tracking/sentry_error_stack_trace_context_type.rb' - - 'app/graphql/types/error_tracking/sentry_error_stack_trace_entry_type.rb' - - 'app/graphql/types/error_tracking/sentry_error_stack_trace_type.rb' - - 'app/graphql/types/error_tracking/sentry_error_tags_type.rb' - - 'app/graphql/types/error_tracking/sentry_error_type.rb' - - 'app/graphql/types/event_type.rb' - - 'app/graphql/types/evidence_type.rb' - - 'app/graphql/types/grafana_integration_type.rb' - - 'app/graphql/types/invitation_interface.rb' - - 'app/graphql/types/issue_type.rb' - - 'app/graphql/types/issues/negated_issue_filter_input_type.rb' - - 'app/graphql/types/jira_import_type.rb' - - 'app/graphql/types/jira_user_type.rb' - - 'app/graphql/types/jira_users_mapping_input_type.rb' - - 'app/graphql/types/label_type.rb' - - 'app/graphql/types/member_interface.rb' - - 'app/graphql/types/merge_request_type.rb' - - 'app/graphql/types/metadata/kas_type.rb' - - 'app/graphql/types/metadata_type.rb' - - 'app/graphql/types/metrics/dashboard_type.rb' - - 'app/graphql/types/metrics/dashboards/annotation_type.rb' - - 'app/graphql/types/milestone_stats_type.rb' - - 'app/graphql/types/milestone_type.rb' - - 'app/graphql/types/namespace/package_settings_type.rb' - - 'app/graphql/types/namespace_type.rb' - - 'app/graphql/types/notes/diff_image_position_input_type.rb' - - 'app/graphql/types/notes/diff_position_base_input_type.rb' - - 'app/graphql/types/notes/diff_position_input_type.rb' - - 'app/graphql/types/notes/diff_position_type.rb' - - 'app/graphql/types/notes/note_type.rb' - - 'app/graphql/types/notes/update_diff_image_position_input_type.rb' - - 'app/graphql/types/packages/composer/json_type.rb' - - 'app/graphql/types/packages/composer/metadatum_type.rb' - - 'app/graphql/types/packages/conan/file_metadatum_type.rb' - - 'app/graphql/types/packages/conan/metadatum_type.rb' - - 'app/graphql/types/packages/maven/metadatum_type.rb' - - 'app/graphql/types/packages/nuget/metadatum_type.rb' - - 'app/graphql/types/packages/package_file_type.rb' - - 'app/graphql/types/packages/package_tag_type.rb' - - 'app/graphql/types/packages/package_type.rb' - - 'app/graphql/types/packages/pypi/metadatum_type.rb' - - 'app/graphql/types/project_type.rb' - - 'app/graphql/types/projects/service_type.rb' - - 'app/graphql/types/projects/services/jira_project_type.rb' - - 'app/graphql/types/prometheus_alert_type.rb' - 'app/graphql/types/query_complexity_type.rb' - 'app/graphql/types/release_asset_link_shared_input_arguments.rb' - 'app/graphql/types/release_asset_link_type.rb' diff --git a/app/assets/javascripts/blob/viewer/index.js b/app/assets/javascripts/blob/viewer/index.js index 4d133659daa..1bda7d4e3f0 100644 --- a/app/assets/javascripts/blob/viewer/index.js +++ b/app/assets/javascripts/blob/viewer/index.js @@ -36,6 +36,34 @@ const loadRichBlobViewer = (type) => { } }; +const loadViewer = (viewerParam) => { + const viewer = viewerParam; + const url = viewer.getAttribute('data-url'); + + if (!url || viewer.getAttribute('data-loaded') || viewer.getAttribute('data-loading')) { + return Promise.resolve(viewer); + } + + viewer.setAttribute('data-loading', 'true'); + + return axios.get(url).then(({ data }) => { + viewer.innerHTML = data.html; + + window.requestIdleCallback(() => { + viewer.removeAttribute('data-loading'); + }); + + return viewer; + }); +}; + +export const initAuxiliaryViewer = () => { + const auxiliaryViewer = document.querySelector('.blob-viewer[data-type="auxiliary"]'); + if (!auxiliaryViewer) return; + + loadViewer(auxiliaryViewer); +}; + export const handleBlobRichViewer = (viewer, type) => { if (!viewer || !type) return; @@ -49,27 +77,20 @@ export const handleBlobRichViewer = (viewer, type) => { }); }; -export default class BlobViewer { +export class BlobViewer { constructor() { performanceMarkAndMeasure({ mark: REPO_BLOB_LOAD_VIEWER_START, }); const viewer = document.querySelector('.blob-viewer[data-type="rich"]'); const type = viewer?.dataset?.richType; - BlobViewer.initAuxiliaryViewer(); + initAuxiliaryViewer(); handleBlobRichViewer(viewer, type); this.initMainViewers(); } - static initAuxiliaryViewer() { - const auxiliaryViewer = document.querySelector('.blob-viewer[data-type="auxiliary"]'); - if (!auxiliaryViewer) return; - - BlobViewer.loadViewer(auxiliaryViewer); - } - initMainViewers() { this.$fileHolder = $('.file-holder'); if (!this.$fileHolder.length) return; @@ -173,7 +194,7 @@ export default class BlobViewer { this.activeViewer = newViewer; this.toggleCopyButtonState(); - BlobViewer.loadViewer(newViewer) + loadViewer(newViewer) .then((viewer) => { $(viewer).renderGFM(); window.requestIdleCallback(() => { @@ -205,25 +226,4 @@ export default class BlobViewer { }), ); } - - static loadViewer(viewerParam) { - const viewer = viewerParam; - const url = viewer.getAttribute('data-url'); - - if (!url || viewer.getAttribute('data-loaded') || viewer.getAttribute('data-loading')) { - return Promise.resolve(viewer); - } - - viewer.setAttribute('data-loading', 'true'); - - return axios.get(url).then(({ data }) => { - viewer.innerHTML = data.html; - - window.requestIdleCallback(() => { - viewer.removeAttribute('data-loading'); - }); - - return viewer; - }); - } } diff --git a/app/assets/javascripts/cycle_analytics/components/stage_code_component.vue b/app/assets/javascripts/cycle_analytics/components/stage_code_component.vue deleted file mode 100644 index 6b757c6972a..00000000000 --- a/app/assets/javascripts/cycle_analytics/components/stage_code_component.vue +++ /dev/null @@ -1,56 +0,0 @@ -<script> -import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar_image.vue'; -import limitWarning from './limit_warning_component.vue'; -import totalTime from './total_time_component.vue'; - -export default { - components: { - userAvatarImage, - limitWarning, - totalTime, - }, - props: { - items: { - type: Array, - default: () => [], - required: false, - }, - stage: { - type: Object, - default: () => ({}), - required: false, - }, - }, -}; -</script> -<template> - <div> - <div class="events-description"> - {{ stage.description }} - <limit-warning :count="items.length" /> - </div> - <ul class="stage-event-list"> - <li v-for="(mergeRequest, i) in items" :key="i" class="stage-event-item"> - <div class="item-details"> - <!-- FIXME: Pass an alt attribute here for accessibility --> - <user-avatar-image :img-src="mergeRequest.author.avatarUrl" /> - <h5 class="item-title merge-request-title"> - <a :href="mergeRequest.url"> {{ mergeRequest.title }} </a> - </h5> - <a :href="mergeRequest.url" class="issue-link"> !{{ mergeRequest.iid }} </a> · - <span> - {{ s__('OpenedNDaysAgo|Opened') }} - <a :href="mergeRequest.url" class="issue-date"> {{ mergeRequest.createdAt }} </a> - </span> - <span> - {{ s__('ByAuthor|by') }} - <a :href="mergeRequest.author.webUrl" class="issue-author-link"> - {{ mergeRequest.author.name }} - </a> - </span> - </div> - <div class="item-time"><total-time :time="mergeRequest.totalTime" /></div> - </li> - </ul> - </div> -</template> diff --git a/app/assets/javascripts/cycle_analytics/components/stage_component.vue b/app/assets/javascripts/cycle_analytics/components/stage_component.vue deleted file mode 100644 index cc7ae74dd3a..00000000000 --- a/app/assets/javascripts/cycle_analytics/components/stage_component.vue +++ /dev/null @@ -1,54 +0,0 @@ -<script> -import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar_image.vue'; -import limitWarning from './limit_warning_component.vue'; -import totalTime from './total_time_component.vue'; - -export default { - components: { - userAvatarImage, - limitWarning, - totalTime, - }, - props: { - items: { - type: Array, - default: () => [], - required: false, - }, - stage: { - type: Object, - default: () => ({}), - required: false, - }, - }, -}; -</script> -<template> - <div> - <div class="events-description"> - {{ stage.description }} - <limit-warning :count="items.length" /> - </div> - <ul class="stage-event-list"> - <li v-for="(issue, i) in items" :key="i" class="stage-event-item"> - <div class="item-details"> - <!-- FIXME: Pass an alt attribute here for accessibility --> - <user-avatar-image :img-src="issue.author.avatarUrl" /> - <h5 class="item-title issue-title"> - <a :href="issue.url" class="issue-title"> {{ issue.title }} </a> - </h5> - <a :href="issue.url" class="issue-link">#{{ issue.iid }}</a> · - <span> - {{ s__('OpenedNDaysAgo|Opened') }} - <a :href="issue.url" class="issue-date">{{ issue.createdAt }}</a> - </span> - <span> - {{ s__('ByAuthor|by') }} - <a :href="issue.author.webUrl" class="issue-author-link"> {{ issue.author.name }} </a> - </span> - </div> - <div class="item-time"><total-time :time="issue.totalTime" /></div> - </li> - </ul> - </div> -</template> diff --git a/app/assets/javascripts/cycle_analytics/components/stage_nav_item.vue b/app/assets/javascripts/cycle_analytics/components/stage_nav_item.vue deleted file mode 100644 index 4b15bd55cbd..00000000000 --- a/app/assets/javascripts/cycle_analytics/components/stage_nav_item.vue +++ /dev/null @@ -1,60 +0,0 @@ -<script> -export default { - name: 'StageNavItem', - props: { - isDefaultStage: { - type: Boolean, - default: false, - required: false, - }, - isActive: { - type: Boolean, - default: false, - required: false, - }, - isUserAllowed: { - type: Boolean, - required: true, - }, - title: { - type: String, - required: true, - }, - value: { - type: String, - default: '', - required: false, - }, - }, - computed: { - hasValue() { - return this.value && this.value.length > 0; - }, - }, -}; -</script> - -<template> - <li @click="$emit('select')"> - <div - :class="{ active: isActive }" - class="stage-nav-item d-flex pl-4 pr-4 m-0 mb-1 ml-2 rounded border-color-default border-style-solid border-width-1px" - > - <div - class="stage-nav-item-cell stage-name w-50 pr-2" - :class="{ 'font-weight-bold': isActive }" - > - {{ title }} - </div> - <div class="stage-nav-item-cell stage-median w-50"> - <template v-if="isUserAllowed"> - <span v-if="hasValue">{{ value }}</span> - <span v-else class="stage-empty">{{ __('Not enough data') }}</span> - </template> - <template v-else> - <span class="not-available">{{ __('Not available') }}</span> - </template> - </div> - </div> - </li> -</template> diff --git a/app/assets/javascripts/cycle_analytics/components/stage_review_component.vue b/app/assets/javascripts/cycle_analytics/components/stage_review_component.vue deleted file mode 100644 index 33b4e649ab0..00000000000 --- a/app/assets/javascripts/cycle_analytics/components/stage_review_component.vue +++ /dev/null @@ -1,70 +0,0 @@ -<script> -import { GlIcon } from '@gitlab/ui'; -import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar_image.vue'; -import limitWarning from './limit_warning_component.vue'; -import totalTime from './total_time_component.vue'; - -export default { - components: { - userAvatarImage, - totalTime, - limitWarning, - GlIcon, - }, - props: { - items: { - type: Array, - default: () => [], - required: false, - }, - stage: { - type: Object, - default: () => ({}), - required: false, - }, - }, -}; -</script> -<template> - <div> - <div class="events-description"> - {{ stage.description }} - <limit-warning :count="items.length" /> - </div> - <ul class="stage-event-list"> - <li v-for="(mergeRequest, i) in items" :key="i" class="stage-event-item"> - <div class="item-details"> - <!-- FIXME: Pass an alt attribute here for accessibility --> - <user-avatar-image :img-src="mergeRequest.author.avatarUrl" /> - <h5 class="item-title merge-request-title"> - <a :href="mergeRequest.url"> {{ mergeRequest.title }} </a> - </h5> - <a :href="mergeRequest.url" class="issue-link">!{{ mergeRequest.iid }}</a> · - <span> - {{ s__('OpenedNDaysAgo|Opened') }} - <a :href="mergeRequest.url" class="issue-date">{{ mergeRequest.createdAt }}</a> - </span> - <span> - {{ s__('ByAuthor|by') }} - <a :href="mergeRequest.author.webUrl" class="issue-author-link">{{ - mergeRequest.author.name - }}</a> - </span> - <template v-if="mergeRequest.state === 'closed'"> - <span class="merge-request-state"> - <gl-icon name="cancel" class="gl-vertical-align-text-bottom" /> - {{ __('CLOSED') }} - </span> - </template> - <template v-else> - <span v-if="mergeRequest.branch" class="merge-request-branch"> - <gl-icon :size="16" name="fork" /> - <a :href="mergeRequest.branch.url"> {{ mergeRequest.branch.name }} </a> - </span> - </template> - </div> - <div class="item-time"><total-time :time="mergeRequest.totalTime" /></div> - </li> - </ul> - </div> -</template> diff --git a/app/assets/javascripts/cycle_analytics/components/stage_staging_component.vue b/app/assets/javascripts/cycle_analytics/components/stage_staging_component.vue deleted file mode 100644 index 6d8f711c13b..00000000000 --- a/app/assets/javascripts/cycle_analytics/components/stage_staging_component.vue +++ /dev/null @@ -1,60 +0,0 @@ -<script> -import { GlIcon, GlSafeHtmlDirective as SafeHtml } from '@gitlab/ui'; -import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar_image.vue'; -import limitWarning from './limit_warning_component.vue'; -import totalTime from './total_time_component.vue'; - -export default { - components: { - userAvatarImage, - totalTime, - limitWarning, - GlIcon, - }, - directives: { - SafeHtml, - }, - props: { - items: { - type: Array, - default: () => [], - required: false, - }, - stage: { - type: Object, - default: () => ({}), - required: false, - }, - }, -}; -</script> -<template> - <div> - <div class="events-description"> - {{ stage.description }} - <limit-warning :count="items.length" /> - </div> - <ul class="stage-event-list"> - <li v-for="(build, i) in items" :key="i" class="stage-event-item item-build-component"> - <div class="item-details"> - <!-- FIXME: Pass an alt attribute here for accessibility --> - <user-avatar-image :img-src="build.author.avatarUrl" /> - <h5 class="item-title"> - <a :href="build.url" class="pipeline-id"> #{{ build.id }} </a> - <gl-icon :size="16" name="fork" /> - <a :href="build.branch.url" class="ref-name"> {{ build.branch.name }} </a> - <span class="icon-branch gl-text-gray-400"> - <gl-icon name="commit" :size="14" /> - </span> - <a :href="build.commitUrl" class="commit-sha"> {{ build.shortSha }} </a> - </h5> - <span> - <a :href="build.url" class="build-date"> {{ build.date }} </a> {{ s__('ByAuthor|by') }} - <a :href="build.author.webUrl" class="issue-author-link"> {{ build.author.name }} </a> - </span> - </div> - <div class="item-time"><total-time :time="build.totalTime" /></div> - </li> - </ul> - </div> -</template> diff --git a/app/assets/javascripts/cycle_analytics/components/stage_test_component.vue b/app/assets/javascripts/cycle_analytics/components/stage_test_component.vue deleted file mode 100644 index c165c8cee78..00000000000 --- a/app/assets/javascripts/cycle_analytics/components/stage_test_component.vue +++ /dev/null @@ -1,56 +0,0 @@ -<script> -import { GlIcon } from '@gitlab/ui'; -import limitWarning from './limit_warning_component.vue'; -import totalTime from './total_time_component.vue'; - -export default { - components: { - totalTime, - limitWarning, - GlIcon, - }, - props: { - items: { - type: Array, - default: () => [], - required: false, - }, - stage: { - type: Object, - default: () => ({}), - required: false, - }, - }, -}; -</script> -<template> - <div> - <div class="events-description"> - {{ stage.description }} - <limit-warning :count="items.length" /> - </div> - <ul class="stage-event-list"> - <li v-for="(build, i) in items" :key="i" class="stage-event-item item-build-component"> - <div class="item-details"> - <h5 class="item-title"> - <span class="icon-build-status gl-text-green-500"> - <gl-icon name="status_success" :size="14" /> - </span> - <a :href="build.url" class="item-build-name"> {{ build.name }} </a> · - <a :href="build.url" class="pipeline-id"> #{{ build.id }} </a> - <gl-icon :size="16" name="fork" /> - <a :href="build.branch.url" class="ref-name"> {{ build.branch.name }} </a> - <span class="icon-branch gl-text-gray-400"> - <gl-icon name="commit" :size="14" /> - </span> - <a :href="build.commitUrl" class="commit-sha"> {{ build.shortSha }} </a> - </h5> - <span> - <a :href="build.url" class="issue-date"> {{ build.date }} </a> - </span> - </div> - <div class="item-time"><total-time :time="build.totalTime" /></div> - </li> - </ul> - </div> -</template> diff --git a/app/assets/javascripts/cycle_analytics/default_event_objects.js b/app/assets/javascripts/cycle_analytics/default_event_objects.js deleted file mode 100644 index 57f9019d2f8..00000000000 --- a/app/assets/javascripts/cycle_analytics/default_event_objects.js +++ /dev/null @@ -1,98 +0,0 @@ -export default { - issue: { - created_at: '', - url: '', - iid: '', - title: '', - total_time: {}, - author: { - avatar_url: '', - id: '', - name: '', - web_url: '', - }, - }, - plan: { - title: '', - commit_url: '', - short_sha: '', - total_time: {}, - author: { - name: '', - id: '', - avatar_url: '', - web_url: '', - }, - }, - code: { - title: '', - iid: '', - created_at: '', - url: '', - total_time: {}, - author: { - name: '', - id: '', - avatar_url: '', - web_url: '', - }, - }, - test: { - name: '', - id: '', - date: '', - url: '', - short_sha: '', - commit_url: '', - total_time: {}, - branch: { - name: '', - url: '', - }, - }, - review: { - title: '', - iid: '', - created_at: '', - url: '', - state: '', - total_time: {}, - author: { - name: '', - id: '', - avatar_url: '', - web_url: '', - }, - }, - staging: { - id: '', - short_sha: '', - date: '', - url: '', - commit_url: '', - total_time: {}, - author: { - name: '', - id: '', - avatar_url: '', - web_url: '', - }, - branch: { - name: '', - url: '', - }, - }, - production: { - title: '', - created_at: '', - url: '', - iid: '', - total_time: {}, - author: { - name: '', - id: '', - avatar_url: '', - web_url: '', - }, - }, -}; diff --git a/app/assets/javascripts/cycle_analytics/store/mutations.js b/app/assets/javascripts/cycle_analytics/store/mutations.js index 118d5174fd0..50157cc3618 100644 --- a/app/assets/javascripts/cycle_analytics/store/mutations.js +++ b/app/assets/javascripts/cycle_analytics/store/mutations.js @@ -1,11 +1,6 @@ import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; import { DEFAULT_DAYS_TO_DISPLAY } from '../constants'; -import { - decorateData, - decorateEvents, - formatMedianValues, - calculateFormattedDayInPast, -} from '../utils'; +import { decorateData, formatMedianValues, calculateFormattedDayInPast } from '../utils'; import * as types from './mutation_types'; export default { @@ -82,10 +77,11 @@ export default { state.hasError = false; }, [types.RECEIVE_STAGE_DATA_SUCCESS](state, { events = [] }) { - const { selectedStage } = state; state.isLoadingStage = false; state.isEmptyStage = !events.length; - state.selectedStageEvents = decorateEvents(events, selectedStage); + state.selectedStageEvents = events.map((ev) => + convertObjectPropsToCamelCase(ev, { deep: true }), + ); state.hasError = false; }, [types.RECEIVE_STAGE_DATA_ERROR](state, error) { diff --git a/app/assets/javascripts/cycle_analytics/utils.js b/app/assets/javascripts/cycle_analytics/utils.js index a1690dd1513..1f72291e97b 100644 --- a/app/assets/javascripts/cycle_analytics/utils.js +++ b/app/assets/javascripts/cycle_analytics/utils.js @@ -2,27 +2,10 @@ import dateFormat from 'dateformat'; import { unescape } from 'lodash'; import { dateFormats } from '~/analytics/shared/constants'; import { sanitize } from '~/lib/dompurify'; -import { roundToNearestHalf, convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; +import { roundToNearestHalf } from '~/lib/utils/common_utils'; import { getDateInPast } from '~/lib/utils/datetime/date_calculation_utility'; import { parseSeconds } from '~/lib/utils/datetime_utility'; import { s__, sprintf } from '../locale'; -import DEFAULT_EVENT_OBJECTS from './default_event_objects'; - -/** - * These `decorate` methods will be removed when me migrate to the - * new table layout https://gitlab.com/gitlab-org/gitlab/-/issues/326704 - */ -const mapToEvent = (event, stage) => { - return convertObjectPropsToCamelCase( - { - ...DEFAULT_EVENT_OBJECTS[stage.slug], - ...event, - }, - { deep: true }, - ); -}; - -export const decorateEvents = (events, stage) => events.map((event) => mapToEvent(event, stage)); const mapToSummary = ({ value, ...rest }) => ({ ...rest, value: value || '-' }); const mapToMedians = ({ name: id, value }) => ({ id, value }); diff --git a/app/assets/javascripts/pages/projects/artifacts/file/index.js b/app/assets/javascripts/pages/projects/artifacts/file/index.js index 057ef157374..07ee4d686cc 100644 --- a/app/assets/javascripts/pages/projects/artifacts/file/index.js +++ b/app/assets/javascripts/pages/projects/artifacts/file/index.js @@ -1,5 +1,5 @@ import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation'; -import BlobViewer from '~/blob/viewer/index'; +import { BlobViewer } from '~/blob/viewer/index'; new ShortcutsNavigation(); // eslint-disable-line no-new new BlobViewer(); // eslint-disable-line no-new diff --git a/app/assets/javascripts/pages/projects/blob/show/index.js b/app/assets/javascripts/pages/projects/blob/show/index.js index 6cc0095f5a5..e5b49dbcede 100644 --- a/app/assets/javascripts/pages/projects/blob/show/index.js +++ b/app/assets/javascripts/pages/projects/blob/show/index.js @@ -2,7 +2,7 @@ import Vue from 'vue'; import VueApollo from 'vue-apollo'; import TableOfContents from '~/blob/components/table_contents.vue'; import PipelineTourSuccessModal from '~/blob/pipeline_tour_success_modal.vue'; -import BlobViewer from '~/blob/viewer/index'; +import { BlobViewer } from '~/blob/viewer/index'; import GpgBadges from '~/gpg_badges'; import createDefaultClient from '~/lib/graphql'; import initBlob from '~/pages/projects/init_blob'; diff --git a/app/assets/javascripts/pages/projects/show/index.js b/app/assets/javascripts/pages/projects/show/index.js index 26f8018a968..78b3f2f1b30 100644 --- a/app/assets/javascripts/pages/projects/show/index.js +++ b/app/assets/javascripts/pages/projects/show/index.js @@ -1,7 +1,7 @@ import initTree from 'ee_else_ce/repository'; import Activities from '~/activities'; import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation'; -import BlobViewer from '~/blob/viewer/index'; +import { BlobViewer } from '~/blob/viewer/index'; import { initUploadForm } from '~/blob_edit/blob_bundle'; import initInviteMembersModal from '~/invite_members/init_invite_members_modal'; import initInviteMembersTrigger from '~/invite_members/init_invite_members_trigger'; diff --git a/app/graphql/types/design_management/design_fields.rb b/app/graphql/types/design_management/design_fields.rb index b770e30f5be..7779c3f1bcb 100644 --- a/app/graphql/types/design_management/design_fields.rb +++ b/app/graphql/types/design_management/design_fields.rb @@ -7,13 +7,13 @@ module Types field_class Types::BaseField - field :id, GraphQL::ID_TYPE, description: 'The ID of this design.', null: false + field :id, GraphQL::Types::ID, description: 'The ID of this design.', null: false field :project, Types::ProjectType, null: false, description: 'The project the design belongs to.' field :issue, Types::IssueType, null: false, description: 'The issue the design belongs to.' - field :filename, GraphQL::STRING_TYPE, null: false, description: 'The filename of the design.' - field :full_path, GraphQL::STRING_TYPE, null: false, description: 'The full path to the design file.' - field :image, GraphQL::STRING_TYPE, null: false, extras: [:parent], description: 'The URL of the full-sized image.' - field :image_v432x230, GraphQL::STRING_TYPE, null: true, extras: [:parent], + field :filename, GraphQL::Types::String, null: false, description: 'The filename of the design.' + field :full_path, GraphQL::Types::String, null: false, description: 'The full path to the design file.' + field :image, GraphQL::Types::String, null: false, extras: [:parent], description: 'The URL of the full-sized image.' + field :image_v432x230, GraphQL::Types::String, null: true, extras: [:parent], description: 'The URL of the design resized to fit within the bounds of 432x230. ' \ 'This will be `null` if the image has not been generated' field :diff_refs, Types::DiffRefsType, @@ -26,7 +26,7 @@ module Types extras: [:parent], description: 'How this design was changed in the current version.' field :notes_count, - GraphQL::INT_TYPE, + GraphQL::Types::Int, null: false, method: :user_notes_count, description: 'The total count of user-created notes for this design.' diff --git a/app/graphql/types/design_management/version_type.rb b/app/graphql/types/design_management/version_type.rb index 265d6185110..cfd2b887dc3 100644 --- a/app/graphql/types/design_management/version_type.rb +++ b/app/graphql/types/design_management/version_type.rb @@ -11,9 +11,9 @@ module Types authorize :read_design - field :id, GraphQL::ID_TYPE, null: false, + field :id, GraphQL::Types::ID, null: false, description: 'ID of the design version.' - field :sha, GraphQL::ID_TYPE, null: false, + field :sha, GraphQL::Types::ID, null: false, description: 'SHA of the design version.' field :designs, diff --git a/app/graphql/types/diff_paths_input_type.rb b/app/graphql/types/diff_paths_input_type.rb index d148b7656eb..e1d3d58411c 100644 --- a/app/graphql/types/diff_paths_input_type.rb +++ b/app/graphql/types/diff_paths_input_type.rb @@ -2,9 +2,9 @@ module Types class DiffPathsInputType < BaseInputObject - argument :old_path, GraphQL::STRING_TYPE, required: false, + argument :old_path, GraphQL::Types::String, required: false, description: 'The path of the file on the start sha.' - argument :new_path, GraphQL::STRING_TYPE, required: false, + argument :new_path, GraphQL::Types::String, required: false, description: 'The path of the file on the head sha.' end end diff --git a/app/graphql/types/diff_refs_type.rb b/app/graphql/types/diff_refs_type.rb index 3c8f934f1eb..b19d09c789c 100644 --- a/app/graphql/types/diff_refs_type.rb +++ b/app/graphql/types/diff_refs_type.rb @@ -6,11 +6,11 @@ module Types class DiffRefsType < BaseObject graphql_name 'DiffRefs' - field :head_sha, GraphQL::STRING_TYPE, null: false, + field :head_sha, GraphQL::Types::String, null: false, description: 'SHA of the HEAD at the time the comment was made.' - field :base_sha, GraphQL::STRING_TYPE, null: true, + field :base_sha, GraphQL::Types::String, null: true, description: 'Merge base of the branch the comment was made on.' - field :start_sha, GraphQL::STRING_TYPE, null: false, + field :start_sha, GraphQL::Types::String, null: false, description: 'SHA of the branch being compared against.' end # rubocop: enable Graphql/AuthorizeTypes diff --git a/app/graphql/types/diff_stats_summary_type.rb b/app/graphql/types/diff_stats_summary_type.rb index 78c0e2f2b4c..079c73d0759 100644 --- a/app/graphql/types/diff_stats_summary_type.rb +++ b/app/graphql/types/diff_stats_summary_type.rb @@ -8,13 +8,13 @@ module Types description 'Aggregated summary of changes' - field :additions, GraphQL::INT_TYPE, null: false, + field :additions, GraphQL::Types::Int, null: false, description: 'Number of lines added.' - field :deletions, GraphQL::INT_TYPE, null: false, + field :deletions, GraphQL::Types::Int, null: false, description: 'Number of lines deleted.' - field :changes, GraphQL::INT_TYPE, null: false, + field :changes, GraphQL::Types::Int, null: false, description: 'Number of lines changed.' - field :file_count, GraphQL::INT_TYPE, null: false, + field :file_count, GraphQL::Types::Int, null: false, description: 'Number of files changed.' def changes diff --git a/app/graphql/types/diff_stats_type.rb b/app/graphql/types/diff_stats_type.rb index 8a6840e5a94..60aacca8ce5 100644 --- a/app/graphql/types/diff_stats_type.rb +++ b/app/graphql/types/diff_stats_type.rb @@ -8,11 +8,11 @@ module Types description 'Changes to a single file' - field :path, GraphQL::STRING_TYPE, null: false, + field :path, GraphQL::Types::String, null: false, description: 'File path, relative to repository root.' - field :additions, GraphQL::INT_TYPE, null: false, + field :additions, GraphQL::Types::Int, null: false, description: 'Number of lines added to this file.' - field :deletions, GraphQL::INT_TYPE, null: false, + field :deletions, GraphQL::Types::Int, null: false, description: 'Number of lines deleted from this file.' end # rubocop: enable Graphql/AuthorizeTypes diff --git a/app/graphql/types/environment_type.rb b/app/graphql/types/environment_type.rb index 2e6417f08ea..267ca944198 100644 --- a/app/graphql/types/environment_type.rb +++ b/app/graphql/types/environment_type.rb @@ -9,16 +9,16 @@ module Types authorize :read_environment - field :name, GraphQL::STRING_TYPE, null: false, + field :name, GraphQL::Types::String, null: false, description: 'Human-readable name of the environment.' - field :id, GraphQL::ID_TYPE, null: false, + field :id, GraphQL::Types::ID, null: false, description: 'ID of the environment.' - field :state, GraphQL::STRING_TYPE, null: false, + field :state, GraphQL::Types::String, null: false, description: 'State of the environment, for example: available/stopped.' - field :path, GraphQL::STRING_TYPE, null: false, + field :path, GraphQL::Types::String, null: false, description: 'The path to the environment.' field :metrics_dashboard, Types::Metrics::DashboardType, null: true, diff --git a/app/graphql/types/error_tracking/sentry_detailed_error_type.rb b/app/graphql/types/error_tracking/sentry_detailed_error_type.rb index 59bd97e3448..79e789d3f8b 100644 --- a/app/graphql/types/error_tracking/sentry_detailed_error_type.rb +++ b/app/graphql/types/error_tracking/sentry_detailed_error_type.rb @@ -10,23 +10,23 @@ module Types authorize :read_sentry_issue - field :id, GraphQL::ID_TYPE, + field :id, GraphQL::Types::ID, null: false, description: 'ID (global ID) of the error.' - field :sentry_id, GraphQL::STRING_TYPE, + field :sentry_id, GraphQL::Types::String, method: :id, null: false, description: 'ID (Sentry ID) of the error.' - field :title, GraphQL::STRING_TYPE, + field :title, GraphQL::Types::String, null: false, description: 'Title of the error.' - field :type, GraphQL::STRING_TYPE, + field :type, GraphQL::Types::String, null: false, description: 'Type of the error.' - field :user_count, GraphQL::INT_TYPE, + field :user_count, GraphQL::Types::Int, null: false, description: 'Count of users affected by the error.' - field :count, GraphQL::INT_TYPE, + field :count, GraphQL::Types::Int, null: false, description: 'Count of occurrences.' field :first_seen, Types::TimeType, @@ -35,31 +35,31 @@ module Types field :last_seen, Types::TimeType, null: false, description: 'Timestamp when the error was last seen.' - field :message, GraphQL::STRING_TYPE, + field :message, GraphQL::Types::String, null: true, description: 'Sentry metadata message of the error.' - field :culprit, GraphQL::STRING_TYPE, + field :culprit, GraphQL::Types::String, null: false, description: 'Culprit of the error.' - field :external_base_url, GraphQL::STRING_TYPE, + field :external_base_url, GraphQL::Types::String, null: false, description: 'External Base URL of the Sentry Instance.' - field :external_url, GraphQL::STRING_TYPE, + field :external_url, GraphQL::Types::String, null: false, description: 'External URL of the error.' - field :sentry_project_id, GraphQL::ID_TYPE, + field :sentry_project_id, GraphQL::Types::ID, method: :project_id, null: false, description: 'ID of the project (Sentry project).' - field :sentry_project_name, GraphQL::STRING_TYPE, + field :sentry_project_name, GraphQL::Types::String, method: :project_name, null: false, description: 'Name of the project affected by the error.' - field :sentry_project_slug, GraphQL::STRING_TYPE, + field :sentry_project_slug, GraphQL::Types::String, method: :project_slug, null: false, description: 'Slug of the project affected by the error.' - field :short_id, GraphQL::STRING_TYPE, + field :short_id, GraphQL::Types::String, null: false, description: 'Short ID (Sentry ID) of the error.' field :status, Types::ErrorTracking::SentryErrorStatusEnum, @@ -68,31 +68,31 @@ module Types field :frequency, [Types::ErrorTracking::SentryErrorFrequencyType], null: false, description: 'Last 24hr stats of the error.' - field :first_release_last_commit, GraphQL::STRING_TYPE, + field :first_release_last_commit, GraphQL::Types::String, null: true, description: 'Commit the error was first seen.' - field :last_release_last_commit, GraphQL::STRING_TYPE, + field :last_release_last_commit, GraphQL::Types::String, null: true, description: 'Commit the error was last seen.' - field :first_release_short_version, GraphQL::STRING_TYPE, + field :first_release_short_version, GraphQL::Types::String, null: true, description: 'Release short version the error was first seen.' - field :last_release_short_version, GraphQL::STRING_TYPE, + field :last_release_short_version, GraphQL::Types::String, null: true, description: 'Release short version the error was last seen.' - field :first_release_version, GraphQL::STRING_TYPE, + field :first_release_version, GraphQL::Types::String, null: true, description: 'Release version the error was first seen.' - field :last_release_version, GraphQL::STRING_TYPE, + field :last_release_version, GraphQL::Types::String, null: true, description: 'Release version the error was last seen.' - field :gitlab_commit, GraphQL::STRING_TYPE, + field :gitlab_commit, GraphQL::Types::String, null: true, description: 'GitLab commit SHA attributed to the Error based on the release version.' - field :gitlab_commit_path, GraphQL::STRING_TYPE, + field :gitlab_commit_path, GraphQL::Types::String, null: true, description: 'Path to the GitLab page for the GitLab commit attributed to the error.' - field :gitlab_issue_path, GraphQL::STRING_TYPE, + field :gitlab_issue_path, GraphQL::Types::String, method: :gitlab_issue, null: true, description: 'URL of GitLab Issue.' diff --git a/app/graphql/types/error_tracking/sentry_error_collection_type.rb b/app/graphql/types/error_tracking/sentry_error_collection_type.rb index d3941b7c410..2d8c3d3d326 100644 --- a/app/graphql/types/error_tracking/sentry_error_collection_type.rb +++ b/app/graphql/types/error_tracking/sentry_error_collection_type.rb @@ -18,7 +18,7 @@ module Types description: 'Stack Trace of Sentry Error.', resolver: Resolvers::ErrorTracking::SentryErrorStackTraceResolver field :external_url, - GraphQL::STRING_TYPE, + GraphQL::Types::String, null: true, description: "External URL for Sentry." end diff --git a/app/graphql/types/error_tracking/sentry_error_frequency_type.rb b/app/graphql/types/error_tracking/sentry_error_frequency_type.rb index 05af1391af3..49a1b1e0476 100644 --- a/app/graphql/types/error_tracking/sentry_error_frequency_type.rb +++ b/app/graphql/types/error_tracking/sentry_error_frequency_type.rb @@ -9,7 +9,7 @@ module Types field :time, Types::TimeType, null: false, description: "Time the error frequency stats were recorded." - field :count, GraphQL::INT_TYPE, + field :count, GraphQL::Types::Int, null: false, description: "Count of errors received since the previously recorded time." end diff --git a/app/graphql/types/error_tracking/sentry_error_stack_trace_context_type.rb b/app/graphql/types/error_tracking/sentry_error_stack_trace_context_type.rb index 0b3c4cf55b9..ad31854b30c 100644 --- a/app/graphql/types/error_tracking/sentry_error_stack_trace_context_type.rb +++ b/app/graphql/types/error_tracking/sentry_error_stack_trace_context_type.rb @@ -8,11 +8,11 @@ module Types description 'An object context for a Sentry error stack trace' field :line, - GraphQL::INT_TYPE, + GraphQL::Types::Int, null: false, description: 'Line number of the context.' field :code, - GraphQL::STRING_TYPE, + GraphQL::Types::String, null: false, description: 'Code number of the context.' diff --git a/app/graphql/types/error_tracking/sentry_error_stack_trace_entry_type.rb b/app/graphql/types/error_tracking/sentry_error_stack_trace_entry_type.rb index c9915d052f9..e8f78004569 100644 --- a/app/graphql/types/error_tracking/sentry_error_stack_trace_entry_type.rb +++ b/app/graphql/types/error_tracking/sentry_error_stack_trace_entry_type.rb @@ -7,16 +7,16 @@ module Types graphql_name 'SentryErrorStackTraceEntry' description 'An object containing a stack trace entry for a Sentry error' - field :function, GraphQL::STRING_TYPE, + field :function, GraphQL::Types::String, null: true, description: 'Function in which the Sentry error occurred.' - field :col, GraphQL::STRING_TYPE, + field :col, GraphQL::Types::String, null: true, description: 'Function in which the Sentry error occurred.' - field :line, GraphQL::STRING_TYPE, + field :line, GraphQL::Types::String, null: true, description: 'Function in which the Sentry error occurred.' - field :file_name, GraphQL::STRING_TYPE, + field :file_name, GraphQL::Types::String, null: true, description: 'File in which the Sentry error occurred.' field :trace_context, [Types::ErrorTracking::SentryErrorStackTraceContextType], diff --git a/app/graphql/types/error_tracking/sentry_error_stack_trace_type.rb b/app/graphql/types/error_tracking/sentry_error_stack_trace_type.rb index 52959a9329b..dff52d77109 100644 --- a/app/graphql/types/error_tracking/sentry_error_stack_trace_type.rb +++ b/app/graphql/types/error_tracking/sentry_error_stack_trace_type.rb @@ -8,10 +8,10 @@ module Types authorize :read_sentry_issue - field :issue_id, GraphQL::STRING_TYPE, + field :issue_id, GraphQL::Types::String, null: false, description: 'ID of the Sentry error.' - field :date_received, GraphQL::STRING_TYPE, + field :date_received, GraphQL::Types::String, null: false, description: 'Time the stack trace was received by Sentry.' field :stack_trace_entries, [Types::ErrorTracking::SentryErrorStackTraceEntryType], diff --git a/app/graphql/types/error_tracking/sentry_error_tags_type.rb b/app/graphql/types/error_tracking/sentry_error_tags_type.rb index e2b051998c5..4d069615e3a 100644 --- a/app/graphql/types/error_tracking/sentry_error_tags_type.rb +++ b/app/graphql/types/error_tracking/sentry_error_tags_type.rb @@ -7,10 +7,10 @@ module Types graphql_name 'SentryErrorTags' description 'State of a Sentry error' - field :level, GraphQL::STRING_TYPE, + field :level, GraphQL::Types::String, null: true, description: "Severity level of the Sentry Error." - field :logger, GraphQL::STRING_TYPE, + field :logger, GraphQL::Types::String, null: true, description: "Logger of the Sentry Error." end diff --git a/app/graphql/types/error_tracking/sentry_error_type.rb b/app/graphql/types/error_tracking/sentry_error_type.rb index c0e09fb8c65..aaa6cbfb28f 100644 --- a/app/graphql/types/error_tracking/sentry_error_type.rb +++ b/app/graphql/types/error_tracking/sentry_error_type.rb @@ -9,10 +9,10 @@ module Types present_using SentryErrorPresenter - field :id, GraphQL::ID_TYPE, + field :id, GraphQL::Types::ID, null: false, description: 'ID (global ID) of the error.' - field :sentry_id, GraphQL::STRING_TYPE, + field :sentry_id, GraphQL::Types::String, method: :id, null: false, description: 'ID (Sentry ID) of the error.' @@ -22,28 +22,28 @@ module Types field :last_seen, Types::TimeType, null: false, description: 'Timestamp when the error was last seen.' - field :title, GraphQL::STRING_TYPE, + field :title, GraphQL::Types::String, null: false, description: 'Title of the error.' - field :type, GraphQL::STRING_TYPE, + field :type, GraphQL::Types::String, null: false, description: 'Type of the error.' - field :user_count, GraphQL::INT_TYPE, + field :user_count, GraphQL::Types::Int, null: false, description: 'Count of users affected by the error.' - field :count, GraphQL::INT_TYPE, + field :count, GraphQL::Types::Int, null: false, description: 'Count of occurrences.' - field :message, GraphQL::STRING_TYPE, + field :message, GraphQL::Types::String, null: true, description: 'Sentry metadata message of the error.' - field :culprit, GraphQL::STRING_TYPE, + field :culprit, GraphQL::Types::String, null: false, description: 'Culprit of the error.' - field :external_url, GraphQL::STRING_TYPE, + field :external_url, GraphQL::Types::String, null: false, description: 'External URL of the error.' - field :short_id, GraphQL::STRING_TYPE, + field :short_id, GraphQL::Types::String, null: false, description: 'Short ID (Sentry ID) of the error.' field :status, Types::ErrorTracking::SentryErrorStatusEnum, @@ -52,15 +52,15 @@ module Types field :frequency, [Types::ErrorTracking::SentryErrorFrequencyType], null: false, description: 'Last 24hr stats of the error.' - field :sentry_project_id, GraphQL::ID_TYPE, + field :sentry_project_id, GraphQL::Types::ID, method: :project_id, null: false, description: 'ID of the project (Sentry project).' - field :sentry_project_name, GraphQL::STRING_TYPE, + field :sentry_project_name, GraphQL::Types::String, method: :project_name, null: false, description: 'Name of the project affected by the error.' - field :sentry_project_slug, GraphQL::STRING_TYPE, + field :sentry_project_slug, GraphQL::Types::String, method: :project_slug, null: false, description: 'Slug of the project affected by the error.' diff --git a/app/graphql/types/event_type.rb b/app/graphql/types/event_type.rb index 2a4c2e7c60a..f4e680e93ef 100644 --- a/app/graphql/types/event_type.rb +++ b/app/graphql/types/event_type.rb @@ -9,7 +9,7 @@ module Types authorize :read_event - field :id, GraphQL::ID_TYPE, + field :id, GraphQL::Types::ID, description: 'ID of the event.', null: false diff --git a/app/graphql/types/evidence_type.rb b/app/graphql/types/evidence_type.rb index 6e56ad7d407..26fb64d25d8 100644 --- a/app/graphql/types/evidence_type.rb +++ b/app/graphql/types/evidence_type.rb @@ -9,11 +9,11 @@ module Types present_using Releases::EvidencePresenter - field :id, GraphQL::ID_TYPE, null: false, + field :id, GraphQL::Types::ID, null: false, description: 'ID of the evidence.' - field :sha, GraphQL::STRING_TYPE, null: true, + field :sha, GraphQL::Types::String, null: true, description: 'SHA1 ID of the evidence hash.' - field :filepath, GraphQL::STRING_TYPE, null: true, + field :filepath, GraphQL::Types::String, null: true, description: 'URL from where the evidence can be downloaded.' field :collected_at, Types::TimeType, null: true, description: 'Timestamp when the evidence was collected.' diff --git a/app/graphql/types/grafana_integration_type.rb b/app/graphql/types/grafana_integration_type.rb index 630d3a10e36..26fefd51e08 100644 --- a/app/graphql/types/grafana_integration_type.rb +++ b/app/graphql/types/grafana_integration_type.rb @@ -6,11 +6,11 @@ module Types authorize :admin_operations - field :id, GraphQL::ID_TYPE, null: false, + field :id, GraphQL::Types::ID, null: false, description: 'Internal ID of the Grafana integration.' - field :grafana_url, GraphQL::STRING_TYPE, null: false, + field :grafana_url, GraphQL::Types::String, null: false, description: 'URL for the Grafana host for the Grafana integration.' - field :enabled, GraphQL::BOOLEAN_TYPE, null: false, + field :enabled, GraphQL::Types::Boolean, null: false, description: 'Indicates whether Grafana integration is enabled.' field :created_at, Types::TimeType, null: false, description: 'Timestamp of the issue\'s creation.' diff --git a/app/graphql/types/group_type.rb b/app/graphql/types/group_type.rb index f5f399b7b89..fbf0084cd0e 100644 --- a/app/graphql/types/group_type.rb +++ b/app/graphql/types/group_type.rb @@ -9,12 +9,12 @@ module Types expose_permissions Types::PermissionTypes::Group field :web_url, - type: GraphQL::STRING_TYPE, + type: GraphQL::Types::String, null: false, description: 'Web URL of the group.' field :avatar_url, - type: GraphQL::STRING_TYPE, + type: GraphQL::Types::String, null: true, description: 'Avatar URL of the group.' @@ -25,42 +25,42 @@ module Types feature_flag: :custom_emoji field :share_with_group_lock, - type: GraphQL::BOOLEAN_TYPE, + type: GraphQL::Types::Boolean, null: true, description: 'Indicates if sharing a project with another group within this group is prevented.' field :project_creation_level, - type: GraphQL::STRING_TYPE, + type: GraphQL::Types::String, null: true, method: :project_creation_level_str, description: 'The permission level required to create projects in the group.' field :subgroup_creation_level, - type: GraphQL::STRING_TYPE, + type: GraphQL::Types::String, null: true, method: :subgroup_creation_level_str, description: 'The permission level required to create subgroups within the group.' field :require_two_factor_authentication, - type: GraphQL::BOOLEAN_TYPE, + type: GraphQL::Types::Boolean, null: true, description: 'Indicates if all users in this group are required to set up two-factor authentication.' field :two_factor_grace_period, - type: GraphQL::INT_TYPE, + type: GraphQL::Types::Int, null: true, description: 'Time before two-factor authentication is enforced.' field :auto_devops_enabled, - type: GraphQL::BOOLEAN_TYPE, + type: GraphQL::Types::Boolean, null: true, description: 'Indicates whether Auto DevOps is enabled for all projects within this group.' field :emails_disabled, - type: GraphQL::BOOLEAN_TYPE, + type: GraphQL::Types::Boolean, null: true, description: 'Indicates if a group has email notifications disabled.' field :mentions_disabled, - type: GraphQL::BOOLEAN_TYPE, + type: GraphQL::Types::Boolean, null: true, description: 'Indicates if a group is disabled from getting mentioned.' @@ -103,7 +103,7 @@ module Types null: true, description: 'A label available on this group.' do argument :title, - type: GraphQL::STRING_TYPE, + type: GraphQL::Types::String, required: true, description: 'Title of the label.' end @@ -120,7 +120,7 @@ module Types authorize: :read_container_image field :container_repositories_count, - type: GraphQL::INT_TYPE, + type: GraphQL::Types::Int, null: false, description: 'Number of container repositories in the group.' diff --git a/app/graphql/types/invitation_interface.rb b/app/graphql/types/invitation_interface.rb index b1f69f043f2..1f0746d7726 100644 --- a/app/graphql/types/invitation_interface.rb +++ b/app/graphql/types/invitation_interface.rb @@ -4,7 +4,7 @@ module Types module InvitationInterface include BaseInterface - field :email, GraphQL::STRING_TYPE, null: false, + field :email, GraphQL::Types::String, null: false, description: 'Email of the member to invite.' field :access_level, Types::AccessLevelType, null: true, diff --git a/app/graphql/types/issue_status_counts_type.rb b/app/graphql/types/issue_status_counts_type.rb index 77429f9ea12..e4a0782e3cf 100644 --- a/app/graphql/types/issue_status_counts_type.rb +++ b/app/graphql/types/issue_status_counts_type.rb @@ -15,7 +15,7 @@ module Types next unless available_issue_states.include?(state.downcase) field state, - GraphQL::INT_TYPE, + GraphQL::Types::Int, null: true, description: "Number of issues with status #{state.upcase} for the project" end diff --git a/app/graphql/types/issue_type.rb b/app/graphql/types/issue_type.rb index 6ff38273c03..bcb37021025 100644 --- a/app/graphql/types/issue_type.rb +++ b/app/graphql/types/issue_type.rb @@ -15,23 +15,23 @@ module Types present_using IssuePresenter - field :id, GraphQL::ID_TYPE, null: false, + field :id, GraphQL::Types::ID, null: false, description: "ID of the issue." - field :iid, GraphQL::ID_TYPE, null: false, + field :iid, GraphQL::Types::ID, null: false, description: "Internal ID of the issue." - field :title, GraphQL::STRING_TYPE, null: false, + field :title, GraphQL::Types::String, null: false, description: 'Title of the issue.' markdown_field :title_html, null: true - field :description, GraphQL::STRING_TYPE, null: true, + field :description, GraphQL::Types::String, null: true, description: 'Description of the issue.' markdown_field :description_html, null: true field :state, IssueStateEnum, null: false, description: 'State of the issue.' - field :reference, GraphQL::STRING_TYPE, null: false, + field :reference, GraphQL::Types::String, null: false, description: 'Internal reference of the issue. Returned in shortened format by default.', method: :to_reference do - argument :full, GraphQL::BOOLEAN_TYPE, required: false, default_value: false, + argument :full, GraphQL::Types::Boolean, required: false, default_value: false, description: 'Boolean option specifying whether the reference should be returned in full.' end @@ -51,42 +51,42 @@ module Types field :due_date, Types::TimeType, null: true, description: 'Due date of the issue.' - field :confidential, GraphQL::BOOLEAN_TYPE, null: false, + field :confidential, GraphQL::Types::Boolean, null: false, description: 'Indicates the issue is confidential.' - field :discussion_locked, GraphQL::BOOLEAN_TYPE, null: false, + field :discussion_locked, GraphQL::Types::Boolean, null: false, description: 'Indicates discussion is locked on the issue.' - field :upvotes, GraphQL::INT_TYPE, null: false, + field :upvotes, GraphQL::Types::Int, null: false, description: 'Number of upvotes the issue has received.' - field :downvotes, GraphQL::INT_TYPE, null: false, + field :downvotes, GraphQL::Types::Int, null: false, description: 'Number of downvotes the issue has received.' - field :user_notes_count, GraphQL::INT_TYPE, null: false, + field :user_notes_count, GraphQL::Types::Int, null: false, description: 'Number of user notes of the issue.', resolver: Resolvers::UserNotesCountResolver - field :user_discussions_count, GraphQL::INT_TYPE, null: false, + field :user_discussions_count, GraphQL::Types::Int, null: false, description: 'Number of user discussions in the issue.', resolver: Resolvers::UserDiscussionsCountResolver - field :web_path, GraphQL::STRING_TYPE, null: false, method: :issue_path, + field :web_path, GraphQL::Types::String, null: false, method: :issue_path, description: 'Web path of the issue.' - field :web_url, GraphQL::STRING_TYPE, null: false, + field :web_url, GraphQL::Types::String, null: false, description: 'Web URL of the issue.' - field :relative_position, GraphQL::INT_TYPE, null: true, + field :relative_position, GraphQL::Types::Int, null: true, description: 'Relative position of the issue (used for positioning in epic tree and issue boards).' field :participants, Types::UserType.connection_type, null: true, complexity: 5, description: 'List of participants in the issue.' - field :emails_disabled, GraphQL::BOOLEAN_TYPE, null: false, + field :emails_disabled, GraphQL::Types::Boolean, null: false, method: :project_emails_disabled?, description: 'Indicates if a project has email notifications disabled: `true` if email notifications are disabled.' - field :subscribed, GraphQL::BOOLEAN_TYPE, method: :subscribed?, null: false, complexity: 5, + field :subscribed, GraphQL::Types::Boolean, method: :subscribed?, null: false, complexity: 5, description: 'Indicates the currently logged in user is subscribed to the issue.' - field :time_estimate, GraphQL::INT_TYPE, null: false, + field :time_estimate, GraphQL::Types::Int, null: false, description: 'Time estimate of the issue.' - field :total_time_spent, GraphQL::INT_TYPE, null: false, + field :total_time_spent, GraphQL::Types::Int, null: false, description: 'Total time reported as spent on the issue.' - field :human_time_estimate, GraphQL::STRING_TYPE, null: true, + field :human_time_estimate, GraphQL::Types::String, null: true, description: 'Human-readable time estimate of the issue.' - field :human_total_time_spent, GraphQL::STRING_TYPE, null: true, + field :human_total_time_spent, GraphQL::Types::String, null: true, description: 'Human-readable total time reported as spent on the issue.' field :closed_at, Types::TimeType, null: true, @@ -115,19 +115,19 @@ module Types field :severity, Types::IssuableSeverityEnum, null: true, description: 'Severity level of the incident.' - field :moved, GraphQL::BOOLEAN_TYPE, method: :moved?, null: true, + field :moved, GraphQL::Types::Boolean, method: :moved?, null: true, description: 'Indicates if issue got moved from other project.' field :moved_to, Types::IssueType, null: true, description: 'Updated Issue after it got moved to another project.' - field :create_note_email, GraphQL::STRING_TYPE, null: true, + field :create_note_email, GraphQL::Types::String, null: true, description: 'User specific email address for the issue.' field :timelogs, Types::TimelogType.connection_type, null: false, description: 'Timelogs on the issue.' - field :project_id, GraphQL::INT_TYPE, null: false, method: :project_id, + field :project_id, GraphQL::Types::Int, null: false, method: :project_id, description: 'ID of the issue project.' def author diff --git a/app/graphql/types/issues/negated_issue_filter_input_type.rb b/app/graphql/types/issues/negated_issue_filter_input_type.rb index 88faf7e7074..201b1ee6b97 100644 --- a/app/graphql/types/issues/negated_issue_filter_input_type.rb +++ b/app/graphql/types/issues/negated_issue_filter_input_type.rb @@ -5,19 +5,19 @@ module Types class NegatedIssueFilterInputType < BaseInputObject graphql_name 'NegatedIssueFilterInput' - argument :iids, [GraphQL::STRING_TYPE], + argument :iids, [GraphQL::Types::String], required: false, description: 'List of IIDs of issues to exclude. For example, `[1, 2]`.' - argument :label_name, [GraphQL::STRING_TYPE], + argument :label_name, [GraphQL::Types::String], required: false, description: 'Labels not applied to this issue.' - argument :milestone_title, [GraphQL::STRING_TYPE], + argument :milestone_title, [GraphQL::Types::String], required: false, description: 'Milestone not applied to this issue.' - argument :assignee_usernames, [GraphQL::STRING_TYPE], + argument :assignee_usernames, [GraphQL::Types::String], required: false, description: 'Usernames of users not assigned to the issue.' - argument :assignee_id, GraphQL::STRING_TYPE, + argument :assignee_id, GraphQL::Types::String, required: false, description: 'ID of a user not assigned to the issues.' end diff --git a/app/graphql/types/jira_import_type.rb b/app/graphql/types/jira_import_type.rb index 6fa115933ac..0cdfc178350 100644 --- a/app/graphql/types/jira_import_type.rb +++ b/app/graphql/types/jira_import_type.rb @@ -12,13 +12,13 @@ module Types description: 'Timestamp of when the Jira import was scheduled.' field :scheduled_by, Types::UserType, null: true, description: 'User that started the Jira import.' - field :jira_project_key, GraphQL::STRING_TYPE, null: false, + field :jira_project_key, GraphQL::Types::String, null: false, description: 'Project key for the imported Jira project.' - field :imported_issues_count, GraphQL::INT_TYPE, null: false, + field :imported_issues_count, GraphQL::Types::Int, null: false, description: 'Count of issues that were successfully imported.' - field :failed_to_import_count, GraphQL::INT_TYPE, null: false, + field :failed_to_import_count, GraphQL::Types::Int, null: false, description: 'Count of issues that failed to import.' - field :total_issue_count, GraphQL::INT_TYPE, null: false, + field :total_issue_count, GraphQL::Types::Int, null: false, description: 'Total count of issues that were attempted to import.' end # rubocop: enable Graphql/AuthorizeTypes diff --git a/app/graphql/types/jira_user_type.rb b/app/graphql/types/jira_user_type.rb index 7ccb7ad6791..6e1c349726c 100644 --- a/app/graphql/types/jira_user_type.rb +++ b/app/graphql/types/jira_user_type.rb @@ -6,17 +6,17 @@ module Types class JiraUserType < BaseObject graphql_name 'JiraUser' - field :jira_account_id, GraphQL::STRING_TYPE, null: false, + field :jira_account_id, GraphQL::Types::String, null: false, description: 'Account ID of the Jira user.' - field :jira_display_name, GraphQL::STRING_TYPE, null: false, + field :jira_display_name, GraphQL::Types::String, null: false, description: 'Display name of the Jira user.' - field :jira_email, GraphQL::STRING_TYPE, null: true, + field :jira_email, GraphQL::Types::String, null: true, description: 'Email of the Jira user, returned only for users with public emails.' - field :gitlab_id, GraphQL::INT_TYPE, null: true, + field :gitlab_id, GraphQL::Types::Int, null: true, description: 'ID of the matched GitLab user.' - field :gitlab_username, GraphQL::STRING_TYPE, null: true, + field :gitlab_username, GraphQL::Types::String, null: true, description: 'Username of the matched GitLab user.' - field :gitlab_name, GraphQL::STRING_TYPE, null: true, + field :gitlab_name, GraphQL::Types::String, null: true, description: 'Name of the matched GitLab user.' end # rubocop: enable Graphql/AuthorizeTypes diff --git a/app/graphql/types/jira_users_mapping_input_type.rb b/app/graphql/types/jira_users_mapping_input_type.rb index 32640b9cb17..37fd05370c0 100644 --- a/app/graphql/types/jira_users_mapping_input_type.rb +++ b/app/graphql/types/jira_users_mapping_input_type.rb @@ -5,11 +5,11 @@ module Types graphql_name 'JiraUsersMappingInputType' argument :jira_account_id, - GraphQL::STRING_TYPE, + GraphQL::Types::String, required: true, description: 'Jira account ID of the user.' argument :gitlab_id, - GraphQL::INT_TYPE, + GraphQL::Types::Int, required: false, description: 'ID of the GitLab user.' end diff --git a/app/graphql/types/label_type.rb b/app/graphql/types/label_type.rb index 4e8718a80da..bb2d561014e 100644 --- a/app/graphql/types/label_type.rb +++ b/app/graphql/types/label_type.rb @@ -8,16 +8,16 @@ module Types authorize :read_label - field :id, GraphQL::ID_TYPE, null: false, + field :id, GraphQL::Types::ID, null: false, description: 'Label ID.' - field :description, GraphQL::STRING_TYPE, null: true, + field :description, GraphQL::Types::String, null: true, description: 'Description of the label (Markdown rendered as HTML for caching).' markdown_field :description_html, null: true - field :title, GraphQL::STRING_TYPE, null: false, + field :title, GraphQL::Types::String, null: false, description: 'Content of the label.' - field :color, GraphQL::STRING_TYPE, null: false, + field :color, GraphQL::Types::String, null: false, description: 'Background color of the label.' - field :text_color, GraphQL::STRING_TYPE, null: false, + field :text_color, GraphQL::Types::String, null: false, description: 'Text color of the label.' field :created_at, Types::TimeType, null: false, description: 'When this label was created.' diff --git a/app/graphql/types/member_interface.rb b/app/graphql/types/member_interface.rb index 6a21e51fe28..c5623cd4710 100644 --- a/app/graphql/types/member_interface.rb +++ b/app/graphql/types/member_interface.rb @@ -4,7 +4,7 @@ module Types module MemberInterface include BaseInterface - field :id, GraphQL::ID_TYPE, null: false, + field :id, GraphQL::Types::ID, null: false, description: 'ID of the member.' field :access_level, Types::AccessLevelType, null: true, diff --git a/app/graphql/types/merge_request_type.rb b/app/graphql/types/merge_request_type.rb index 0e9df926cdd..8e6b5421ede 100644 --- a/app/graphql/types/merge_request_type.rb +++ b/app/graphql/types/merge_request_type.rb @@ -15,14 +15,14 @@ module Types present_using MergeRequestPresenter - field :id, GraphQL::ID_TYPE, null: false, + field :id, GraphQL::Types::ID, null: false, description: 'ID of the merge request.' - field :iid, GraphQL::STRING_TYPE, null: false, + field :iid, GraphQL::Types::String, null: false, description: 'Internal ID of the merge request.' - field :title, GraphQL::STRING_TYPE, null: false, + field :title, GraphQL::Types::String, null: false, description: 'Title of the merge request.' markdown_field :title_html, null: true - field :description, GraphQL::STRING_TYPE, null: true, + field :description, GraphQL::Types::String, null: true, description: 'Description of the merge request (Markdown rendered as HTML for caching).' markdown_field :description_html, null: true field :state, MergeRequestStateEnum, null: false, @@ -41,91 +41,91 @@ module Types description: 'References of the base SHA, the head SHA, and the start SHA for this merge request.' field :project, Types::ProjectType, null: false, description: 'Alias for target_project.' - field :project_id, GraphQL::INT_TYPE, null: false, method: :target_project_id, + field :project_id, GraphQL::Types::Int, null: false, method: :target_project_id, description: 'ID of the merge request project.' - field :source_project_id, GraphQL::INT_TYPE, null: true, + field :source_project_id, GraphQL::Types::Int, null: true, description: 'ID of the merge request source project.' - field :target_project_id, GraphQL::INT_TYPE, null: false, + field :target_project_id, GraphQL::Types::Int, null: false, description: 'ID of the merge request target project.' - field :source_branch, GraphQL::STRING_TYPE, null: false, + field :source_branch, GraphQL::Types::String, null: false, description: 'Source branch of the merge request.' - field :source_branch_protected, GraphQL::BOOLEAN_TYPE, null: false, calls_gitaly: true, + field :source_branch_protected, GraphQL::Types::Boolean, null: false, calls_gitaly: true, description: 'Indicates if the source branch is protected.' - field :target_branch, GraphQL::STRING_TYPE, null: false, + field :target_branch, GraphQL::Types::String, null: false, description: 'Target branch of the merge request.' - field :work_in_progress, GraphQL::BOOLEAN_TYPE, method: :work_in_progress?, null: false, + field :work_in_progress, GraphQL::Types::Boolean, method: :work_in_progress?, null: false, deprecated: { reason: 'Use `draft`', milestone: '13.12' }, description: 'Indicates if the merge request is a draft.' - field :draft, GraphQL::BOOLEAN_TYPE, method: :draft?, null: false, + field :draft, GraphQL::Types::Boolean, method: :draft?, null: false, description: 'Indicates if the merge request is a draft.' - field :merge_when_pipeline_succeeds, GraphQL::BOOLEAN_TYPE, null: true, + field :merge_when_pipeline_succeeds, GraphQL::Types::Boolean, null: true, description: 'Indicates if the merge has been set to be merged when its pipeline succeeds (MWPS).' - field :diff_head_sha, GraphQL::STRING_TYPE, null: true, + field :diff_head_sha, GraphQL::Types::String, null: true, description: 'Diff head SHA of the merge request.' field :diff_stats, [Types::DiffStatsType], null: true, calls_gitaly: true, description: 'Details about which files were changed in this merge request.' do - argument :path, GraphQL::STRING_TYPE, required: false, description: 'A specific file-path.' + argument :path, GraphQL::Types::String, required: false, description: 'A specific file-path.' end field :diff_stats_summary, Types::DiffStatsSummaryType, null: true, calls_gitaly: true, description: 'Summary of which files were changed in this merge request.' - field :merge_commit_sha, GraphQL::STRING_TYPE, null: true, + field :merge_commit_sha, GraphQL::Types::String, null: true, description: 'SHA of the merge request commit (set once merged).' - field :user_notes_count, GraphQL::INT_TYPE, null: true, + field :user_notes_count, GraphQL::Types::Int, null: true, description: 'User notes count of the merge request.', resolver: Resolvers::UserNotesCountResolver - field :user_discussions_count, GraphQL::INT_TYPE, null: true, + field :user_discussions_count, GraphQL::Types::Int, null: true, description: 'Number of user discussions in the merge request.', resolver: Resolvers::UserDiscussionsCountResolver - field :should_remove_source_branch, GraphQL::BOOLEAN_TYPE, method: :should_remove_source_branch?, null: true, + field :should_remove_source_branch, GraphQL::Types::Boolean, method: :should_remove_source_branch?, null: true, description: 'Indicates if the source branch of the merge request will be deleted after merge.' - field :force_remove_source_branch, GraphQL::BOOLEAN_TYPE, method: :force_remove_source_branch?, null: true, + field :force_remove_source_branch, GraphQL::Types::Boolean, method: :force_remove_source_branch?, null: true, description: 'Indicates if the project settings will lead to source branch deletion after merge.' - field :merge_status, GraphQL::STRING_TYPE, method: :public_merge_status, null: true, + field :merge_status, GraphQL::Types::String, method: :public_merge_status, null: true, description: 'Status of the merge request.', deprecated: { reason: :renamed, replacement: 'MergeRequest.mergeStatusEnum', milestone: '14.0' } field :merge_status_enum, ::Types::MergeRequests::MergeStatusEnum, method: :public_merge_status, null: true, description: 'Merge status of the merge request.' - field :in_progress_merge_commit_sha, GraphQL::STRING_TYPE, null: true, + field :in_progress_merge_commit_sha, GraphQL::Types::String, null: true, description: 'Commit SHA of the merge request if merge is in progress.' - field :merge_error, GraphQL::STRING_TYPE, null: true, + field :merge_error, GraphQL::Types::String, null: true, description: 'Error message due to a merge error.' - field :allow_collaboration, GraphQL::BOOLEAN_TYPE, null: true, + field :allow_collaboration, GraphQL::Types::Boolean, null: true, description: 'Indicates if members of the target project can push to the fork.' - field :should_be_rebased, GraphQL::BOOLEAN_TYPE, method: :should_be_rebased?, null: false, calls_gitaly: true, + field :should_be_rebased, GraphQL::Types::Boolean, method: :should_be_rebased?, null: false, calls_gitaly: true, description: 'Indicates if the merge request will be rebased.' - field :rebase_commit_sha, GraphQL::STRING_TYPE, null: true, + field :rebase_commit_sha, GraphQL::Types::String, null: true, description: 'Rebase commit SHA of the merge request.' - field :rebase_in_progress, GraphQL::BOOLEAN_TYPE, method: :rebase_in_progress?, null: false, calls_gitaly: true, + field :rebase_in_progress, GraphQL::Types::Boolean, method: :rebase_in_progress?, null: false, calls_gitaly: true, description: 'Indicates if there is a rebase currently in progress for the merge request.' - field :default_merge_commit_message, GraphQL::STRING_TYPE, null: true, + field :default_merge_commit_message, GraphQL::Types::String, null: true, description: 'Default merge commit message of the merge request.' - field :default_merge_commit_message_with_description, GraphQL::STRING_TYPE, null: true, + field :default_merge_commit_message_with_description, GraphQL::Types::String, null: true, description: 'Default merge commit message of the merge request with description.' - field :default_squash_commit_message, GraphQL::STRING_TYPE, null: true, calls_gitaly: true, + field :default_squash_commit_message, GraphQL::Types::String, null: true, calls_gitaly: true, description: 'Default squash commit message of the merge request.' - field :merge_ongoing, GraphQL::BOOLEAN_TYPE, method: :merge_ongoing?, null: false, + field :merge_ongoing, GraphQL::Types::Boolean, method: :merge_ongoing?, null: false, description: 'Indicates if a merge is currently occurring.' - field :source_branch_exists, GraphQL::BOOLEAN_TYPE, + field :source_branch_exists, GraphQL::Types::Boolean, null: false, calls_gitaly: true, method: :source_branch_exists?, description: 'Indicates if the source branch of the merge request exists.' - field :target_branch_exists, GraphQL::BOOLEAN_TYPE, + field :target_branch_exists, GraphQL::Types::Boolean, null: false, calls_gitaly: true, method: :target_branch_exists?, description: 'Indicates if the target branch of the merge request exists.' - field :diverged_from_target_branch, GraphQL::BOOLEAN_TYPE, + field :diverged_from_target_branch, GraphQL::Types::Boolean, null: false, calls_gitaly: true, method: :diverged_from_target_branch?, description: 'Indicates if the source branch is behind the target branch.' - field :mergeable_discussions_state, GraphQL::BOOLEAN_TYPE, null: true, + field :mergeable_discussions_state, GraphQL::Types::Boolean, null: true, description: 'Indicates if all discussions in the merge request have been resolved, allowing the merge request to be merged.' - field :web_url, GraphQL::STRING_TYPE, null: true, + field :web_url, GraphQL::Types::String, null: true, description: 'Web URL of the merge request.' - field :upvotes, GraphQL::INT_TYPE, null: false, + field :upvotes, GraphQL::Types::Int, null: false, description: 'Number of upvotes for the merge request.' - field :downvotes, GraphQL::INT_TYPE, null: false, + field :downvotes, GraphQL::Types::Int, null: false, description: 'Number of downvotes for the merge request.' field :head_pipeline, Types::Ci::PipelineType, null: true, method: :actual_head_pipeline, @@ -151,52 +151,52 @@ module Types description: 'User who created this merge request.' field :participants, Types::UserType.connection_type, null: true, complexity: 15, description: 'Participants in the merge request. This includes the author, assignees, reviewers, and users mentioned in notes.' - field :subscribed, GraphQL::BOOLEAN_TYPE, method: :subscribed?, null: false, complexity: 5, + field :subscribed, GraphQL::Types::Boolean, method: :subscribed?, null: false, complexity: 5, description: 'Indicates if the currently logged in user is subscribed to this merge request.' field :labels, Types::LabelType.connection_type, null: true, complexity: 5, description: 'Labels of the merge request.' - field :discussion_locked, GraphQL::BOOLEAN_TYPE, + field :discussion_locked, GraphQL::Types::Boolean, description: 'Indicates if comments on the merge request are locked to members only.', null: false - field :time_estimate, GraphQL::INT_TYPE, null: false, + field :time_estimate, GraphQL::Types::Int, null: false, description: 'Time estimate of the merge request.' - field :total_time_spent, GraphQL::INT_TYPE, null: false, + field :total_time_spent, GraphQL::Types::Int, null: false, description: 'Total time reported as spent on the merge request.' - field :human_time_estimate, GraphQL::STRING_TYPE, null: true, + field :human_time_estimate, GraphQL::Types::String, null: true, description: 'Human-readable time estimate of the merge request.' - field :human_total_time_spent, GraphQL::STRING_TYPE, null: true, + field :human_total_time_spent, GraphQL::Types::String, null: true, description: 'Human-readable total time reported as spent on the merge request.' - field :reference, GraphQL::STRING_TYPE, null: false, method: :to_reference, + field :reference, GraphQL::Types::String, null: false, method: :to_reference, description: 'Internal reference of the merge request. Returned in shortened format by default.' do - argument :full, GraphQL::BOOLEAN_TYPE, required: false, default_value: false, + argument :full, GraphQL::Types::Boolean, required: false, default_value: false, description: 'Boolean option specifying whether the reference should be returned in full.' end field :task_completion_status, Types::TaskCompletionStatus, null: false, description: Types::TaskCompletionStatus.description - field :commit_count, GraphQL::INT_TYPE, null: true, method: :commits_count, + field :commit_count, GraphQL::Types::Int, null: true, method: :commits_count, description: 'Number of commits in the merge request.' - field :conflicts, GraphQL::BOOLEAN_TYPE, null: false, method: :cannot_be_merged?, + field :conflicts, GraphQL::Types::Boolean, null: false, method: :cannot_be_merged?, description: 'Indicates if the merge request has conflicts.' - field :auto_merge_enabled, GraphQL::BOOLEAN_TYPE, null: false, + field :auto_merge_enabled, GraphQL::Types::Boolean, null: false, description: 'Indicates if auto merge is enabled for the merge request.' field :approved_by, Types::UserType.connection_type, null: true, description: 'Users who approved the merge request.' - field :squash_on_merge, GraphQL::BOOLEAN_TYPE, null: false, method: :squash_on_merge?, + field :squash_on_merge, GraphQL::Types::Boolean, null: false, method: :squash_on_merge?, description: 'Indicates if squash on merge is enabled.' - field :squash, GraphQL::BOOLEAN_TYPE, null: false, + field :squash, GraphQL::Types::Boolean, null: false, description: 'Indicates if squash on merge is enabled.' - field :available_auto_merge_strategies, [GraphQL::STRING_TYPE], null: true, calls_gitaly: true, + field :available_auto_merge_strategies, [GraphQL::Types::String], null: true, calls_gitaly: true, description: 'Array of available auto merge strategies.' - field :has_ci, GraphQL::BOOLEAN_TYPE, null: false, method: :has_ci?, + field :has_ci, GraphQL::Types::Boolean, null: false, method: :has_ci?, description: 'Indicates if the merge request has CI.' - field :mergeable, GraphQL::BOOLEAN_TYPE, null: false, method: :mergeable?, calls_gitaly: true, + field :mergeable, GraphQL::Types::Boolean, null: false, method: :mergeable?, calls_gitaly: true, description: 'Indicates if the merge request is mergeable.' field :commits_without_merge_commits, Types::CommitType.connection_type, null: true, calls_gitaly: true, description: 'Merge request commits excluding merge commits.' - field :security_auto_fix, GraphQL::BOOLEAN_TYPE, null: true, + field :security_auto_fix, GraphQL::Types::Boolean, null: true, description: 'Indicates if the merge request is created by @GitLab-Security-Bot.' - field :auto_merge_strategy, GraphQL::STRING_TYPE, null: true, + field :auto_merge_strategy, GraphQL::Types::String, null: true, description: 'Selected auto merge strategy.' field :merge_user, Types::UserType, null: true, description: 'User who merged this merge request.' diff --git a/app/graphql/types/metadata/kas_type.rb b/app/graphql/types/metadata/kas_type.rb index 8af4c23270b..a947986fa60 100644 --- a/app/graphql/types/metadata/kas_type.rb +++ b/app/graphql/types/metadata/kas_type.rb @@ -7,11 +7,11 @@ module Types authorize :read_instance_metadata - field :enabled, GraphQL::BOOLEAN_TYPE, null: false, + field :enabled, GraphQL::Types::Boolean, null: false, description: 'Indicates whether the Kubernetes Agent Server is enabled.' - field :version, GraphQL::STRING_TYPE, null: true, + field :version, GraphQL::Types::String, null: true, description: 'KAS version.' - field :external_url, GraphQL::STRING_TYPE, null: true, + field :external_url, GraphQL::Types::String, null: true, description: 'The URL used by the Agents to communicate with KAS.' end end diff --git a/app/graphql/types/metadata_type.rb b/app/graphql/types/metadata_type.rb index 851c2a3f1e3..ed1e697711d 100644 --- a/app/graphql/types/metadata_type.rb +++ b/app/graphql/types/metadata_type.rb @@ -6,9 +6,9 @@ module Types authorize :read_instance_metadata - field :version, GraphQL::STRING_TYPE, null: false, + field :version, GraphQL::Types::String, null: false, description: 'Version.' - field :revision, GraphQL::STRING_TYPE, null: false, + field :revision, GraphQL::Types::String, null: false, description: 'Revision.' field :kas, ::Types::Metadata::KasType, null: false, description: 'Metadata about KAS.' diff --git a/app/graphql/types/metrics/dashboard_type.rb b/app/graphql/types/metrics/dashboard_type.rb index 40d2c2f195c..04cac55894e 100644 --- a/app/graphql/types/metrics/dashboard_type.rb +++ b/app/graphql/types/metrics/dashboard_type.rb @@ -7,10 +7,10 @@ module Types class DashboardType < ::Types::BaseObject graphql_name 'MetricsDashboard' - field :path, GraphQL::STRING_TYPE, null: true, + field :path, GraphQL::Types::String, null: true, description: 'Path to a file with the dashboard definition.' - field :schema_validation_warnings, [GraphQL::STRING_TYPE], null: true, + field :schema_validation_warnings, [GraphQL::Types::String], null: true, description: 'Dashboard schema validation warnings.' field :annotations, Types::Metrics::Dashboards::AnnotationType.connection_type, null: true, diff --git a/app/graphql/types/metrics/dashboards/annotation_type.rb b/app/graphql/types/metrics/dashboards/annotation_type.rb index b9e040dd063..fb35f2bd9a1 100644 --- a/app/graphql/types/metrics/dashboards/annotation_type.rb +++ b/app/graphql/types/metrics/dashboards/annotation_type.rb @@ -7,13 +7,13 @@ module Types authorize :read_metrics_dashboard_annotation graphql_name 'MetricsDashboardAnnotation' - field :description, GraphQL::STRING_TYPE, null: true, + field :description, GraphQL::Types::String, null: true, description: 'Description of the annotation.' - field :id, GraphQL::ID_TYPE, null: false, + field :id, GraphQL::Types::ID, null: false, description: 'ID of the annotation.' - field :panel_id, GraphQL::STRING_TYPE, null: true, + field :panel_id, GraphQL::Types::String, null: true, description: 'ID of a dashboard panel to which the annotation should be scoped.' field :starting_at, Types::TimeType, null: true, diff --git a/app/graphql/types/milestone_stats_type.rb b/app/graphql/types/milestone_stats_type.rb index e313b880e0d..6d8b7deb8e7 100644 --- a/app/graphql/types/milestone_stats_type.rb +++ b/app/graphql/types/milestone_stats_type.rb @@ -7,10 +7,10 @@ module Types authorize :read_milestone - field :total_issues_count, GraphQL::INT_TYPE, null: true, + field :total_issues_count, GraphQL::Types::Int, null: true, description: 'Total number of issues associated with the milestone.' - field :closed_issues_count, GraphQL::INT_TYPE, null: true, + field :closed_issues_count, GraphQL::Types::Int, null: true, description: 'Number of closed issues associated with the milestone.' end end diff --git a/app/graphql/types/milestone_type.rb b/app/graphql/types/milestone_type.rb index 27bc77b4da1..18e4a5d33e3 100644 --- a/app/graphql/types/milestone_type.rb +++ b/app/graphql/types/milestone_type.rb @@ -11,25 +11,25 @@ module Types alias_method :milestone, :object - field :id, GraphQL::ID_TYPE, null: false, + field :id, GraphQL::Types::ID, null: false, description: 'ID of the milestone.' - field :iid, GraphQL::ID_TYPE, null: false, + field :iid, GraphQL::Types::ID, null: false, description: "Internal ID of the milestone." - field :title, GraphQL::STRING_TYPE, null: false, + field :title, GraphQL::Types::String, null: false, description: 'Title of the milestone.' - field :description, GraphQL::STRING_TYPE, null: true, + field :description, GraphQL::Types::String, null: true, description: 'Description of the milestone.' field :state, Types::MilestoneStateEnum, null: false, description: 'State of the milestone.' - field :expired, GraphQL::BOOLEAN_TYPE, null: false, + field :expired, GraphQL::Types::Boolean, null: false, description: 'Expired state of the milestone (a milestone is expired when the due date is past the current date). Defaults to `false` when due date has not been set.' - field :web_path, GraphQL::STRING_TYPE, null: false, method: :milestone_path, + field :web_path, GraphQL::Types::String, null: false, method: :milestone_path, description: 'Web path of the milestone.' field :due_date, Types::TimeType, null: true, @@ -44,15 +44,15 @@ module Types field :updated_at, Types::TimeType, null: false, description: 'Timestamp of last milestone update.' - field :project_milestone, GraphQL::BOOLEAN_TYPE, null: false, + field :project_milestone, GraphQL::Types::Boolean, null: false, description: 'Indicates if milestone is at project level.', method: :project_milestone? - field :group_milestone, GraphQL::BOOLEAN_TYPE, null: false, + field :group_milestone, GraphQL::Types::Boolean, null: false, description: 'Indicates if milestone is at group level.', method: :group_milestone? - field :subgroup_milestone, GraphQL::BOOLEAN_TYPE, null: false, + field :subgroup_milestone, GraphQL::Types::Boolean, null: false, description: 'Indicates if milestone is at subgroup level.', method: :subgroup_milestone? diff --git a/app/graphql/types/namespace/package_settings_type.rb b/app/graphql/types/namespace/package_settings_type.rb index af091515979..d573cc9ded5 100644 --- a/app/graphql/types/namespace/package_settings_type.rb +++ b/app/graphql/types/namespace/package_settings_type.rb @@ -8,9 +8,9 @@ module Types authorize :read_package_settings - field :maven_duplicates_allowed, GraphQL::BOOLEAN_TYPE, null: false, description: 'Indicates whether duplicate Maven packages are allowed for this namespace.' + field :maven_duplicates_allowed, GraphQL::Types::Boolean, null: false, description: 'Indicates whether duplicate Maven packages are allowed for this namespace.' field :maven_duplicate_exception_regex, Types::UntrustedRegexp, null: true, description: 'When maven_duplicates_allowed is false, you can publish duplicate packages with names that match this regex. Otherwise, this setting has no effect.' - field :generic_duplicates_allowed, GraphQL::BOOLEAN_TYPE, null: false, description: 'Indicates whether duplicate generic packages are allowed for this namespace.' + field :generic_duplicates_allowed, GraphQL::Types::Boolean, null: false, description: 'Indicates whether duplicate generic packages are allowed for this namespace.' field :generic_duplicate_exception_regex, Types::UntrustedRegexp, null: true, description: 'When generic_duplicates_allowed is false, you can publish duplicate packages with names that match this regex. Otherwise, this setting has no effect.' end end diff --git a/app/graphql/types/namespace_type.rb b/app/graphql/types/namespace_type.rb index 96eff8a46b0..da5e4ae0642 100644 --- a/app/graphql/types/namespace_type.rb +++ b/app/graphql/types/namespace_type.rb @@ -6,27 +6,27 @@ module Types authorize :read_namespace - field :id, GraphQL::ID_TYPE, null: false, + field :id, GraphQL::Types::ID, null: false, description: 'ID of the namespace.' - field :name, GraphQL::STRING_TYPE, null: false, + field :name, GraphQL::Types::String, null: false, description: 'Name of the namespace.' - field :path, GraphQL::STRING_TYPE, null: false, + field :path, GraphQL::Types::String, null: false, description: 'Path of the namespace.' - field :full_name, GraphQL::STRING_TYPE, null: false, + field :full_name, GraphQL::Types::String, null: false, description: 'Full name of the namespace.' - field :full_path, GraphQL::ID_TYPE, null: false, + field :full_path, GraphQL::Types::ID, null: false, description: 'Full path of the namespace.' - field :description, GraphQL::STRING_TYPE, null: true, + field :description, GraphQL::Types::String, null: true, description: 'Description of the namespace.' markdown_field :description_html, null: true - field :visibility, GraphQL::STRING_TYPE, null: true, + field :visibility, GraphQL::Types::String, null: true, description: 'Visibility of the namespace.' - field :lfs_enabled, GraphQL::BOOLEAN_TYPE, null: true, method: :lfs_enabled?, + field :lfs_enabled, GraphQL::Types::Boolean, null: true, method: :lfs_enabled?, description: 'Indicates if Large File Storage (LFS) is enabled for namespace.' - field :request_access_enabled, GraphQL::BOOLEAN_TYPE, null: true, + field :request_access_enabled, GraphQL::Types::Boolean, null: true, description: 'Indicates if users can request access to namespace.' field :root_storage_statistics, Types::RootStorageStatisticsType, diff --git a/app/graphql/types/notes/diff_image_position_input_type.rb b/app/graphql/types/notes/diff_image_position_input_type.rb index dd5c8f20cc3..d56c67bbec8 100644 --- a/app/graphql/types/notes/diff_image_position_input_type.rb +++ b/app/graphql/types/notes/diff_image_position_input_type.rb @@ -5,13 +5,13 @@ module Types class DiffImagePositionInputType < DiffPositionBaseInputType graphql_name 'DiffImagePositionInput' - argument :x, GraphQL::INT_TYPE, required: true, + argument :x, GraphQL::Types::Int, required: true, description: copy_field_description(Types::Notes::DiffPositionType, :x) - argument :y, GraphQL::INT_TYPE, required: true, + argument :y, GraphQL::Types::Int, required: true, description: copy_field_description(Types::Notes::DiffPositionType, :y) - argument :width, GraphQL::INT_TYPE, required: true, + argument :width, GraphQL::Types::Int, required: true, description: copy_field_description(Types::Notes::DiffPositionType, :width) - argument :height, GraphQL::INT_TYPE, required: true, + argument :height, GraphQL::Types::Int, required: true, description: copy_field_description(Types::Notes::DiffPositionType, :height) end end diff --git a/app/graphql/types/notes/diff_position_base_input_type.rb b/app/graphql/types/notes/diff_position_base_input_type.rb index c8f9f9028cc..e773fbbc8a1 100644 --- a/app/graphql/types/notes/diff_position_base_input_type.rb +++ b/app/graphql/types/notes/diff_position_base_input_type.rb @@ -3,11 +3,11 @@ module Types module Notes class DiffPositionBaseInputType < BaseInputObject - argument :head_sha, GraphQL::STRING_TYPE, required: true, + argument :head_sha, GraphQL::Types::String, required: true, description: copy_field_description(Types::DiffRefsType, :head_sha) - argument :base_sha, GraphQL::STRING_TYPE, required: false, + argument :base_sha, GraphQL::Types::String, required: false, description: copy_field_description(Types::DiffRefsType, :base_sha) - argument :start_sha, GraphQL::STRING_TYPE, required: true, + argument :start_sha, GraphQL::Types::String, required: true, description: copy_field_description(Types::DiffRefsType, :start_sha) argument :paths, diff --git a/app/graphql/types/notes/diff_position_input_type.rb b/app/graphql/types/notes/diff_position_input_type.rb index 7ec5fd9e086..18ce6672d14 100644 --- a/app/graphql/types/notes/diff_position_input_type.rb +++ b/app/graphql/types/notes/diff_position_input_type.rb @@ -5,9 +5,9 @@ module Types class DiffPositionInputType < DiffPositionBaseInputType graphql_name 'DiffPositionInput' - argument :old_line, GraphQL::INT_TYPE, required: false, + argument :old_line, GraphQL::Types::Int, required: false, description: copy_field_description(Types::Notes::DiffPositionType, :old_line) - argument :new_line, GraphQL::INT_TYPE, required: false, + argument :new_line, GraphQL::Types::Int, required: false, description: copy_field_description(Types::Notes::DiffPositionType, :new_line) end end diff --git a/app/graphql/types/notes/diff_position_type.rb b/app/graphql/types/notes/diff_position_type.rb index 67747a13dcf..9c756d56b97 100644 --- a/app/graphql/types/notes/diff_position_type.rb +++ b/app/graphql/types/notes/diff_position_type.rb @@ -10,29 +10,29 @@ module Types field :diff_refs, Types::DiffRefsType, null: false, description: 'Information about the branch, HEAD, and base at the time of commenting.' - field :file_path, GraphQL::STRING_TYPE, null: false, + field :file_path, GraphQL::Types::String, null: false, description: 'Path of the file that was changed.' - field :old_path, GraphQL::STRING_TYPE, null: true, + field :old_path, GraphQL::Types::String, null: true, description: 'Path of the file on the start SHA.' - field :new_path, GraphQL::STRING_TYPE, null: true, + field :new_path, GraphQL::Types::String, null: true, description: 'Path of the file on the HEAD SHA.' field :position_type, Types::Notes::PositionTypeEnum, null: false, description: 'Type of file the position refers to.' # Fields for text positions - field :old_line, GraphQL::INT_TYPE, null: true, + field :old_line, GraphQL::Types::Int, null: true, description: 'Line on start SHA that was changed.' - field :new_line, GraphQL::INT_TYPE, null: true, + field :new_line, GraphQL::Types::Int, null: true, description: 'Line on HEAD SHA that was changed.' # Fields for image positions - field :x, GraphQL::INT_TYPE, null: true, + field :x, GraphQL::Types::Int, null: true, description: 'X position of the note.' - field :y, GraphQL::INT_TYPE, null: true, + field :y, GraphQL::Types::Int, null: true, description: 'Y position of the note.' - field :width, GraphQL::INT_TYPE, null: true, + field :width, GraphQL::Types::Int, null: true, description: 'Total width of the image.' - field :height, GraphQL::INT_TYPE, null: true, + field :height, GraphQL::Types::Int, null: true, description: 'Total height of the image.' def old_line diff --git a/app/graphql/types/notes/note_type.rb b/app/graphql/types/notes/note_type.rb index 751cf7c10f1..fa33428114c 100644 --- a/app/graphql/types/notes/note_type.rb +++ b/app/graphql/types/notes/note_type.rb @@ -22,13 +22,13 @@ module Types null: false, description: 'User who wrote this note.' - field :system, GraphQL::BOOLEAN_TYPE, + field :system, GraphQL::Types::Boolean, null: false, description: 'Indicates whether this note was created by the system or by a user.' - field :system_note_icon_name, GraphQL::STRING_TYPE, null: true, + field :system_note_icon_name, GraphQL::Types::String, null: true, description: 'Name of the icon corresponding to a system note.' - field :body, GraphQL::STRING_TYPE, + field :body, GraphQL::Types::String, null: false, method: :note, description: 'Content of the note.' @@ -43,10 +43,10 @@ module Types description: 'The discussion this note is a part of.' field :position, Types::Notes::DiffPositionType, null: true, description: 'The position of this note on a diff.' - field :confidential, GraphQL::BOOLEAN_TYPE, null: true, + field :confidential, GraphQL::Types::Boolean, null: true, description: 'Indicates if this note is confidential.', method: :confidential? - field :url, GraphQL::STRING_TYPE, + field :url, GraphQL::Types::String, null: true, description: 'URL to view this Note in the Web UI.' diff --git a/app/graphql/types/notes/update_diff_image_position_input_type.rb b/app/graphql/types/notes/update_diff_image_position_input_type.rb index ab27f6b9ad3..0c6e4a16434 100644 --- a/app/graphql/types/notes/update_diff_image_position_input_type.rb +++ b/app/graphql/types/notes/update_diff_image_position_input_type.rb @@ -6,19 +6,19 @@ module Types class UpdateDiffImagePositionInputType < BaseInputObject graphql_name 'UpdateDiffImagePositionInput' - argument :x, GraphQL::INT_TYPE, + argument :x, GraphQL::Types::Int, required: false, description: copy_field_description(Types::Notes::DiffPositionType, :x) - argument :y, GraphQL::INT_TYPE, + argument :y, GraphQL::Types::Int, required: false, description: copy_field_description(Types::Notes::DiffPositionType, :y) - argument :width, GraphQL::INT_TYPE, + argument :width, GraphQL::Types::Int, required: false, description: copy_field_description(Types::Notes::DiffPositionType, :width) - argument :height, GraphQL::INT_TYPE, + argument :height, GraphQL::Types::Int, required: false, description: copy_field_description(Types::Notes::DiffPositionType, :height) diff --git a/app/graphql/types/packages/composer/json_type.rb b/app/graphql/types/packages/composer/json_type.rb index b7aa32f0170..d2bd62ca74d 100644 --- a/app/graphql/types/packages/composer/json_type.rb +++ b/app/graphql/types/packages/composer/json_type.rb @@ -8,10 +8,10 @@ module Types graphql_name 'PackageComposerJsonType' description 'Represents a composer JSON file' - field :name, GraphQL::STRING_TYPE, null: true, description: 'The name set in the Composer JSON file.' - field :type, GraphQL::STRING_TYPE, null: true, description: 'The type set in the Composer JSON file.' - field :license, GraphQL::STRING_TYPE, null: true, description: 'The license set in the Composer JSON file.' - field :version, GraphQL::STRING_TYPE, null: true, description: 'The version set in the Composer JSON file.' + field :name, GraphQL::Types::String, null: true, description: 'The name set in the Composer JSON file.' + field :type, GraphQL::Types::String, null: true, description: 'The type set in the Composer JSON file.' + field :license, GraphQL::Types::String, null: true, description: 'The license set in the Composer JSON file.' + field :version, GraphQL::Types::String, null: true, description: 'The version set in the Composer JSON file.' end end end diff --git a/app/graphql/types/packages/composer/metadatum_type.rb b/app/graphql/types/packages/composer/metadatum_type.rb index 9d4ce3cebd4..092e729ec56 100644 --- a/app/graphql/types/packages/composer/metadatum_type.rb +++ b/app/graphql/types/packages/composer/metadatum_type.rb @@ -9,7 +9,7 @@ module Types authorize :read_package - field :target_sha, GraphQL::STRING_TYPE, null: false, description: 'Target SHA of the package.' + field :target_sha, GraphQL::Types::String, null: false, description: 'Target SHA of the package.' field :composer_json, Types::Packages::Composer::JsonType, null: false, description: 'Data of the Composer JSON file.' end end diff --git a/app/graphql/types/packages/conan/file_metadatum_type.rb b/app/graphql/types/packages/conan/file_metadatum_type.rb index 97d5abe6ba4..9a26fd5de51 100644 --- a/app/graphql/types/packages/conan/file_metadatum_type.rb +++ b/app/graphql/types/packages/conan/file_metadatum_type.rb @@ -12,9 +12,9 @@ module Types authorize :read_package field :id, ::Types::GlobalIDType[::Packages::Conan::FileMetadatum], null: false, description: 'ID of the metadatum.' - field :recipe_revision, GraphQL::STRING_TYPE, null: false, description: 'Revision of the Conan recipe.' - field :package_revision, GraphQL::STRING_TYPE, null: true, description: 'Revision of the package.' - field :conan_package_reference, GraphQL::STRING_TYPE, null: true, description: 'Reference of the Conan package.' + field :recipe_revision, GraphQL::Types::String, null: false, description: 'Revision of the Conan recipe.' + field :package_revision, GraphQL::Types::String, null: true, description: 'Revision of the package.' + field :conan_package_reference, GraphQL::Types::String, null: true, description: 'Reference of the Conan package.' field :conan_file_type, ::Types::Packages::Conan::MetadatumFileTypeEnum, null: false, description: 'Type of the Conan file.' end end diff --git a/app/graphql/types/packages/conan/metadatum_type.rb b/app/graphql/types/packages/conan/metadatum_type.rb index 00b84235d27..cdfd0aa4483 100644 --- a/app/graphql/types/packages/conan/metadatum_type.rb +++ b/app/graphql/types/packages/conan/metadatum_type.rb @@ -12,10 +12,10 @@ module Types field :id, ::Types::GlobalIDType[::Packages::Conan::Metadatum], null: false, description: 'ID of the metadatum.' field :created_at, Types::TimeType, null: false, description: 'Date of creation.' field :updated_at, Types::TimeType, null: false, description: 'Date of most recent update.' - field :package_username, GraphQL::STRING_TYPE, null: false, description: 'Username of the Conan package.' - field :package_channel, GraphQL::STRING_TYPE, null: false, description: 'Channel of the Conan package.' - field :recipe, GraphQL::STRING_TYPE, null: false, description: 'Recipe of the Conan package.' - field :recipe_path, GraphQL::STRING_TYPE, null: false, description: 'Recipe path of the Conan package.' + field :package_username, GraphQL::Types::String, null: false, description: 'Username of the Conan package.' + field :package_channel, GraphQL::Types::String, null: false, description: 'Channel of the Conan package.' + field :recipe, GraphQL::Types::String, null: false, description: 'Recipe of the Conan package.' + field :recipe_path, GraphQL::Types::String, null: false, description: 'Recipe path of the Conan package.' end end end diff --git a/app/graphql/types/packages/maven/metadatum_type.rb b/app/graphql/types/packages/maven/metadatum_type.rb index bdb250ef96b..eb3829648d1 100644 --- a/app/graphql/types/packages/maven/metadatum_type.rb +++ b/app/graphql/types/packages/maven/metadatum_type.rb @@ -12,10 +12,10 @@ module Types field :id, ::Types::GlobalIDType[::Packages::Maven::Metadatum], null: false, description: 'ID of the metadatum.' field :created_at, Types::TimeType, null: false, description: 'Date of creation.' field :updated_at, Types::TimeType, null: false, description: 'Date of most recent update.' - field :path, GraphQL::STRING_TYPE, null: false, description: 'Path of the Maven package.' - field :app_group, GraphQL::STRING_TYPE, null: false, description: 'App group of the Maven package.' - field :app_version, GraphQL::STRING_TYPE, null: true, description: 'App version of the Maven package.' - field :app_name, GraphQL::STRING_TYPE, null: false, description: 'App name of the Maven package.' + field :path, GraphQL::Types::String, null: false, description: 'Path of the Maven package.' + field :app_group, GraphQL::Types::String, null: false, description: 'App group of the Maven package.' + field :app_version, GraphQL::Types::String, null: true, description: 'App version of the Maven package.' + field :app_name, GraphQL::Types::String, null: false, description: 'App name of the Maven package.' end end end diff --git a/app/graphql/types/packages/nuget/metadatum_type.rb b/app/graphql/types/packages/nuget/metadatum_type.rb index 63fae2fb197..ed9d97724af 100644 --- a/app/graphql/types/packages/nuget/metadatum_type.rb +++ b/app/graphql/types/packages/nuget/metadatum_type.rb @@ -10,9 +10,9 @@ module Types authorize :read_package field :id, ::Types::GlobalIDType[::Packages::Nuget::Metadatum], null: false, description: 'ID of the metadatum.' - field :license_url, GraphQL::STRING_TYPE, null: false, description: 'License URL of the Nuget package.' - field :project_url, GraphQL::STRING_TYPE, null: false, description: 'Project URL of the Nuget package.' - field :icon_url, GraphQL::STRING_TYPE, null: false, description: 'Icon URL of the Nuget package.' + field :license_url, GraphQL::Types::String, null: false, description: 'License URL of the Nuget package.' + field :project_url, GraphQL::Types::String, null: false, description: 'Project URL of the Nuget package.' + field :icon_url, GraphQL::Types::String, null: false, description: 'Icon URL of the Nuget package.' end end end diff --git a/app/graphql/types/packages/package_file_type.rb b/app/graphql/types/packages/package_file_type.rb index e9e38559626..f77c40de8d8 100644 --- a/app/graphql/types/packages/package_file_type.rb +++ b/app/graphql/types/packages/package_file_type.rb @@ -10,12 +10,12 @@ module Types field :id, ::Types::GlobalIDType[::Packages::PackageFile], null: false, description: 'ID of the file.' field :created_at, Types::TimeType, null: false, description: 'The created date.' field :updated_at, Types::TimeType, null: false, description: 'The updated date.' - field :size, GraphQL::STRING_TYPE, null: false, description: 'Size of the package file.' - field :file_name, GraphQL::STRING_TYPE, null: false, description: 'Name of the package file.' - field :download_path, GraphQL::STRING_TYPE, null: false, description: 'Download path of the package file.' - field :file_md5, GraphQL::STRING_TYPE, null: true, description: 'Md5 of the package file.' - field :file_sha1, GraphQL::STRING_TYPE, null: true, description: 'Sha1 of the package file.' - field :file_sha256, GraphQL::STRING_TYPE, null: true, description: 'Sha256 of the package file.' + field :size, GraphQL::Types::String, null: false, description: 'Size of the package file.' + field :file_name, GraphQL::Types::String, null: false, description: 'Name of the package file.' + field :download_path, GraphQL::Types::String, null: false, description: 'Download path of the package file.' + field :file_md5, GraphQL::Types::String, null: true, description: 'Md5 of the package file.' + field :file_sha1, GraphQL::Types::String, null: true, description: 'Sha1 of the package file.' + field :file_sha256, GraphQL::Types::String, null: true, description: 'Sha256 of the package file.' field :file_metadata, Types::Packages::FileMetadataType, null: true, description: 'File metadata.' diff --git a/app/graphql/types/packages/package_tag_type.rb b/app/graphql/types/packages/package_tag_type.rb index a05ce03da67..450f3fc8e9c 100644 --- a/app/graphql/types/packages/package_tag_type.rb +++ b/app/graphql/types/packages/package_tag_type.rb @@ -7,8 +7,8 @@ module Types description 'Represents a package tag' authorize :read_package - field :id, GraphQL::ID_TYPE, null: false, description: 'The ID of the tag.' - field :name, GraphQL::STRING_TYPE, null: false, description: 'The name of the tag.' + field :id, GraphQL::Types::ID, null: false, description: 'The ID of the tag.' + field :name, GraphQL::Types::String, null: false, description: 'The name of the tag.' field :created_at, Types::TimeType, null: false, description: 'The created date.' field :updated_at, Types::TimeType, null: false, description: 'The updated date.' end diff --git a/app/graphql/types/packages/package_type.rb b/app/graphql/types/packages/package_type.rb index ee6785e3555..b8654ebd2c6 100644 --- a/app/graphql/types/packages/package_type.rb +++ b/app/graphql/types/packages/package_type.rb @@ -11,10 +11,10 @@ module Types field :id, ::Types::GlobalIDType[::Packages::Package], null: false, description: 'ID of the package.' - field :name, GraphQL::STRING_TYPE, null: false, description: 'Name of the package.' + field :name, GraphQL::Types::String, null: false, description: 'Name of the package.' field :created_at, Types::TimeType, null: false, description: 'Date of creation.' field :updated_at, Types::TimeType, null: false, description: 'Date of most recent update.' - field :version, GraphQL::STRING_TYPE, null: true, description: 'Version string.' + field :version, GraphQL::Types::String, null: true, description: 'Version string.' field :package_type, Types::Packages::PackageTypeEnum, null: false, description: 'Package type.' field :tags, Types::Packages::PackageTagType.connection_type, null: true, description: 'Package tags.' field :project, Types::ProjectType, null: false, description: 'Project where the package is stored.' diff --git a/app/graphql/types/packages/pypi/metadatum_type.rb b/app/graphql/types/packages/pypi/metadatum_type.rb index 031d3572197..63452d8ab6e 100644 --- a/app/graphql/types/packages/pypi/metadatum_type.rb +++ b/app/graphql/types/packages/pypi/metadatum_type.rb @@ -10,7 +10,7 @@ module Types authorize :read_package field :id, ::Types::GlobalIDType[::Packages::Pypi::Metadatum], null: false, description: 'ID of the metadatum.' - field :required_python, GraphQL::STRING_TYPE, null: true, description: 'Required Python version of the Pypi package.' + field :required_python, GraphQL::Types::String, null: true, description: 'Required Python version of the Pypi package.' end end end diff --git a/app/graphql/types/permission_types/base_permission_type.rb b/app/graphql/types/permission_types/base_permission_type.rb index deb8560bd79..a2cefb872c9 100644 --- a/app/graphql/types/permission_types/base_permission_type.rb +++ b/app/graphql/types/permission_types/base_permission_type.rb @@ -24,7 +24,7 @@ module Types def self.permission_field(name, **kword_args) kword_args = kword_args.reverse_merge( name: name, - type: GraphQL::BOOLEAN_TYPE, + type: GraphQL::Types::Boolean, description: "Indicates the user can perform `#{name}` on this resource", null: false) diff --git a/app/graphql/types/project_type.rb b/app/graphql/types/project_type.rb index 968635f9e6e..62861fceb1a 100644 --- a/app/graphql/types/project_type.rb +++ b/app/graphql/types/project_type.rb @@ -8,44 +8,44 @@ module Types expose_permissions Types::PermissionTypes::Project - field :id, GraphQL::ID_TYPE, null: false, + field :id, GraphQL::Types::ID, null: false, description: 'ID of the project.' - field :full_path, GraphQL::ID_TYPE, null: false, + field :full_path, GraphQL::Types::ID, null: false, description: 'Full path of the project.' - field :path, GraphQL::STRING_TYPE, null: false, + field :path, GraphQL::Types::String, null: false, description: 'Path of the project.' field :sast_ci_configuration, Types::CiConfiguration::Sast::Type, null: true, calls_gitaly: true, description: 'SAST CI configuration for the project.' - field :name_with_namespace, GraphQL::STRING_TYPE, null: false, + field :name_with_namespace, GraphQL::Types::String, null: false, description: 'Full name of the project with its namespace.' - field :name, GraphQL::STRING_TYPE, null: false, + field :name, GraphQL::Types::String, null: false, description: 'Name of the project (without namespace).' - field :description, GraphQL::STRING_TYPE, null: true, + field :description, GraphQL::Types::String, null: true, description: 'Short description of the project.' markdown_field :description_html, null: true - field :tag_list, GraphQL::STRING_TYPE, null: true, + field :tag_list, GraphQL::Types::String, null: true, deprecated: { reason: 'Use `topics`', milestone: '13.12' }, description: 'List of project topics (not Git tags).' - field :topics, [GraphQL::STRING_TYPE], null: true, + field :topics, [GraphQL::Types::String], null: true, description: 'List of project topics.' - field :ssh_url_to_repo, GraphQL::STRING_TYPE, null: true, + field :ssh_url_to_repo, GraphQL::Types::String, null: true, description: 'URL to connect to the project via SSH.' - field :http_url_to_repo, GraphQL::STRING_TYPE, null: true, + field :http_url_to_repo, GraphQL::Types::String, null: true, description: 'URL to connect to the project via HTTPS.' - field :web_url, GraphQL::STRING_TYPE, null: true, + field :web_url, GraphQL::Types::String, null: true, description: 'Web URL of the project.' - field :star_count, GraphQL::INT_TYPE, null: false, + field :star_count, GraphQL::Types::Int, null: false, description: 'Number of times the project has been starred.' - field :forks_count, GraphQL::INT_TYPE, null: false, calls_gitaly: true, # 4 times + field :forks_count, GraphQL::Types::Int, null: false, calls_gitaly: true, # 4 times description: 'Number of times the project has been forked.' field :created_at, Types::TimeType, null: true, @@ -53,26 +53,26 @@ module Types field :last_activity_at, Types::TimeType, null: true, description: 'Timestamp of the project last activity.' - field :archived, GraphQL::BOOLEAN_TYPE, null: true, + field :archived, GraphQL::Types::Boolean, null: true, description: 'Indicates the archived status of the project.' - field :visibility, GraphQL::STRING_TYPE, null: true, + field :visibility, GraphQL::Types::String, null: true, description: 'Visibility of the project.' - field :shared_runners_enabled, GraphQL::BOOLEAN_TYPE, null: true, + field :shared_runners_enabled, GraphQL::Types::Boolean, null: true, description: 'Indicates if shared runners are enabled for the project.' - field :lfs_enabled, GraphQL::BOOLEAN_TYPE, null: true, + field :lfs_enabled, GraphQL::Types::Boolean, null: true, description: 'Indicates if the project has Large File Storage (LFS) enabled.' - field :merge_requests_ff_only_enabled, GraphQL::BOOLEAN_TYPE, null: true, + field :merge_requests_ff_only_enabled, GraphQL::Types::Boolean, null: true, description: 'Indicates if no merge commits should be created and all merges should instead be fast-forwarded, which means that merging is only allowed if the branch could be fast-forwarded.' - field :service_desk_enabled, GraphQL::BOOLEAN_TYPE, null: true, + field :service_desk_enabled, GraphQL::Types::Boolean, null: true, description: 'Indicates if the project has service desk enabled.' - field :service_desk_address, GraphQL::STRING_TYPE, null: true, + field :service_desk_address, GraphQL::Types::String, null: true, description: 'E-mail address of the service desk.' - field :avatar_url, GraphQL::STRING_TYPE, null: true, calls_gitaly: true, + field :avatar_url, GraphQL::Types::String, null: true, calls_gitaly: true, description: 'URL to avatar image file of the project.' { @@ -90,36 +90,36 @@ module Types end end - field :jobs_enabled, GraphQL::BOOLEAN_TYPE, null: true, + field :jobs_enabled, GraphQL::Types::Boolean, null: true, description: 'Indicates if CI/CD pipeline jobs are enabled for the current user.' - field :public_jobs, GraphQL::BOOLEAN_TYPE, method: :public_builds, null: true, + field :public_jobs, GraphQL::Types::Boolean, method: :public_builds, null: true, description: 'Indicates if there is public access to pipelines and job details of the project, including output logs and artifacts.' - field :open_issues_count, GraphQL::INT_TYPE, null: true, + field :open_issues_count, GraphQL::Types::Int, null: true, description: 'Number of open issues for the project.' - field :import_status, GraphQL::STRING_TYPE, null: true, + field :import_status, GraphQL::Types::String, null: true, description: 'Status of import background job of the project.' - field :jira_import_status, GraphQL::STRING_TYPE, null: true, + field :jira_import_status, GraphQL::Types::String, null: true, description: 'Status of Jira import background job of the project.' - field :only_allow_merge_if_pipeline_succeeds, GraphQL::BOOLEAN_TYPE, null: true, + field :only_allow_merge_if_pipeline_succeeds, GraphQL::Types::Boolean, null: true, description: 'Indicates if merge requests of the project can only be merged with successful jobs.' - field :allow_merge_on_skipped_pipeline, GraphQL::BOOLEAN_TYPE, null: true, + field :allow_merge_on_skipped_pipeline, GraphQL::Types::Boolean, null: true, description: 'If `only_allow_merge_if_pipeline_succeeds` is true, indicates if merge requests of the project can also be merged with skipped jobs.' - field :request_access_enabled, GraphQL::BOOLEAN_TYPE, null: true, + field :request_access_enabled, GraphQL::Types::Boolean, null: true, description: 'Indicates if users can request member access to the project.' - field :only_allow_merge_if_all_discussions_are_resolved, GraphQL::BOOLEAN_TYPE, null: true, + field :only_allow_merge_if_all_discussions_are_resolved, GraphQL::Types::Boolean, null: true, description: 'Indicates if merge requests of the project can only be merged when all the discussions are resolved.' - field :printing_merge_request_link_enabled, GraphQL::BOOLEAN_TYPE, null: true, + field :printing_merge_request_link_enabled, GraphQL::Types::Boolean, null: true, description: 'Indicates if a link to create or view a merge request should display after a push to Git repositories of the project from the command line.' - field :remove_source_branch_after_merge, GraphQL::BOOLEAN_TYPE, null: true, + field :remove_source_branch_after_merge, GraphQL::Types::Boolean, null: true, description: 'Indicates if `Delete source branch` option should be enabled by default for all new merge requests of the project.' - field :autoclose_referenced_issues, GraphQL::BOOLEAN_TYPE, null: true, + field :autoclose_referenced_issues, GraphQL::Types::Boolean, null: true, description: 'Indicates if issues referenced by merge requests and commits within the default branch are closed automatically.' - field :suggestion_commit_message, GraphQL::STRING_TYPE, null: true, + field :suggestion_commit_message, GraphQL::Types::String, null: true, description: 'The commit message used to apply merge request suggestions.' - field :squash_read_only, GraphQL::BOOLEAN_TYPE, null: false, method: :squash_readonly?, + field :squash_read_only, GraphQL::Types::Boolean, null: false, method: :squash_readonly?, description: 'Indicates if `squashReadOnly` is enabled.' field :namespace, Types::NamespaceType, null: true, @@ -318,14 +318,14 @@ module Types description: 'Container repositories of the project.', resolver: Resolvers::ContainerRepositoriesResolver - field :container_repositories_count, GraphQL::INT_TYPE, null: false, + field :container_repositories_count, GraphQL::Types::Int, null: false, description: 'Number of container repositories in the project.' field :label, Types::LabelType, null: true, description: 'A label available on this project.' do - argument :title, GraphQL::STRING_TYPE, + argument :title, GraphQL::Types::String, required: true, description: 'Title of the label.' end diff --git a/app/graphql/types/projects/service_type.rb b/app/graphql/types/projects/service_type.rb index 6f0dcd44cad..4a9e5dcbfe9 100644 --- a/app/graphql/types/projects/service_type.rb +++ b/app/graphql/types/projects/service_type.rb @@ -8,9 +8,9 @@ module Types # TODO: Add all the fields that we want to expose for the project services integrations # https://gitlab.com/gitlab-org/gitlab/-/issues/213088 - field :type, GraphQL::STRING_TYPE, null: true, + field :type, GraphQL::Types::String, null: true, description: 'Class name of the service.' - field :active, GraphQL::BOOLEAN_TYPE, null: true, + field :active, GraphQL::Types::Boolean, null: true, description: 'Indicates if the service is active.' definition_methods do diff --git a/app/graphql/types/projects/services/jira_project_type.rb b/app/graphql/types/projects/services/jira_project_type.rb index 90abce2b4c3..957ac91db6b 100644 --- a/app/graphql/types/projects/services/jira_project_type.rb +++ b/app/graphql/types/projects/services/jira_project_type.rb @@ -7,12 +7,12 @@ module Types class JiraProjectType < BaseObject graphql_name 'JiraProject' - field :key, GraphQL::STRING_TYPE, null: false, + field :key, GraphQL::Types::String, null: false, description: 'Key of the Jira project.' - field :project_id, GraphQL::INT_TYPE, null: false, + field :project_id, GraphQL::Types::Int, null: false, description: 'ID of the Jira project.', method: :id - field :name, GraphQL::STRING_TYPE, null: true, + field :name, GraphQL::Types::String, null: true, description: 'Name of the Jira project.' end # rubocop:enable Graphql/AuthorizeTypes diff --git a/app/graphql/types/prometheus_alert_type.rb b/app/graphql/types/prometheus_alert_type.rb index 8e800536675..8327848032a 100644 --- a/app/graphql/types/prometheus_alert_type.rb +++ b/app/graphql/types/prometheus_alert_type.rb @@ -9,11 +9,11 @@ module Types present_using PrometheusAlertPresenter - field :id, GraphQL::ID_TYPE, null: false, + field :id, GraphQL::Types::ID, null: false, description: 'ID of the alert condition.' field :humanized_text, - GraphQL::STRING_TYPE, + GraphQL::Types::String, null: false, description: 'The human-readable text of the alert condition.' end diff --git a/app/services/ci/destroy_pipeline_service.rb b/app/services/ci/destroy_pipeline_service.rb index 494fcb23a06..978821c1ded 100644 --- a/app/services/ci/destroy_pipeline_service.rb +++ b/app/services/ci/destroy_pipeline_service.rb @@ -7,7 +7,7 @@ module Ci Ci::ExpirePipelineCacheService.new.execute(pipeline, delete: true) - pipeline.cancel_running if pipeline.cancelable? && ::Feature.enabled?(:cancel_pipelines_prior_to_destroy, default_enabled: :yaml) + pipeline.cancel_running if pipeline.cancelable? && ::Feature.enabled?(:cancel_pipelines_prior_to_destroy, pipeline.project, default_enabled: :yaml) pipeline.reset.destroy! diff --git a/app/views/admin/application_settings/_grafana.html.haml b/app/views/admin/application_settings/_grafana.html.haml index fd9e7ee50c4..70c1e3ce3c1 100644 --- a/app/views/admin/application_settings/_grafana.html.haml +++ b/app/views/admin/application_settings/_grafana.html.haml @@ -2,16 +2,16 @@ = form_errors(@application_setting) %fieldset - %p - = _("Add a Grafana button in the admin sidebar, monitoring section, to access a variety of statistics on the health and performance of GitLab.") - = link_to sprite_icon('question-o'), help_page_path('administration/monitoring/performance/grafana_configuration.md') .form-group .form-check = f.check_box :grafana_enabled, class: 'form-check-input' = f.label :grafana_enabled, class: 'form-check-label' do - = _('Enable access to Grafana') + = _("Add a link to Grafana") + .form-text.text-muted + = _("A Metrics Dashboard menu item appears in the Monitoring section of the Admin Area.") .form-group = f.label :grafana_url, _('Grafana URL'), class: 'label-bold' = f.text_field :grafana_url, class: 'form-control gl-form-input', placeholder: '/-/grafana' + %span.form-text.text-muted#support_help_block= _('URL of the Grafana instance to link to from the Metrics Dashboard menu item.') = f.submit _('Save changes'), class: "gl-button btn btn-confirm" diff --git a/app/views/admin/application_settings/metrics_and_profiling.html.haml b/app/views/admin/application_settings/metrics_and_profiling.html.haml index 14483e4e55e..fcd3720e3d5 100644 --- a/app/views/admin/application_settings/metrics_and_profiling.html.haml +++ b/app/views/admin/application_settings/metrics_and_profiling.html.haml @@ -22,7 +22,9 @@ %button.btn.gl-button.btn-default.js-settings-toggle{ type: 'button' } = expanded_by_default? ? _('Collapse') : _('Expand') %p - = _('Enable and configure Grafana.') + = _('Link to your Grafana instance.') + = link_to s_('Learn more.'), help_page_path('administration/monitoring/performance/grafana_configuration.md'), target: '_blank', rel: 'noopener noreferrer' + .settings-content = render 'grafana' diff --git a/doc/administration/monitoring/performance/grafana_configuration.md b/doc/administration/monitoring/performance/grafana_configuration.md index 6de60162d46..02073bd2e18 100644 --- a/doc/administration/monitoring/performance/grafana_configuration.md +++ b/doc/administration/monitoring/performance/grafana_configuration.md @@ -65,12 +65,12 @@ GitLab sidebar: 1. On the top bar, select **Menu >** **{admin}** **Admin**. 1. On the left sidebar, select **Settings > Metrics and profiling** and expand **Metrics - Grafana**. -1. Check the **Enable access to Grafana** checkbox. +1. Select the **Add a link to Grafana** checkbox. 1. Configure the **Grafana URL**: - *If Grafana is enabled through Omnibus GitLab and on the same server,* leave **Grafana URL** unchanged. It should be `/-/grafana`. - *Otherwise,* enter the full URL of the Grafana instance. -1. Click **Save changes**. +1. Select **Save changes**. GitLab displays your link in the **Menu > Admin > Monitoring > Metrics Dashboard**. diff --git a/doc/administration/reference_architectures/10k_users.md b/doc/administration/reference_architectures/10k_users.md index 1fc3483fbd4..65be734f51b 100644 --- a/doc/administration/reference_architectures/10k_users.md +++ b/doc/administration/reference_architectures/10k_users.md @@ -15,32 +15,32 @@ full list of reference architectures, see > - **High Availability:** Yes ([Praefect](#configure-praefect-postgresql) needs a third-party PostgreSQL solution for HA) > - **Test requests per second (RPS) rates:** API: 200 RPS, Web: 20 RPS, Git (Pull): 20 RPS, Git (Push): 4 RPS -| Service | Nodes | Configuration | GCP | AWS | Azure | -|--------------------------------------------|-------------|-------------------------|------------------|--------------|-----------| -| External load balancing node(3) | 1 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` | -| Consul(1) | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` | -| PostgreSQL(1) | 3 | 8 vCPU, 30 GB memory | `n1-standard-8` | `m5.2xlarge` | `D8s v3` | -| PgBouncer(1) | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` | -| Internal load balancing node(3) | 1 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` | -| Redis - Cache(2) | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` | `D4s v3` | -| Redis - Queues / Shared State(2) | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` | `D4s v3` | -| Redis Sentinel - Cache(2) | 3 | 1 vCPU, 3.75 GB memory | `n1-standard-1` | `c5.large` | `A1 v2` | -| Redis Sentinel - Queues / Shared State(2) | 3 | 1 vCPU, 3.75 GB memory | `n1-standard-1` | `c5.large` | `A1 v2` | -| Gitaly | 3 | 16 vCPU, 60 GB memory | `n1-standard-16` | `m5.4xlarge` | `D16s v3` | -| Praefect | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` | -| Praefect PostgreSQL(1) | 1+ | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` | -| Sidekiq | 4 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` | `D4s v3` | -| GitLab Rails | 3 | 32 vCPU, 28.8 GB memory | `n1-highcpu-32` | `c5.9xlarge` | `F32s v2` | -| Monitoring node | 1 | 4 vCPU, 3.6 GB memory | `n1-highcpu-4` | `c5.xlarge` | `F4s v2` | -| Object storage(4) | n/a | n/a | n/a | n/a | n/a | -| NFS server (optional, not recommended) | 1 | 4 vCPU, 3.6 GB memory | `n1-highcpu-4` | `c5.xlarge` | `F4s v2` | +| Service | Nodes | Configuration | GCP | AWS | Azure | +|-----------------------------------------------------|-------------|-------------------------|------------------|--------------|-----------| +| External load balancing node<sup>3</sup> | 1 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` | +| Consul<sup>1</sup> | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` | +| PostgreSQL<sup>1</sup> | 3 | 8 vCPU, 30 GB memory | `n1-standard-8` | `m5.2xlarge` | `D8s v3` | +| PgBouncer<sup>1</sup> | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` | +| Internal load balancing node<sup>3</sup> | 1 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` | +| Redis - Cache<sup>2</sup> | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` | `D4s v3` | +| Redis - Queues / Shared State<sup>2</sup> | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` | `D4s v3` | +| Redis Sentinel - Cache<sup>2</sup> | 3 | 1 vCPU, 3.75 GB memory | `n1-standard-1` | `c5.large` | `A1 v2` | +| Redis Sentinel - Queues / Shared State<sup>2</sup> | 3 | 1 vCPU, 3.75 GB memory | `n1-standard-1` | `c5.large` | `A1 v2` | +| Gitaly | 3 | 16 vCPU, 60 GB memory | `n1-standard-16` | `m5.4xlarge` | `D16s v3` | +| Praefect | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` | +| Praefect PostgreSQL<sup>1</sup> | 1+ | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` | +| Sidekiq | 4 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` | `D4s v3` | +| GitLab Rails | 3 | 32 vCPU, 28.8 GB memory | `n1-highcpu-32` | `c5.9xlarge` | `F32s v2` | +| Monitoring node | 1 | 4 vCPU, 3.6 GB memory | `n1-highcpu-4` | `c5.xlarge` | `F4s v2` | +| Object storage<sup>4</sup> | n/a | n/a | n/a | n/a | n/a | +| NFS server (optional, not recommended) | 1 | 4 vCPU, 3.6 GB memory | `n1-highcpu-4` | `c5.xlarge` | `F4s v2` | <!-- Disable ordered list rule https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md029---ordered-list-item-prefix --> <!-- 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. 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. -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. <!-- markdownlint-enable MD029 --> NOTE: @@ -141,7 +141,7 @@ is recommended instead of using NFS. Using an object storage service also doesn't require you to provision and maintain a node. It's also worth noting that at this time [Praefect requires its own database server](../gitaly/praefect.md#postgresql) and -that to achieve full High Availability a third party PostgreSQL database solution will be required. +that to achieve full High Availability a third-party PostgreSQL database solution will be required. We hope to offer a built in solutions for these restrictions in the future but in the meantime a non HA PostgreSQL server can be set up via Omnibus GitLab, which the above specs reflect. Refer to the following issues for more information: [`omnibus-gitlab#5919`](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/5919) & [`gitaly#3398`](https://gitlab.com/gitlab-org/gitaly/-/issues/3398) @@ -2368,7 +2368,7 @@ in Kubernetes via our official [Helm Charts](https://docs.gitlab.com/charts/). In this setup, we support running the equivalent of GitLab Rails and Sidekiq nodes in a Kubernetes cluster, named Webservice and Sidekiq respectively. In addition, the following other supporting services are supported: NGINX, Task Runner, Migrations, -Prometheus and Grafana. +Prometheus, and Grafana. Hybrid installations leverage the benefits of both cloud native and traditional compute deployments. With this, _stateless_ components can benefit from cloud native @@ -2379,23 +2379,23 @@ NOTE: This is an **advanced** setup. Running services in Kubernetes is well known to be complex. **This setup is only recommended** if you have strong working knowledge and experience in Kubernetes. The rest of this -section will assume this. +section assumes this. ### Cluster topology -The following tables and diagram details the hybrid environment using the same formats +The following tables and diagram detail the hybrid environment using the same formats as the normal environment above. -First starting with the components that run in Kubernetes. The recommendations at this -time use Google Cloud’s Kubernetes Engine (GKE) and associated machine types, but the memory +First are the components that run in Kubernetes. The recommendation at this time is to +use Google Cloud’s Kubernetes Engine (GKE) and associated machine types, but the memory and CPU requirements should translate to most other providers. We hope to update this in the future with further specific cloud provider details. -| Service | Nodes(1) | Configuration | GCP | Allocatable CPUs and Memory | -|-------------------------------------------------------|----------|-------------------------|------------------|-----------------------------| -| Webservice | 4 | 32 vCPU, 28.8 GB memory | `n1-highcpu-32` | 127.5 vCPU, 118 GB memory | -| Sidekiq | 4 | 4 vCPU, 15 GB memory | `n1-standard-4` | 15.5 vCPU, 50 GB memory | -| Supporting services such as NGINX or Prometheus | 2 | 4 vCPU, 15 GB memory | `n1-standard-4` | 7.75 vCPU, 25 GB memory | +| Service | Nodes<sup>1</sup> | Configuration | GCP | Allocatable CPUs and Memory | +|-------------------------------------------------------|-------------------|-------------------------|------------------|-----------------------------| +| Webservice | 4 | 32 vCPU, 28.8 GB memory | `n1-highcpu-32` | 127.5 vCPU, 118 GB memory | +| Sidekiq | 4 | 4 vCPU, 15 GB memory | `n1-standard-4` | 15.5 vCPU, 50 GB memory | +| Supporting services such as NGINX, Prometheus | 2 | 4 vCPU, 15 GB memory | `n1-standard-4` | 7.75 vCPU, 25 GB memory | <!-- Disable ordered list rule https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md029---ordered-list-item-prefix --> <!-- markdownlint-disable MD029 --> @@ -2406,27 +2406,27 @@ future with further specific cloud provider details. Next are the backend components that run on static compute VMs via Omnibus (or External PaaS services where applicable): -| Service | Nodes | Configuration | GCP | -|--------------------------------------------|-------|-------------------------|------------------| -| Consul(1) | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | -| PostgreSQL(1) | 3 | 8 vCPU, 30 GB memory | `n1-standard-8` | -| PgBouncer(1) | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | -| Internal load balancing node(3) | 1 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | -| Redis - Cache(2) | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | -| Redis - Queues / Shared State(2) | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | -| Redis Sentinel - Cache(2) | 3 | 1 vCPU, 3.75 GB memory | `n1-standard-1` | -| Redis Sentinel - Queues / Shared State(2) | 3 | 1 vCPU, 3.75 GB memory | `n1-standard-1` | -| Gitaly | 3 | 16 vCPU, 60 GB memory | `n1-standard-16` | -| Praefect | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | -| Praefect PostgreSQL(1) | 1+ | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | -| Object storage(4) | n/a | n/a | n/a | +| Service | Nodes | Configuration | GCP | +|-----------------------------------------------------|-------|-------------------------|------------------| +| Consul<sup>1</sup> | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | +| PostgreSQL<sup>1</sup> | 3 | 8 vCPU, 30 GB memory | `n1-standard-8` | +| PgBouncer<sup>1</sup> | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | +| Internal load balancing node<sup>3</sup> | 1 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | +| Redis - Cache<sup>2</sup> | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | +| Redis - Queues / Shared State<sup>2</sup> | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | +| Redis Sentinel - Cache<sup>2</sup> | 3 | 1 vCPU, 3.75 GB memory | `n1-standard-1` | +| Redis Sentinel - Queues / Shared State<sup>2</sup> | 3 | 1 vCPU, 3.75 GB memory | `n1-standard-1` | +| Gitaly | 3 | 16 vCPU, 60 GB memory | `n1-standard-16` | +| Praefect | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | +| Praefect PostgreSQL<sup>1</sup> | 1+ | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | +| Object storage<sup>4</sup> | n/a | n/a | n/a | <!-- Disable ordered list rule https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md029---ordered-list-item-prefix --> <!-- 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. 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. -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. <!-- markdownlint-enable MD029 --> NOTE: @@ -2520,11 +2520,11 @@ documents how to apply the calculated configuration to the Helm Chart. #### Webservice Webservice pods typically need about 1 vCPU and 1.25 GB of memory _per worker_. -Each Webservice pod will consume roughly 4 vCPUs and 5 GB of memory using +Each Webservice pod consumes roughly 4 vCPUs and 5 GB of memory using the [recommended topology](#cluster-topology) because four worker processes are created by default and each pod has other small processes running. -For 10k users we recommend a total Puma worker count of around 80. +For 10,000 users we recommend a total Puma worker count of around 80. With the [provided recommendations](#cluster-topology) this allows the deployment of up to 20 Webservice pods with 4 workers per pod and 5 pods per node. Expand available resources using the ratio of 1 vCPU to 1.25 GB of memory _per each worker process_ for each additional diff --git a/doc/administration/reference_architectures/25k_users.md b/doc/administration/reference_architectures/25k_users.md index e45a8f6963c..de222e2890c 100644 --- a/doc/administration/reference_architectures/25k_users.md +++ b/doc/administration/reference_architectures/25k_users.md @@ -15,32 +15,32 @@ full list of reference architectures, see > - **High Availability:** Yes ([Praefect](#configure-praefect-postgresql) needs a third-party PostgreSQL solution for HA) > - **Test requests per second (RPS) rates:** API: 500 RPS, Web: 50 RPS, Git (Pull): 50 RPS, Git (Push): 10 RPS -| Service | Nodes | Configuration | GCP | AWS | Azure | -|------------------------------------------|-------------|-------------------------|------------------|--------------|-----------| -| External load balancing node(3) | 1 | 4 vCPU, 3.6 GB memory | `n1-highcpu-4` | `c5.xlarge` | `F4s v2` | -| Consul(1) | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` | -| PostgreSQL(1) | 3 | 16 vCPU, 60 GB memory | `n1-standard-16` | `m5.4xlarge` | `D16s v3` | -| PgBouncer(1) | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` | -| Internal load balancing node(3) | 1 | 4 vCPU, 3.6GB memory | `n1-highcpu-4` | `c5.large` | `F2s v2` | -| Redis - Cache(2) | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` | `D4s v3` | -| Redis - Queues / Shared State(2) | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` | `D4s v3` | -| Redis Sentinel - Cache(2) | 3 | 1 vCPU, 3.75 GB memory | `n1-standard-1` | `c5.large` | `A1 v2` | -| Redis Sentinel - Queues / Shared State(2)| 3 | 1 vCPU, 3.75 GB memory | `n1-standard-1` | `c5.large` | `A1 v2` | -| Gitaly | 3 | 32 vCPU, 120 GB memory | `n1-standard-32` | `m5.8xlarge` | `D32s v3` | -| Praefect | 3 | 4 vCPU, 3.6 GB memory | `n1-highcpu-4` | `c5.xlarge` | `F4s v2` | -| Praefect PostgreSQL(1) | 1+ | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` | -| Sidekiq | 4 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` | `D4s v3` | -| GitLab Rails | 5 | 32 vCPU, 28.8 GB memory | `n1-highcpu-32` | `c5.9xlarge` | `F32s v2` | -| Monitoring node | 1 | 4 vCPU, 3.6 GB memory | `n1-highcpu-4` | `c5.xlarge` | `F4s v2` | -| Object storage(4) | n/a | n/a | n/a | n/a | n/a | -| NFS server (optional, not recommended) | 1 | 4 vCPU, 3.6 GB memory | `n1-highcpu-4` | `c5.xlarge` | `F4s v2` | +| Service | Nodes | Configuration | GCP | AWS | Azure | +|---------------------------------------------------|-------------|-------------------------|------------------|--------------|-----------| +| External load balancing node<sup>3</sup> | 1 | 4 vCPU, 3.6 GB memory | `n1-highcpu-4` | `c5.xlarge` | `F4s v2` | +| Consul<sup>1</sup> | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` | +| PostgreSQL<sup>1</sup> | 3 | 16 vCPU, 60 GB memory | `n1-standard-16` | `m5.4xlarge` | `D16s v3` | +| PgBouncer<sup>1</sup> | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` | +| Internal load balancing node<sup>3</sup> | 1 | 4 vCPU, 3.6GB memory | `n1-highcpu-4` | `c5.large` | `F2s v2` | +| Redis - Cache<sup>2</sup> | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` | `D4s v3` | +| Redis - Queues / Shared State<sup>2</sup> | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` | `D4s v3` | +| Redis Sentinel - Cache<sup>2</sup> | 3 | 1 vCPU, 3.75 GB memory | `n1-standard-1` | `c5.large` | `A1 v2` | +| Redis Sentinel - Queues / Shared State<sup>2</sup>| 3 | 1 vCPU, 3.75 GB memory | `n1-standard-1` | `c5.large` | `A1 v2` | +| Gitaly | 3 | 32 vCPU, 120 GB memory | `n1-standard-32` | `m5.8xlarge` | `D32s v3` | +| Praefect | 3 | 4 vCPU, 3.6 GB memory | `n1-highcpu-4` | `c5.xlarge` | `F4s v2` | +| Praefect PostgreSQL<sup>1</sup> | 1+ | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` | +| Sidekiq | 4 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` | `D4s v3` | +| GitLab Rails | 5 | 32 vCPU, 28.8 GB memory | `n1-highcpu-32` | `c5.9xlarge` | `F32s v2` | +| Monitoring node | 1 | 4 vCPU, 3.6 GB memory | `n1-highcpu-4` | `c5.xlarge` | `F4s v2` | +| Object storage<sup>4</sup> | n/a | n/a | n/a | n/a | n/a | +| NFS server (optional, not recommended) | 1 | 4 vCPU, 3.6 GB memory | `n1-highcpu-4` | `c5.xlarge` | `F4s v2` | <!-- Disable ordered list rule https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md029---ordered-list-item-prefix --> <!-- 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. 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. -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. <!-- markdownlint-enable MD029 --> NOTE: @@ -141,7 +141,7 @@ is recommended instead of using NFS. Using an object storage service also doesn't require you to provision and maintain a node. It's also worth noting that at this time [Praefect requires its own database server](../gitaly/praefect.md#postgresql) and -that to achieve full High Availability a third party PostgreSQL database solution will be required. +that to achieve full High Availability a third-party PostgreSQL database solution will be required. We hope to offer a built in solutions for these restrictions in the future but in the meantime a non HA PostgreSQL server can be set up via Omnibus GitLab, which the above specs reflect. Refer to the following issues for more information: [`omnibus-gitlab#5919`](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/5919) & [`gitaly#3398`](https://gitlab.com/gitlab-org/gitaly/-/issues/3398) @@ -2380,7 +2380,7 @@ in Kubernetes via our official [Helm Charts](https://docs.gitlab.com/charts/). In this setup, we support running the equivalent of GitLab Rails and Sidekiq nodes in a Kubernetes cluster, named Webservice and Sidekiq respectively. In addition, the following other supporting services are supported: NGINX, Task Runner, Migrations, -Prometheus and Grafana. +Prometheus, and Grafana. Hybrid installations leverage the benefits of both cloud native and traditional compute deployments. With this, _stateless_ components can benefit from cloud native @@ -2391,23 +2391,23 @@ NOTE: This is an **advanced** setup. Running services in Kubernetes is well known to be complex. **This setup is only recommended** if you have strong working knowledge and experience in Kubernetes. The rest of this -section will assume this. +section assumes this. ### Cluster topology -The following tables and diagram details the hybrid environment using the same formats +The following tables and diagram detail the hybrid environment using the same formats as the normal environment above. -First starting with the components that run in Kubernetes. The recommendations at this -time use Google Cloud’s Kubernetes Engine (GKE) and associated machine types, but the memory +First are the components that run in Kubernetes. The recommendation at this time is to +use Google Cloud’s Kubernetes Engine (GKE) and associated machine types, but the memory and CPU requirements should translate to most other providers. We hope to update this in the future with further specific cloud provider details. -| Service | Nodes(1) | Configuration | GCP | Allocatable CPUs and Memory | -|-------------------------------------------------------|----------|-------------------------|------------------|-----------------------------| -| Webservice | 7 | 32 vCPU, 28.8 GB memory | `n1-highcpu-32` | 223 vCPU, 206.5 GB memory | -| Sidekiq | 4 | 4 vCPU, 15 GB memory | `n1-standard-4` | 15.5 vCPU, 50 GB memory | -| Supporting services such as NGINX, Prometheus, etc. | 2 | 4 vCPU, 15 GB memory | `n1-standard-4` | 7.75 vCPU, 25 GB memory | +| Service | Nodes<sup>1</sup> | Configuration | GCP | Allocatable CPUs and Memory | +|-------------------------------------------------------|-------------------|-------------------------|------------------|-----------------------------| +| Webservice | 7 | 32 vCPU, 28.8 GB memory | `n1-highcpu-32` | 223 vCPU, 206.5 GB memory | +| Sidekiq | 4 | 4 vCPU, 15 GB memory | `n1-standard-4` | 15.5 vCPU, 50 GB memory | +| Supporting services such as NGINX, Prometheus | 2 | 4 vCPU, 15 GB memory | `n1-standard-4` | 7.75 vCPU, 25 GB memory | <!-- Disable ordered list rule https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md029---ordered-list-item-prefix --> <!-- markdownlint-disable MD029 --> @@ -2418,27 +2418,27 @@ future with further specific cloud provider details. Next are the backend components that run on static compute VMs via Omnibus (or External PaaS services where applicable): -| Service | Nodes | Configuration | GCP | -|--------------------------------------------|-------|-------------------------|------------------| -| Consul(1) | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | -| PostgreSQL(1) | 3 | 16 vCPU, 60 GB memory | `n1-standard-16` | -| PgBouncer(1) | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | -| Internal load balancing node(3) | 1 | 4 vCPU, 3.6GB memory | `n1-highcpu-4` | -| Redis - Cache(2) | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | -| Redis - Queues / Shared State(2) | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | -| Redis Sentinel - Cache(2) | 3 | 1 vCPU, 3.75 GB memory | `n1-standard-1` | -| Redis Sentinel - Queues / Shared State(2) | 3 | 1 vCPU, 3.75 GB memory | `n1-standard-1` | -| Gitaly | 3 | 32 vCPU, 120 GB memory | `n1-standard-32` | -| Praefect | 3 | 4 vCPU, 3.6 GB memory | `n1-highcpu-4` | -| Praefect PostgreSQL(1) | 1+ | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | -| Object storage(4) | n/a | n/a | n/a | +| Service | Nodes | Configuration | GCP | +|-----------------------------------------------------|-------|-------------------------|------------------| +| Consul<sup>1</sup> | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | +| PostgreSQL<sup>1</sup> | 3 | 16 vCPU, 60 GB memory | `n1-standard-16` | +| PgBouncer<sup>1</sup> | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | +| Internal load balancing node<sup>3</sup> | 1 | 4 vCPU, 3.6GB memory | `n1-highcpu-4` | +| Redis - Cache<sup>2</sup> | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | +| Redis - Queues / Shared State<sup>2</sup> | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | +| Redis Sentinel - Cache<sup>2</sup> | 3 | 1 vCPU, 3.75 GB memory | `n1-standard-1` | +| Redis Sentinel - Queues / Shared State<sup>2</sup> | 3 | 1 vCPU, 3.75 GB memory | `n1-standard-1` | +| Gitaly | 3 | 32 vCPU, 120 GB memory | `n1-standard-32` | +| Praefect | 3 | 4 vCPU, 3.6 GB memory | `n1-highcpu-4` | +| Praefect PostgreSQL<sup>1</sup> | 1+ | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | +| Object storage<sup>4</sup> | n/a | n/a | n/a | <!-- Disable ordered list rule https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md029---ordered-list-item-prefix --> <!-- 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. 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. -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. <!-- markdownlint-enable MD029 --> NOTE: @@ -2532,11 +2532,11 @@ documents how to apply the calculated configuration to the Helm Chart. #### Webservice Webservice pods typically need about 1 vCPU and 1.25 GB of memory _per worker_. -Each Webservice pod will consume roughly 4 vCPUs and 5 GB of memory using +Each Webservice pod consumes roughly 4 vCPUs and 5 GB of memory using the [recommended topology](#cluster-topology) because four worker processes are created by default and each pod has other small processes running. -For 25k users we recommend a total Puma worker count of around 140. +For 25,000 users we recommend a total Puma worker count of around 140. With the [provided recommendations](#cluster-topology) this allows the deployment of up to 35 Webservice pods with 4 workers per pod and 5 pods per node. Expand available resources using the ratio of 1 vCPU to 1.25 GB of memory _per each worker process_ for each additional diff --git a/doc/administration/reference_architectures/2k_users.md b/doc/administration/reference_architectures/2k_users.md index ff3db877553..19a1d74b7bc 100644 --- a/doc/administration/reference_architectures/2k_users.md +++ b/doc/administration/reference_architectures/2k_users.md @@ -18,20 +18,20 @@ For a full list of reference architectures, see | Service | Nodes | Configuration | GCP | AWS | Azure | |------------------------------------------|--------|-------------------------|-----------------|--------------|----------| -| Load balancer(3) | 1 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` | -| PostgreSQL(1) | 1 | 2 vCPU, 7.5 GB memory | `n1-standard-2` | `m5.large` | `D2s v3` | -| Redis(2) | 1 | 1 vCPU, 3.75 GB memory | `n1-standard-1` | `m5.large` | `D2s v3` | +| Load balancer<sup>3</sup> | 1 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` | +| PostgreSQL<sup>1</sup> | 1 | 2 vCPU, 7.5 GB memory | `n1-standard-2` | `m5.large` | `D2s v3` | +| Redis<sup>2</sup> | 1 | 1 vCPU, 3.75 GB memory | `n1-standard-1` | `m5.large` | `D2s v3` | | Gitaly | 1 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` | `D4s v3` | | GitLab Rails | 2 | 8 vCPU, 7.2 GB memory | `n1-highcpu-8` | `c5.2xlarge` | `F8s v2` | | Monitoring node | 1 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` | -| Object storage(4) | n/a | n/a | n/a | n/a | n/a | +| Object storage<sup>4</sup> | n/a | n/a | n/a | n/a | n/a | | NFS server (optional, not recommended) | 1 | 4 vCPU, 3.6 GB memory | `n1-highcpu-4` | `c5.xlarge` | `F4s v2` | <!-- 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. -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. -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. +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. +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. +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. <!-- markdownlint-enable MD029 --> NOTE: diff --git a/doc/administration/reference_architectures/3k_users.md b/doc/administration/reference_architectures/3k_users.md index 7b6132bbf08..c60def6ea41 100644 --- a/doc/administration/reference_architectures/3k_users.md +++ b/doc/administration/reference_architectures/3k_users.md @@ -27,19 +27,19 @@ For a full list of reference architectures, see | Service | Nodes | Configuration | GCP | AWS | Azure | |--------------------------------------------|-------------|-----------------------|-----------------|--------------|----------| -| External load balancing node(3) | 1 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` | -| Redis(2) | 3 | 2 vCPU, 7.5 GB memory | `n1-standard-2` | `m5.large` | `D2s v3` | -| Consul(1) + Sentinel(2) | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` | -| PostgreSQL(1) | 3 | 2 vCPU, 7.5 GB memory | `n1-standard-2` | `m5.large` | `D2s v3` | -| PgBouncer(1) | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` | -| Internal load balancing node(3) | 1 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` | +| External load balancing node<sup>3</sup> | 1 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` | +| Redis<sup>2</sup> | 3 | 2 vCPU, 7.5 GB memory | `n1-standard-2` | `m5.large` | `D2s v3` | +| Consul<sup>1</sup> + Sentinel<sup>2</sup> | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` | +| PostgreSQL<sup>1</sup> | 3 | 2 vCPU, 7.5 GB memory | `n1-standard-2` | `m5.large` | `D2s v3` | +| PgBouncer<sup>1</sup> | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` | +| Internal load balancing node<sup>3</sup> | 1 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` | | Gitaly | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` | `D4s v3` | | Praefect | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` | -| Praefect PostgreSQL(1) | 1+ | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` | +| Praefect PostgreSQL<sup>1</sup> | 1+ | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` | | Sidekiq | 4 | 2 vCPU, 7.5 GB memory | `n1-standard-2` | `m5.large` | `D2s v3` | | GitLab Rails | 3 | 8 vCPU, 7.2 GB memory | `n1-highcpu-8` | `c5.2xlarge` | `F8s v2` | | Monitoring node | 1 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` | -| Object storage(4) | n/a | n/a | n/a | n/a | n/a | +| Object storage<sup>4</sup> | n/a | n/a | n/a | n/a | n/a | | NFS server (optional, not recommended) | 1 | 4 vCPU, 3.6 GB memory | `n1-highcpu-4` | `c5.xlarge` | `F4s v2` | <!-- Disable ordered list rule https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md029---ordered-list-item-prefix --> @@ -47,7 +47,7 @@ For a full list of reference architectures, see 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. 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. -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. <!-- markdownlint-enable MD029 --> NOTE: @@ -63,10 +63,7 @@ together { collections "**Sidekiq** x4" as sidekiq #ff8dd1 } -together { - card "**Prometheus + Grafana**" as monitor #7FFFD4 - collections "**Consul** x3" as consul #e76a9b -} +card "**Prometheus + Grafana**" as monitor #7FFFD4 card "Gitaly Cluster" as gitaly_cluster { collections "**Praefect** x3" as praefect #FF8C00 @@ -86,14 +83,15 @@ card "Database" as database { postgres_primary .[#4EA7FF]> postgres_secondary } -card "redis" as redis { - collections "**Redis Persistent** x3" as redis_persistent #FF6347 - collections "**Redis Cache** x3" as redis_cache #FF6347 - collections "**Redis Persistent Sentinel** x3" as redis_persistent_sentinel #FF6347 - collections "**Redis Cache Sentinel** x3"as redis_cache_sentinel #FF6347 +card "**Consul + Sentinel**" as consul_sentinel { + collections "**Consul** x3" as consul #e76a9b + collections "**Redis Sentinel** x3" as sentinel #e6e727 +} - redis_persistent <.[#FF6347]- redis_persistent_sentinel - redis_cache <.[#FF6347]- redis_cache_sentinel +card "Redis" as redis { + collections "**Redis** x3" as redis_nodes #FF6347 + + redis_nodes <.[#FF6347]- sentinel } cloud "**Object Storage**" as object_storage #white @@ -2097,6 +2095,184 @@ but with smaller performance requirements, several modifications can be consider - As Redis Sentinel runs on the same box as Consul in this architecture, it may need to be run on a separate box if Redis is still being run via Omnibus. - Redis: Can be run on reputable Cloud PaaS solutions such as Google Memorystore and AWS ElastiCache. In this setup, the Redis Sentinel is no longer required. +## Cloud Native Hybrid reference architecture with Helm Charts (alternative) + +As an alternative approach, you can also run select components of GitLab as Cloud Native +in Kubernetes via our official [Helm Charts](https://docs.gitlab.com/charts/). +In this setup, we support running the equivalent of GitLab Rails and Sidekiq nodes +in a Kubernetes cluster, named Webservice and Sidekiq respectively. In addition, +the following other supporting services are supported: NGINX, Task Runner, Migrations, +Prometheus, and Grafana. + +Hybrid installations leverage the benefits of both cloud native and traditional +compute deployments. With this, _stateless_ components can benefit from cloud native +workload management benefits while _stateful_ components are deployed in compute VMs +with Omnibus to benefit from increased permanence. + +NOTE: +This is an **advanced** setup. Running services in Kubernetes is well known +to be complex. **This setup is only recommended** if you have strong working +knowledge and experience in Kubernetes. The rest of this +section assumes this. + +### Cluster topology + +The following tables and diagram detail the hybrid environment using the same formats +as the normal environment above. + +First are the components that run in Kubernetes. The recommendation at this time is to +use Google Cloud’s Kubernetes Engine (GKE) and associated machine types, but the memory +and CPU requirements should translate to most other providers. We hope to update this in the +future with further specific cloud provider details. + +| Service | Nodes<sup>1</sup> | Configuration | GCP | Allocatable CPUs and Memory | +|-------------------------------------------------------|-------------------|-------------------------|------------------|-----------------------------| +| Webservice | 2 | 16 vCPU, 14.4 GB memory | `n1-highcpu-16` | 31.8 vCPU, 24.8 GB memory | +| Sidekiq | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | 11.8 vCPU, 38.9 GB memory | +| Supporting services such as NGINX, Prometheus | 2 | 2 vCPU, 7.5 GB memory | `n1-standard-2` | 3.9 vCPU, 11.8 GB memory | + +<!-- Disable ordered list rule https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md029---ordered-list-item-prefix --> +<!-- markdownlint-disable MD029 --> +1. Nodes configuration is shown as it is forced to ensure pod vcpu / memory ratios and avoid scaling during **performance testing**. + In production deployments there is no need to assign pods to nodes. A minimum of three nodes in three different availability zones is strongly recommended to align with resilient cloud architecture practices. +<!-- markdownlint-enable MD029 --> + +Next are the backend components that run on static compute VMs via Omnibus (or External PaaS +services where applicable): + +| Service | Nodes | Configuration | GCP | +|--------------------------------------------|-------|-------------------------|------------------| +| Redis<sup>2</sup> | 3 | 2 vCPU, 7.5 GB memory | `n1-standard-2` | +| Consul<sup>1</sup> + Sentinel<sup>2</sup> | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | +| PostgreSQL<sup>1</sup> | 3 | 2 vCPU, 7.5 GB memory | `n1-standard-2` | +| PgBouncer<sup>1</sup> | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | +| Internal load balancing node<sup>3</sup> | 1 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | +| Gitaly | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | +| Praefect | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | +| Praefect PostgreSQL<sup>1</sup> | 1+ | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | +| Object storage<sup>4</sup> | n/a | n/a | n/a | + +<!-- Disable ordered list rule https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md029---ordered-list-item-prefix --> +<!-- 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. +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. +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. +<!-- markdownlint-enable MD029 --> + +NOTE: +For all PaaS solutions that involve configuring instances, it is strongly recommended to implement a minimum of three nodes in three different availability zones to align with resilient cloud architecture practices. + +```plantuml +@startuml 3k + +card "Kubernetes via Helm Charts" as kubernetes { + card "**External Load Balancer**" as elb #6a9be7 + + together { + collections "**Webservice** x2" as gitlab #32CD32 + collections "**Sidekiq** x3" as sidekiq #ff8dd1 + } + + card "**Prometheus + Grafana**" as monitor #7FFFD4 + card "**Supporting Services**" as support +} + +card "**Internal Load Balancer**" as ilb #9370DB + +card "**Consul + Sentinel**" as consul_sentinel { + collections "**Consul** x3" as consul #e76a9b + collections "**Redis Sentinel** x3" as sentinel #e6e727 +} + +card "Gitaly Cluster" as gitaly_cluster { + collections "**Praefect** x3" as praefect #FF8C00 + collections "**Gitaly** x3" as gitaly #FF8C00 + card "**Praefect PostgreSQL***\n//Non fault-tolerant//" as praefect_postgres #FF8C00 + + praefect -[#FF8C00]-> gitaly + praefect -[#FF8C00]> praefect_postgres +} + +card "Database" as database { + collections "**PGBouncer** x3" as pgbouncer #4EA7FF + card "**PostgreSQL** (Primary)" as postgres_primary #4EA7FF + collections "**PostgreSQL** (Secondary) x2" as postgres_secondary #4EA7FF + + pgbouncer -[#4EA7FF]-> postgres_primary + postgres_primary .[#4EA7FF]> postgres_secondary +} + +card "Redis" as redis { + collections "**Redis** x3" as redis_nodes #FF6347 + + redis_nodes <.[#FF6347]- sentinel +} + +cloud "**Object Storage**" as object_storage #white + +elb -[#6a9be7]-> gitlab +elb -[#6a9be7]-> monitor +elb -[hidden]-> support + +gitlab -[#32CD32]--> ilb +gitlab -[#32CD32]-> object_storage +gitlab -[#32CD32]---> redis +gitlab -[hidden]--> consul + +sidekiq -[#ff8dd1]--> ilb +sidekiq -[#ff8dd1]-> object_storage +sidekiq -[#ff8dd1]---> redis +sidekiq -[hidden]--> consul + +ilb -[#9370DB]-> gitaly_cluster +ilb -[#9370DB]-> database + +consul .[#e76a9b]-> database +consul .[#e76a9b]-> gitaly_cluster +consul .[#e76a9b,norank]--> redis + +monitor .[#7FFFD4]> consul +monitor .[#7FFFD4]-> database +monitor .[#7FFFD4]-> gitaly_cluster +monitor .[#7FFFD4,norank]--> redis +monitor .[#7FFFD4]> ilb +monitor .[#7FFFD4,norank]u--> elb + +@enduml +``` + +### Resource usage settings + +The following formulas help when calculating how many pods may be deployed within resource constraints. +The [3k reference architecture example values file](https://gitlab.com/gitlab-org/charts/gitlab/-/blob/master/examples/ref/3k.yaml) +documents how to apply the calculated configuration to the Helm Chart. + +#### Webservice + +Webservice pods typically need about 1 vCPU and 1.25 GB of memory _per worker_. +Each Webservice pod consumes roughly 4 vCPUs and 5 GB of memory using +the [recommended topology](#cluster-topology) because four worker processes +are created by default and each pod has other small processes running. + +For 3,000 users we recommend a total Puma worker count of around 16. +With the [provided recommendations](#cluster-topology) this allows the deployment of up to 4 +Webservice pods with 4 workers per pod and 2 pods per node. Expand available resources using +the ratio of 1 vCPU to 1.25 GB of memory _per each worker process_ for each additional +Webservice pod. + +For further information on resource usage, see the [Webservice resources](https://docs.gitlab.com/charts/charts/gitlab/webservice/#resources). + +#### Sidekiq + +Sidekiq pods should generally have 1 vCPU and 2 GB of memory. + +[The provided starting point](#cluster-topology) allows the deployment of up to +8 Sidekiq pods. Expand available resources using the 1 vCPU to 2GB memory +ratio for each additional pod. + +For further information on resource usage, see the [Sidekiq resources](https://docs.gitlab.com/charts/charts/gitlab/sidekiq/#resources). + <div align="right"> <a type="button" class="btn btn-default" href="#setup-components"> Back to setup components <i class="fa fa-angle-double-up" aria-hidden="true"></i> diff --git a/doc/administration/reference_architectures/50k_users.md b/doc/administration/reference_architectures/50k_users.md index 766f94f6c53..acc0a3c27e0 100644 --- a/doc/administration/reference_architectures/50k_users.md +++ b/doc/administration/reference_architectures/50k_users.md @@ -15,32 +15,32 @@ full list of reference architectures, see > - **High Availability:** Yes ([Praefect](#configure-praefect-postgresql) needs a third-party PostgreSQL solution for HA) > - **Test requests per second (RPS) rates:** API: 1000 RPS, Web: 100 RPS, Git (Pull): 100 RPS, Git (Push): 20 RPS -| Service | Nodes | Configuration | GCP | AWS | Azure | -|------------------------------------------|-------------|-------------------------|------------------|---------------|-----------| -| External load balancing node(3) | 1 | 8 vCPU, 7.2 GB memory | `n1-highcpu-8` | `c5.2xlarge` | `F8s v2` | -| Consul(1) | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` | -| PostgreSQL(1) | 3 | 32 vCPU, 120 GB memory | `n1-standard-32` | `m5.8xlarge` | `D32s v3` | -| PgBouncer(1) | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` | -| Internal load balancing node(3) | 1 | 8 vCPU, 7.2 GB memory | `n1-highcpu-8` | `c5.2xlarge` | `F8s v2` | -| Redis - Cache(2) | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` | `D4s v3` | -| Redis - Queues / Shared State(2) | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` | `D4s v3` | -| Redis Sentinel - Cache(2) | 3 | 1 vCPU, 3.75 GB memory | `n1-standard-1` | `c5.large` | `A1 v2` | -| Redis Sentinel - Queues / Shared State(2)| 3 | 1 vCPU, 3.75 GB memory | `n1-standard-1` | `c5.large` | `A1 v2` | -| Gitaly | 3 | 64 vCPU, 240 GB memory | `n1-standard-64` | `m5.16xlarge` | `D64s v3` | -| Praefect | 3 | 4 vCPU, 3.6 GB memory | `n1-highcpu-4` | `c5.xlarge` | `F4s v2` | -| Praefect PostgreSQL(1) | 1+ | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` | -| Sidekiq | 4 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` | `D4s v3` | -| GitLab Rails | 12 | 32 vCPU, 28.8 GB memory | `n1-highcpu-32` | `c5.9xlarge` | `F32s v2` | -| Monitoring node | 1 | 4 vCPU, 3.6 GB memory | `n1-highcpu-4` | `c5.xlarge` | `F4s v2` | -| Object storage(4) | n/a | n/a | n/a | n/a | n/a | -| NFS server (optional, not recommended) | 1 | 4 vCPU, 3.6 GB memory | `n1-highcpu-4` | `c5.xlarge` | `F4s v2` | +| Service | Nodes | Configuration | GCP | AWS | Azure | +|---------------------------------------------------|-------------|-------------------------|------------------|---------------|-----------| +| External load balancing node<sup>3</sup> | 1 | 8 vCPU, 7.2 GB memory | `n1-highcpu-8` | `c5.2xlarge` | `F8s v2` | +| Consul<sup>1</sup> | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` | +| PostgreSQL<sup>1</sup> | 3 | 32 vCPU, 120 GB memory | `n1-standard-32` | `m5.8xlarge` | `D32s v3` | +| PgBouncer<sup>1</sup> | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` | +| Internal load balancing node<sup>3</sup> | 1 | 8 vCPU, 7.2 GB memory | `n1-highcpu-8` | `c5.2xlarge` | `F8s v2` | +| Redis - Cache<sup>2</sup> | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` | `D4s v3` | +| Redis - Queues / Shared State<sup>2</sup> | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` | `D4s v3` | +| Redis Sentinel - Cache<sup>2</sup> | 3 | 1 vCPU, 3.75 GB memory | `n1-standard-1` | `c5.large` | `A1 v2` | +| Redis Sentinel - Queues / Shared State<sup>2</sup>| 3 | 1 vCPU, 3.75 GB memory | `n1-standard-1` | `c5.large` | `A1 v2` | +| Gitaly | 3 | 64 vCPU, 240 GB memory | `n1-standard-64` | `m5.16xlarge` | `D64s v3` | +| Praefect | 3 | 4 vCPU, 3.6 GB memory | `n1-highcpu-4` | `c5.xlarge` | `F4s v2` | +| Praefect PostgreSQL<sup>1</sup> | 1+ | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` | +| Sidekiq | 4 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` | `D4s v3` | +| GitLab Rails | 12 | 32 vCPU, 28.8 GB memory | `n1-highcpu-32` | `c5.9xlarge` | `F32s v2` | +| Monitoring node | 1 | 4 vCPU, 3.6 GB memory | `n1-highcpu-4` | `c5.xlarge` | `F4s v2` | +| Object storage<sup>4</sup> | n/a | n/a | n/a | n/a | n/a | +| NFS server (optional, not recommended) | 1 | 4 vCPU, 3.6 GB memory | `n1-highcpu-4` | `c5.xlarge` | `F4s v2` | <!-- Disable ordered list rule https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md029---ordered-list-item-prefix --> <!-- 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. 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. -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. <!-- markdownlint-enable MD029 --> NOTE: @@ -141,7 +141,7 @@ is recommended instead of using NFS. Using an object storage service also doesn't require you to provision and maintain a node. It's also worth noting that at this time [Praefect requires its own database server](../gitaly/praefect.md#postgresql) and -that to achieve full High Availability a third party PostgreSQL database solution will be required. +that to achieve full High Availability a third-party PostgreSQL database solution will be required. We hope to offer a built in solutions for these restrictions in the future but in the meantime a non HA PostgreSQL server can be set up via Omnibus GitLab, which the above specs reflect. Refer to the following issues for more information: [`omnibus-gitlab#5919`](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/5919) & [`gitaly#3398`](https://gitlab.com/gitlab-org/gitaly/-/issues/3398) @@ -2391,7 +2391,7 @@ in Kubernetes via our official [Helm Charts](https://docs.gitlab.com/charts/). In this setup, we support running the equivalent of GitLab Rails and Sidekiq nodes in a Kubernetes cluster, named Webservice and Sidekiq respectively. In addition, the following other supporting services are supported: NGINX, Task Runner, Migrations, -Prometheus and Grafana. +Prometheus, and Grafana. Hybrid installations leverage the benefits of both cloud native and traditional compute deployments. With this, _stateless_ components can benefit from cloud native @@ -2402,23 +2402,23 @@ NOTE: This is an **advanced** setup. Running services in Kubernetes is well known to be complex. **This setup is only recommended** if you have strong working knowledge and experience in Kubernetes. The rest of this -section will assume this. +section assumes this. ### Cluster topology -The following tables and diagram details the hybrid environment using the same formats +The following tables and diagram detail the hybrid environment using the same formats as the normal environment above. -First starting with the components that run in Kubernetes. The recommendations at this -time use Google Cloud’s Kubernetes Engine (GKE) and associated machine types, but the memory +First are the components that run in Kubernetes. The recommendation at this time is to +use Google Cloud’s Kubernetes Engine (GKE) and associated machine types, but the memory and CPU requirements should translate to most other providers. We hope to update this in the future with further specific cloud provider details. -| Service | Nodes(1) | Configuration | GCP | Allocatable CPUs and Memory | -|-------------------------------------------------------|----------|-------------------------|------------------|-----------------------------| -| Webservice | 16 | 32 vCPU, 28.8 GB memory | `n1-highcpu-32` | 510 vCPU, 472 GB memory | -| Sidekiq | 4 | 4 vCPU, 15 GB memory | `n1-standard-4` | 15.5 vCPU, 50 GB memory | -| Supporting services such as NGINX, Prometheus, etc. | 2 | 4 vCPU, 15 GB memory | `n1-standard-4` | 7.75 vCPU, 25 GB memory | +| Service | Nodes<sup>1</sup> | Configuration | GCP | Allocatable CPUs and Memory | +|-------------------------------------------------------|-------------------|-------------------------|------------------|-----------------------------| +| Webservice | 16 | 32 vCPU, 28.8 GB memory | `n1-highcpu-32` | 510 vCPU, 472 GB memory | +| Sidekiq | 4 | 4 vCPU, 15 GB memory | `n1-standard-4` | 15.5 vCPU, 50 GB memory | +| Supporting services such as NGINX, Prometheus | 2 | 4 vCPU, 15 GB memory | `n1-standard-4` | 7.75 vCPU, 25 GB memory | <!-- Disable ordered list rule https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md029---ordered-list-item-prefix --> <!-- markdownlint-disable MD029 --> @@ -2429,27 +2429,27 @@ future with further specific cloud provider details. Next are the backend components that run on static compute VMs via Omnibus (or External PaaS services where applicable): -| Service | Nodes | Configuration | GCP | -|--------------------------------------------|-------|-------------------------|------------------| -| Consul(1) | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | -| PostgreSQL(1) | 3 | 32 vCPU, 120 GB memory | `n1-standard-32` | -| PgBouncer(1) | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | -| Internal load balancing node(3) | 1 | 8 vCPU, 7.2 GB memory | `n1-highcpu-8` | -| Redis - Cache(2) | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | -| Redis - Queues / Shared State(2) | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | -| Redis Sentinel - Cache(2) | 3 | 1 vCPU, 3.75 GB memory | `n1-standard-1` | -| Redis Sentinel - Queues / Shared State(2) | 3 | 1 vCPU, 3.75 GB memory | `n1-standard-1` | -| Gitaly | 3 | 64 vCPU, 240 GB memory | `n1-standard-64` | -| Praefect | 3 | 4 vCPU, 3.6 GB memory | `n1-highcpu-4` | -| Praefect PostgreSQL(1) | 1+ | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | -| Object storage(4) | n/a | n/a | n/a | +| Service | Nodes | Configuration | GCP | +|-----------------------------------------------------|-------|-------------------------|------------------| +| Consul<sup>1</sup> | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | +| PostgreSQL<sup>1</sup> | 3 | 32 vCPU, 120 GB memory | `n1-standard-32` | +| PgBouncer<sup>1</sup> | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | +| Internal load balancing node<sup>3</sup> | 1 | 8 vCPU, 7.2 GB memory | `n1-highcpu-8` | +| Redis - Cache<sup>2</sup> | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | +| Redis - Queues / Shared State<sup>2</sup> | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | +| Redis Sentinel - Cache<sup>2</sup> | 3 | 1 vCPU, 3.75 GB memory | `n1-standard-1` | +| Redis Sentinel - Queues / Shared State<sup>2</sup> | 3 | 1 vCPU, 3.75 GB memory | `n1-standard-1` | +| Gitaly | 3 | 64 vCPU, 240 GB memory | `n1-standard-64` | +| Praefect | 3 | 4 vCPU, 3.6 GB memory | `n1-highcpu-4` | +| Praefect PostgreSQL<sup>1</sup> | 1+ | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | +| Object storage<sup>4</sup> | n/a | n/a | n/a | <!-- Disable ordered list rule https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md029---ordered-list-item-prefix --> <!-- 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. 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. -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. <!-- markdownlint-enable MD029 --> NOTE: @@ -2543,11 +2543,11 @@ documents how to apply the calculated configuration to the Helm Chart. #### Webservice Webservice pods typically need about 1 vCPU and 1.25 GB of memory _per worker_. -Each Webservice pod will consume roughly 4 vCPUs and 5 GB of memory using +Each Webservice pod consumes roughly 4 vCPUs and 5 GB of memory using the [recommended topology](#cluster-topology) because four worker processes are created by default and each pod has other small processes running. -For 50k users we recommend a total Puma worker count of around 320. +For 50,000 users we recommend a total Puma worker count of around 320. With the [provided recommendations](#cluster-topology) this allows the deployment of up to 80 Webservice pods with 4 workers per pod and 5 pods per node. Expand available resources using the ratio of 1 vCPU to 1.25 GB of memory _per each worker process_ for each additional diff --git a/doc/administration/reference_architectures/5k_users.md b/doc/administration/reference_architectures/5k_users.md index e57c4545b13..8fcd350d22a 100644 --- a/doc/administration/reference_architectures/5k_users.md +++ b/doc/administration/reference_architectures/5k_users.md @@ -24,19 +24,19 @@ costly-to-operate environment by using the | Service | Nodes | Configuration | GCP | AWS | Azure | |--------------------------------------------|-------------|-------------------------|-----------------|--------------|----------| -| External load balancing node(3) | 1 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` | -| Redis(2) | 3 | 2 vCPU, 7.5 GB memory | `n1-standard-2` | `m5.large` | `D2s v3` | -| Consul(1) + Sentinel(2) | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` | -| PostgreSQL(1) | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` | `D4s v3` | -| PgBouncer(1) | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` | -| Internal load balancing node(3) | 1 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` | +| External load balancing node<sup>3</sup> | 1 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` | +| Redis<sup>2</sup> | 3 | 2 vCPU, 7.5 GB memory | `n1-standard-2` | `m5.large` | `D2s v3` | +| Consul<sup>1</sup> + Sentinel<sup>2</sup> | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` | +| PostgreSQL<sup>1</sup> | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` | `D4s v3` | +| PgBouncer<sup>1</sup> | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` | +| Internal load balancing node<sup>3</sup> | 1 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` | | Gitaly | 3 | 8 vCPU, 30 GB memory | `n1-standard-8` | `m5.2xlarge` | `D8s v3` | | Praefect | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` | -| Praefect PostgreSQL(1) | 1+ | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` | +| Praefect PostgreSQL<sup>1</sup> | 1+ | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` | | Sidekiq | 4 | 2 vCPU, 7.5 GB memory | `n1-standard-2` | `m5.large` | `D2s v3` | | GitLab Rails | 3 | 16 vCPU, 14.4 GB memory | `n1-highcpu-16` | `c5.4xlarge` | `F16s v2`| | Monitoring node | 1 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` | -| Object storage(4) | n/a | n/a | n/a | n/a | n/a | +| Object storage<sup>4</sup> | n/a | n/a | n/a | n/a | n/a | | NFS server (optional, not recommended) | 1 | 4 vCPU, 3.6 GB memory | `n1-highcpu-4` | `c5.xlarge` | `F4s v2` | <!-- Disable ordered list rule https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md029---ordered-list-item-prefix --> @@ -44,7 +44,7 @@ costly-to-operate environment by using the 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. 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. -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. <!-- markdownlint-enable MD029 --> NOTE: @@ -80,9 +80,9 @@ card "Database" as database { postgres_primary .[#4EA7FF]> postgres_secondary } -node "**Consul + Sentinel** x3" as consul_sentinel { - component Consul as consul #e76a9b - component Sentinel as sentinel #e6e727 +card "**Consul + Sentinel**" as consul_sentinel { + collections "**Consul** x3" as consul #e76a9b + collections "**Redis Sentinel** x3" as sentinel #e6e727 } card "Redis" as redis { @@ -143,7 +143,7 @@ is recommended instead of using NFS. Using an object storage service also doesn't require you to provision and maintain a node. It's also worth noting that at this time [Praefect requires its own database server](../gitaly/praefect.md#postgresql) and -that to achieve full High Availability a third party PostgreSQL database solution will be required. +that to achieve full High Availability a third-party PostgreSQL database solution will be required. We hope to offer a built in solutions for these restrictions in the future but in the meantime a non HA PostgreSQL server can be set up via Omnibus GitLab, which the above specs reflect. Refer to the following issues for more information: [`omnibus-gitlab#5919`](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/5919) & [`gitaly#3398`](https://gitlab.com/gitlab-org/gitaly/-/issues/3398) @@ -2072,7 +2072,7 @@ in Kubernetes via our official [Helm Charts](https://docs.gitlab.com/charts/). In this setup, we support running the equivalent of GitLab Rails and Sidekiq nodes in a Kubernetes cluster, named Webservice and Sidekiq respectively. In addition, the following other supporting services are supported: NGINX, Task Runner, Migrations, -Prometheus and Grafana. +Prometheus, and Grafana. Hybrid installations leverage the benefits of both cloud native and traditional compute deployments. With this, _stateless_ components can benefit from cloud native @@ -2083,23 +2083,23 @@ NOTE: This is an **advanced** setup. Running services in Kubernetes is well known to be complex. **This setup is only recommended** if you have strong working knowledge and experience in Kubernetes. The rest of this -section will assume this. +section assumes this. ### Cluster topology -The following tables and diagram details the hybrid environment using the same formats +The following tables and diagram detail the hybrid environment using the same formats as the normal environment above. -First starting with the components that run in Kubernetes. The recommendations at this -time use Google Cloud’s Kubernetes Engine (GKE) and associated machine types, but the memory +First are the components that run in Kubernetes. The recommendation at this time is to +use Google Cloud’s Kubernetes Engine (GKE) and associated machine types, but the memory and CPU requirements should translate to most other providers. We hope to update this in the future with further specific cloud provider details. -| Service | Nodes(1) | Configuration | GCP | Allocatable CPUs and Memory | -|-------------------------------------------------------|----------|-------------------------|------------------|-----------------------------| -| Webservice | 5 | 16 vCPU, 14.4 GB memory | `n1-highcpu-16` | 79.5 vCPU, 62 GB memory | -| Sidekiq | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | 11.8 vCPU, 38.9 GB memory | -| Supporting services such as NGINX, Prometheus, etc. | 2 | 2 vCPU, 7.5 GB memory | `n1-standard-2` | 3.9 vCPU, 11.8 GB memory | +| Service | Nodes<sup>1</sup> | Configuration | GCP | Allocatable CPUs and Memory | +|-------------------------------------------------------|-------------------|-------------------------|------------------|-----------------------------| +| Webservice | 5 | 16 vCPU, 14.4 GB memory | `n1-highcpu-16` | 79.5 vCPU, 62 GB memory | +| Sidekiq | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | 11.8 vCPU, 38.9 GB memory | +| Supporting services such as NGINX, Prometheus | 2 | 2 vCPU, 7.5 GB memory | `n1-standard-2` | 3.9 vCPU, 11.8 GB memory | <!-- Disable ordered list rule https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md029---ordered-list-item-prefix --> <!-- markdownlint-disable MD029 --> @@ -2112,22 +2112,22 @@ services where applicable): | Service | Nodes | Configuration | GCP | |--------------------------------------------|-------|-------------------------|------------------| -| Redis(2) | 3 | 2 vCPU, 7.5 GB memory | `n1-standard-2` | -| Consul(1) + Sentinel(2) | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | -| PostgreSQL(1) | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | -| PgBouncer(1) | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | -| Internal load balancing node(3) | 1 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | +| Redis<sup>2</sup> | 3 | 2 vCPU, 7.5 GB memory | `n1-standard-2` | +| Consul<sup>1</sup> + Sentinel<sup>2</sup> | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | +| PostgreSQL<sup>1</sup> | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | +| PgBouncer<sup>1</sup> | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | +| Internal load balancing node<sup>3</sup> | 1 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | | Gitaly | 3 | 8 vCPU, 30 GB memory | `n1-standard-8` | | Praefect | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | -| Praefect PostgreSQL(1) | 1+ | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | -| Object storage(4) | n/a | n/a | n/a | +| Praefect PostgreSQL<sup>1</sup> | 1+ | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | +| Object storage<sup>4</sup> | n/a | n/a | n/a | <!-- Disable ordered list rule https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md029---ordered-list-item-prefix --> <!-- 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. 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. -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. <!-- markdownlint-enable MD029 --> NOTE: @@ -2150,9 +2150,9 @@ card "Kubernetes via Helm Charts" as kubernetes { card "**Internal Load Balancer**" as ilb #9370DB -node "**Consul + Sentinel** x3" as consul_sentinel { - component Consul as consul #e76a9b - component Sentinel as sentinel #e6e727 +card "**Consul + Sentinel**" as consul_sentinel { + collections "**Consul** x3" as consul #e76a9b + collections "**Redis Sentinel** x3" as sentinel #e6e727 } card "Gitaly Cluster" as gitaly_cluster { @@ -2221,11 +2221,11 @@ documents how to apply the calculated configuration to the Helm Chart. #### Webservice Webservice pods typically need about 1 vCPU and 1.25 GB of memory _per worker_. -Each Webservice pod will consume roughly 4 vCPUs and 5 GB of memory using +Each Webservice pod consumes roughly 4 vCPUs and 5 GB of memory using the [recommended topology](#cluster-topology) because four worker processes are created by default and each pod has other small processes running. -For 5k users we recommend a total Puma worker count of around 40. +For 5,000 users we recommend a total Puma worker count of around 40. With the [provided recommendations](#cluster-topology) this allows the deployment of up to 10 Webservice pods with 4 workers per pod and 2 pods per node. Expand available resources using the ratio of 1 vCPU to 1.25 GB of memory _per each worker process_ for each additional diff --git a/doc/administration/reference_architectures/index.md b/doc/administration/reference_architectures/index.md index 22871f6ea8d..2965b1202db 100644 --- a/doc/administration/reference_architectures/index.md +++ b/doc/administration/reference_architectures/index.md @@ -71,6 +71,7 @@ The following reference architectures are available: The following Cloud Native Hybrid reference architectures, where select recommended components can be run in Kubernetes, are available: +- [Up to 3,000 users](3k_users.md#cloud-native-hybrid-reference-architecture-with-helm-charts-alternative) - [Up to 5,000 users](5k_users.md#cloud-native-hybrid-reference-architecture-with-helm-charts-alternative) - [Up to 10,000 users](10k_users.md#cloud-native-hybrid-reference-architecture-with-helm-charts-alternative) - [Up to 25,000 users](25k_users.md#cloud-native-hybrid-reference-architecture-with-helm-charts-alternative) diff --git a/doc/development/usage_ping/dictionary.md b/doc/development/usage_ping/dictionary.md index 934bdf9c808..286a216c6da 100644 --- a/doc/development/usage_ping/dictionary.md +++ b/doc/development/usage_ping/dictionary.md @@ -3836,7 +3836,7 @@ Count of License Scanning jobs run Group: `group::composition analysis` -Data Category: `Subscription` +Data Category: `Operational` Status: `data_available` diff --git a/lib/gitlab/ci/features.rb b/lib/gitlab/ci/features.rb index d26a903c1f8..51051b0490f 100644 --- a/lib/gitlab/ci/features.rb +++ b/lib/gitlab/ci/features.rb @@ -3,7 +3,7 @@ module Gitlab module Ci ## - # Ci::Features is a class that aggregates all CI/CD feature flags in one place. + # Deprecated: Ci::Features is a class that aggregates all CI/CD feature flags in one place. # module Features # NOTE: The feature flag `disallow_to_create_merge_request_pipelines_in_target_project` diff --git a/lib/gitlab/database.rb b/lib/gitlab/database.rb index a269b8d0366..75738a62305 100644 --- a/lib/gitlab/database.rb +++ b/lib/gitlab/database.rb @@ -352,11 +352,11 @@ module Gitlab end end - def self.dbname(ar_connection) + def self.db_config_name(ar_connection) if ar_connection.respond_to?(:pool) && ar_connection.pool.respond_to?(:db_config) && - ar_connection.pool.db_config.respond_to?(:database) - return ar_connection.pool.db_config.database + ar_connection.pool.db_config.respond_to?(:name) + return ar_connection.pool.db_config.name end 'unknown' diff --git a/lib/gitlab/metrics/subscribers/active_record.rb b/lib/gitlab/metrics/subscribers/active_record.rb index a8fcad9ff9f..4a46b7626bd 100644 --- a/lib/gitlab/metrics/subscribers/active_record.rb +++ b/lib/gitlab/metrics/subscribers/active_record.rb @@ -74,9 +74,9 @@ module Gitlab end if Feature.enabled?(:multiple_database_metrics, default_enabled: :yaml) - ::Gitlab::SafeRequestStore[:duration_by_database]&.each do |dbname, duration_by_role| + ::Gitlab::SafeRequestStore[:duration_by_database]&.each do |name, duration_by_role| duration_by_role.each do |db_role, duration| - payload[:"db_#{db_role}_#{dbname}_duration_s"] = duration.to_f.round(3) + payload[:"db_#{db_role}_#{name}_duration_s"] = duration.to_f.round(3) end end end @@ -113,11 +113,11 @@ module Gitlab ::Gitlab::SafeRequestStore[duration_key] = (::Gitlab::SafeRequestStore[duration_key].presence || 0) + duration # Per database metrics - dbname = ::Gitlab::Database.dbname(event.payload[:connection]) + name = ::Gitlab::Database.db_config_name(event.payload[:connection]) ::Gitlab::SafeRequestStore[:duration_by_database] ||= {} - ::Gitlab::SafeRequestStore[:duration_by_database][dbname] ||= {} - ::Gitlab::SafeRequestStore[:duration_by_database][dbname][db_role] ||= 0 - ::Gitlab::SafeRequestStore[:duration_by_database][dbname][db_role] += duration + ::Gitlab::SafeRequestStore[:duration_by_database][name] ||= {} + ::Gitlab::SafeRequestStore[:duration_by_database][name][db_role] ||= 0 + ::Gitlab::SafeRequestStore[:duration_by_database][name][db_role] += duration end def ignored_query?(payload) diff --git a/lib/gitlab/middleware/multipart.rb b/lib/gitlab/middleware/multipart.rb index 329041e3ba2..30b3fe3d893 100644 --- a/lib/gitlab/middleware/multipart.rb +++ b/lib/gitlab/middleware/multipart.rb @@ -177,7 +177,7 @@ module Gitlab @app.call(env) end rescue UploadedFile::InvalidPathError => e - [400, { 'Content-Type' => 'text/plain' }, e.message] + [400, { 'Content-Type' => 'text/plain' }, [e.message]] end end end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 79d63d21237..e70f1465b97 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -1405,6 +1405,9 @@ msgstr "" msgid "A Let's Encrypt account will be configured for this GitLab installation using your email address. You will receive emails to warn of expiring certificates." msgstr "" +msgid "A Metrics Dashboard menu item appears in the Monitoring section of the Admin Area." +msgstr "" + msgid "A basic page and serverless function that uses AWS Lambda, AWS API Gateway, and GitLab Pages" msgstr "" @@ -1897,9 +1900,6 @@ msgstr "" msgid "Add a GPG key" msgstr "" -msgid "Add a Grafana button in the admin sidebar, monitoring section, to access a variety of statistics on the health and performance of GitLab." -msgstr "" - msgid "Add a Jaeger URL to replace this page with a link to your Jaeger server. You first need to %{link_start_tag}install Jaeger%{link_end_tag}." msgstr "" @@ -1936,6 +1936,9 @@ msgstr "" msgid "Add a link" msgstr "" +msgid "Add a link to Grafana" +msgstr "" + msgid "Add a new issue" msgstr "" @@ -12085,18 +12088,12 @@ msgstr "" msgid "Enable a Prometheus metrics endpoint at %{metrics_path} to expose a variety of statistics on the health and performance of GitLab. Additional information on authenticating and connecting to the metrics endpoint is available %{link}." msgstr "" -msgid "Enable access to Grafana" -msgstr "" - msgid "Enable access to the Performance Bar" msgstr "" msgid "Enable access to the Performance Bar for a given group." msgstr "" -msgid "Enable and configure Grafana." -msgstr "" - msgid "Enable and configure Prometheus metrics." msgstr "" @@ -19637,6 +19634,9 @@ msgstr "" msgid "Link to go to GitLab pipeline documentation" msgstr "" +msgid "Link to your Grafana instance." +msgstr "" + msgid "Linked emails (%{email_count})" msgstr "" @@ -22360,9 +22360,6 @@ msgstr "" msgid "Not confidential" msgstr "" -msgid "Not enough data" -msgstr "" - msgid "Not found." msgstr "" @@ -34794,6 +34791,9 @@ msgstr "" msgid "URL must start with %{codeStart}http://%{codeEnd}, %{codeStart}https://%{codeEnd}, or %{codeStart}ftp://%{codeEnd}" msgstr "" +msgid "URL of the Grafana instance to link to from the Metrics Dashboard menu item." +msgstr "" + msgid "URL of the external Spam Check endpoint" msgstr "" diff --git a/spec/frontend/blob/viewer/index_spec.js b/spec/frontend/blob/viewer/index_spec.js index 6a24b76abc8..705c4630a68 100644 --- a/spec/frontend/blob/viewer/index_spec.js +++ b/spec/frontend/blob/viewer/index_spec.js @@ -3,7 +3,7 @@ import MockAdapter from 'axios-mock-adapter'; import $ from 'jquery'; import { setTestTimeout } from 'helpers/timeout'; -import BlobViewer from '~/blob/viewer/index'; +import { BlobViewer } from '~/blob/viewer/index'; import axios from '~/lib/utils/axios_utils'; const execImmediately = (callback) => { diff --git a/spec/frontend/cycle_analytics/stage_nav_item_spec.js b/spec/frontend/cycle_analytics/stage_nav_item_spec.js deleted file mode 100644 index d577d0b602a..00000000000 --- a/spec/frontend/cycle_analytics/stage_nav_item_spec.js +++ /dev/null @@ -1,152 +0,0 @@ -import { mount, shallowMount } from '@vue/test-utils'; -import StageNavItem from '~/cycle_analytics/components/stage_nav_item.vue'; - -describe('StageNavItem', () => { - let wrapper = null; - const title = 'Cool stage'; - const value = '1 day'; - - function createComponent(props, shallow = true) { - const func = shallow ? shallowMount : mount; - return func(StageNavItem, { - propsData: { - isActive: false, - isUserAllowed: false, - isDefaultStage: true, - title, - value, - ...props, - }, - }); - } - - function hasStageName() { - const stageName = wrapper.find('.stage-name'); - expect(stageName.exists()).toBe(true); - expect(stageName.text()).toEqual(title); - } - - it('renders stage name', () => { - wrapper = createComponent({ isUserAllowed: true }); - hasStageName(); - wrapper.destroy(); - }); - - describe('User has access', () => { - describe('with a value', () => { - beforeEach(() => { - wrapper = createComponent({ isUserAllowed: true }); - }); - - afterEach(() => { - wrapper.destroy(); - }); - it('renders the value for median value', () => { - expect(wrapper.find('.stage-empty').exists()).toBe(false); - expect(wrapper.find('.not-available').exists()).toBe(false); - expect(wrapper.find('.stage-median').text()).toEqual(value); - }); - }); - - describe('without a value', () => { - beforeEach(() => { - wrapper = createComponent({ isUserAllowed: true, value: null }); - }); - - afterEach(() => { - wrapper.destroy(); - }); - - it('has the stage-empty class', () => { - expect(wrapper.find('.stage-empty').exists()).toBe(true); - }); - - it('renders Not enough data for the median value', () => { - expect(wrapper.find('.stage-median').text()).toEqual('Not enough data'); - }); - }); - }); - - describe('is active', () => { - beforeEach(() => { - wrapper = createComponent({ isActive: true }, false); - }); - - afterEach(() => { - wrapper.destroy(); - }); - it('has the active class', () => { - expect(wrapper.find('.stage-nav-item').classes('active')).toBe(true); - }); - }); - - describe('is not active', () => { - beforeEach(() => { - wrapper = createComponent(); - }); - - afterEach(() => { - wrapper.destroy(); - }); - it('emits the `select` event when clicked', () => { - expect(wrapper.emitted().select).toBeUndefined(); - wrapper.trigger('click'); - return wrapper.vm.$nextTick(() => { - expect(wrapper.emitted().select.length).toBe(1); - }); - }); - }); - - describe('User does not have access', () => { - beforeEach(() => { - wrapper = createComponent({ isUserAllowed: false }, false); - }); - - afterEach(() => { - wrapper.destroy(); - }); - it('renders stage name', () => { - hasStageName(); - }); - - it('has class not-available', () => { - expect(wrapper.find('.stage-empty').exists()).toBe(false); - expect(wrapper.find('.not-available').exists()).toBe(true); - }); - - it('renders Not available for the median value', () => { - expect(wrapper.find('.stage-median').text()).toBe('Not available'); - }); - it('does not render options menu', () => { - expect(wrapper.find('[data-testid="more-actions-toggle"]').exists()).toBe(false); - }); - }); - - describe('User can edit stages', () => { - beforeEach(() => { - wrapper = createComponent({ isUserAllowed: true }, false); - }); - - afterEach(() => { - wrapper.destroy(); - }); - it('renders stage name', () => { - hasStageName(); - }); - - it('does not render options menu', () => { - expect(wrapper.find('[data-testid="more-actions-toggle"]').exists()).toBe(false); - }); - - it('can not edit the stage', () => { - expect(wrapper.text()).not.toContain('Edit stage'); - }); - it('can not remove the stage', () => { - expect(wrapper.text()).not.toContain('Remove stage'); - }); - - it('can not hide the stage', () => { - expect(wrapper.text()).not.toContain('Hide stage'); - }); - }); -}); diff --git a/spec/frontend/cycle_analytics/utils_spec.js b/spec/frontend/cycle_analytics/utils_spec.js index 1fecdfc0539..b8bc2bf512a 100644 --- a/spec/frontend/cycle_analytics/utils_spec.js +++ b/spec/frontend/cycle_analytics/utils_spec.js @@ -1,6 +1,5 @@ import { useFakeDate } from 'helpers/fake_date'; import { - decorateEvents, decorateData, transformStagesForPathNavigation, timeSummaryForPathNavigation, @@ -13,7 +12,6 @@ import { selectedStage, rawData, convertedData, - rawEvents, allowedStages, stageMedians, pathNavIssueMetric, @@ -21,34 +19,6 @@ import { } from './mock_data'; describe('Value stream analytics utils', () => { - describe('decorateEvents', () => { - const [result] = decorateEvents(rawEvents, selectedStage); - const eventKeys = Object.keys(result); - const authorKeys = Object.keys(result.author); - it('will return the same number of events', () => { - expect(decorateEvents(rawEvents, selectedStage).length).toBe(rawEvents.length); - }); - - it('will set all the required event fields', () => { - ['totalTime', 'author', 'createdAt', 'shortSha', 'commitUrl'].forEach((key) => { - expect(eventKeys).toContain(key); - }); - ['webUrl', 'avatarUrl'].forEach((key) => { - expect(authorKeys).toContain(key); - }); - }); - - it('will remove unused fields', () => { - ['total_time', 'created_at', 'short_sha', 'commit_url'].forEach((key) => { - expect(eventKeys).not.toContain(key); - }); - - ['web_url', 'avatar_url'].forEach((key) => { - expect(authorKeys).not.toContain(key); - }); - }); - }); - describe('decorateData', () => { const result = decorateData(rawData); it('returns the summary data', () => { diff --git a/spec/graphql/types/global_id_type_spec.rb b/spec/graphql/types/global_id_type_spec.rb index cdf09dd9cc9..4efa3018dad 100644 --- a/spec/graphql/types/global_id_type_spec.rb +++ b/spec/graphql/types/global_id_type_spec.rb @@ -255,7 +255,7 @@ RSpec.describe Types::GlobalIDType do query(GraphQL.parse(gql_query), vars).result end - all_types = [::GraphQL::ID_TYPE, ::Types::GlobalIDType, ::Types::GlobalIDType[::Project]] + all_types = [::GraphQL::Types::ID, ::Types::GlobalIDType, ::Types::GlobalIDType[::Project]] shared_examples 'a working query' do # Simplified schema to test compatibility @@ -284,7 +284,7 @@ RSpec.describe Types::GlobalIDType do # This is needed so that all types are always registered as input types field :echo, String, null: true do - argument :id, ::GraphQL::ID_TYPE, required: false + argument :id, ::GraphQL::Types::ID, required: false argument :gid, ::Types::GlobalIDType, required: false argument :pid, ::Types::GlobalIDType[::Project], required: false end diff --git a/spec/graphql/types/permission_types/base_permission_type_spec.rb b/spec/graphql/types/permission_types/base_permission_type_spec.rb index 68632a509ee..e4726ad0e6e 100644 --- a/spec/graphql/types/permission_types/base_permission_type_spec.rb +++ b/spec/graphql/types/permission_types/base_permission_type_spec.rb @@ -36,7 +36,7 @@ RSpec.describe Types::PermissionTypes::BasePermissionType do expected_keywords = { name: :resolve_using_hash, hash_key: :the_key, - type: GraphQL::BOOLEAN_TYPE, + type: GraphQL::Types::Boolean, description: "custom description", null: false } diff --git a/spec/lib/gitlab/database_spec.rb b/spec/lib/gitlab/database_spec.rb index a834e41c019..674976daf28 100644 --- a/spec/lib/gitlab/database_spec.rb +++ b/spec/lib/gitlab/database_spec.rb @@ -487,19 +487,19 @@ RSpec.describe Gitlab::Database do end end - describe '.dbname' do - it 'returns the dbname for the connection' do + describe '.db_config_name' do + it 'returns the db_config name for the connection' do connection = ActiveRecord::Base.connection - expect(described_class.dbname(connection)).to be_a(String) - expect(described_class.dbname(connection)).to eq(connection.pool.db_config.database) + expect(described_class.db_config_name(connection)).to be_a(String) + expect(described_class.db_config_name(connection)).to eq(connection.pool.db_config.name) end context 'when the pool is a NullPool' do it 'returns unknown' do connection = double(:active_record_connection, pool: ActiveRecord::ConnectionAdapters::NullPool.new) - expect(described_class.dbname(connection)).to eq('unknown') + expect(described_class.db_config_name(connection)).to eq('unknown') end end end diff --git a/spec/lib/gitlab/middleware/multipart_spec.rb b/spec/lib/gitlab/middleware/multipart_spec.rb index 65ec3535271..294a5ee82ed 100644 --- a/spec/lib/gitlab/middleware/multipart_spec.rb +++ b/spec/lib/gitlab/middleware/multipart_spec.rb @@ -77,7 +77,8 @@ RSpec.describe Gitlab::Middleware::Multipart do result = subject expect(result[0]).to eq(400) - expect(result[2]).to include('insecure path used') + expect(result[2]).to be_a(Array) + expect(result[2].first).to include('insecure path used') end end end diff --git a/spec/lib/gitlab/object_hierarchy_spec.rb b/spec/lib/gitlab/object_hierarchy_spec.rb index 64161fbafdd..86d09f4601c 100644 --- a/spec/lib/gitlab/object_hierarchy_spec.rb +++ b/spec/lib/gitlab/object_hierarchy_spec.rb @@ -23,7 +23,7 @@ RSpec.describe Gitlab::ObjectHierarchy do end it 'can find ancestors upto a certain level' do - relation = described_class.new(Group.where(id: child2), options: options).base_and_ancestors(upto: child1) + relation = described_class.new(Group.where(id: child2), options: options).base_and_ancestors(upto: child1.id) expect(relation).to contain_exactly(child2) end @@ -143,7 +143,7 @@ RSpec.describe Gitlab::ObjectHierarchy do end it 'can find ancestors upto a certain level' do - relation = described_class.new(Group.where(id: child2), options: options).ancestors(upto: child1) + relation = described_class.new(Group.where(id: child2), options: options).ancestors(upto: child1.id) expect(relation).to be_empty end diff --git a/spec/lib/gitlab/sidekiq_logging/structured_logger_spec.rb b/spec/lib/gitlab/sidekiq_logging/structured_logger_spec.rb index 4406b34e638..73a5f64186e 100644 --- a/spec/lib/gitlab/sidekiq_logging/structured_logger_spec.rb +++ b/spec/lib/gitlab/sidekiq_logging/structured_logger_spec.rb @@ -298,7 +298,7 @@ RSpec.describe Gitlab::SidekiqLogging::StructuredLogger do allow(Gitlab::Database::LoadBalancing).to receive(:enable?).and_return(true) end - let(:dbname) { ::Gitlab::Database.dbname(ActiveRecord::Base.connection) } + let(:db_config_name) { ::Gitlab::Database.db_config_name(ActiveRecord::Base.connection) } let(:expected_end_payload_with_db) do expected_end_payload.merge( @@ -314,7 +314,7 @@ RSpec.describe Gitlab::SidekiqLogging::StructuredLogger do 'db_primary_cached_count' => 0, 'db_primary_wal_count' => 0, 'db_primary_duration_s' => a_value > 0, - "db_primary_#{dbname}_duration_s" => a_value > 0, + "db_primary_#{db_config_name}_duration_s" => a_value > 0, 'db_primary_wal_cached_count' => 0, 'db_replica_wal_cached_count' => 0 ) diff --git a/spec/support/shared_examples/metrics/active_record_subscriber_shared_examples.rb b/spec/support/shared_examples/metrics/active_record_subscriber_shared_examples.rb index a84658780b9..8b21ae1101e 100644 --- a/spec/support/shared_examples/metrics/active_record_subscriber_shared_examples.rb +++ b/spec/support/shared_examples/metrics/active_record_subscriber_shared_examples.rb @@ -23,7 +23,7 @@ RSpec.shared_examples 'store ActiveRecord info in RequestStore' do |db_role| db_replica_wal_cached_count: 0, db_replica_wal_count: 0 } - expected[:"db_primary_#{::Gitlab::Database.dbname(connection)}_duration_s"] = 0.002 if record_query + expected[:"db_primary_#{::Gitlab::Database.db_config_name(connection)}_duration_s"] = 0.002 if record_query elsif db_role == :replica expected = { db_count: record_query ? 1 : 0, @@ -40,7 +40,7 @@ RSpec.shared_examples 'store ActiveRecord info in RequestStore' do |db_role| db_primary_wal_cached_count: 0, db_primary_wal_count: 0 } - expected[:"db_replica_#{::Gitlab::Database.dbname(connection)}_duration_s"] = 0.002 if record_query + expected[:"db_replica_#{::Gitlab::Database.db_config_name(connection)}_duration_s"] = 0.002 if record_query else expected = { db_count: record_query ? 1 : 0, @@ -64,7 +64,7 @@ RSpec.shared_examples 'store ActiveRecord info in RequestStore' do |db_role| subscriber.sql(event) connection = event.payload[:connection] - expect(described_class.db_counter_payload).not_to include(:"db_replica_#{::Gitlab::Database.dbname(connection)}_duration_s") + expect(described_class.db_counter_payload).not_to include(:"db_replica_#{::Gitlab::Database.db_config_name(connection)}_duration_s") end end end diff --git a/tooling/lib/tooling/kubernetes_client.rb b/tooling/lib/tooling/kubernetes_client.rb index 12c4ee0039f..1d7b924e2c3 100644 --- a/tooling/lib/tooling/kubernetes_client.rb +++ b/tooling/lib/tooling/kubernetes_client.rb @@ -142,10 +142,13 @@ module Tooling def resources_created_before_date(response, date) items = JSON.parse(response)['items'] # rubocop:disable Gitlab/Json - items.filter_map do |item| + items.each_with_object([]) do |item, result| item_created_at = Time.parse(item.dig('metadata', 'creationTimestamp')) - item.dig('metadata', 'name') if item_created_at < date + if item_created_at < date + resource_name = item.dig('metadata', 'name') + result << resource_name + end end rescue ::JSON::ParserError => ex puts "Ignoring this JSON parsing error: #{ex}\n\nResponse was:\n#{response}" # rubocop:disable Rails/Output |