diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-12-01 12:09:35 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-12-01 12:09:35 +0000 |
commit | 4ee706fcd1ffcb2926fd9258e9f296c260a3d06c (patch) | |
tree | 47ef82efe01cd18bc0da6eb0922273aed9e060ea | |
parent | 5a9468a4e504d06fd8f5a558f953f4af6355f702 (diff) | |
download | gitlab-ce-4ee706fcd1ffcb2926fd9258e9f296c260a3d06c.tar.gz |
Add latest changes from gitlab-org/gitlab@master
81 files changed, 961 insertions, 788 deletions
diff --git a/.rubocop.yml b/.rubocop.yml index 2367cef34b8..8113b7d6a7b 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -450,22 +450,6 @@ Cop/ActiveModelErrorsDirectManipulation: Gitlab/AvoidFeatureGet: Enabled: true -RSpec/TimecopFreeze: - Enabled: true - AutoCorrect: true - Include: - - 'spec/**/*.rb' - - 'ee/spec/**/*.rb' - - 'qa/spec/**/*.rb' - -RSpec/TimecopTravel: - Enabled: true - AutoCorrect: true - Include: - - 'spec/**/*.rb' - - 'ee/spec/**/*.rb' - - 'qa/spec/**/*.rb' - RSpec/WebMockEnable: Enabled: true Include: diff --git a/.rubocop_todo/rails/http_status.yml b/.rubocop_todo/rails/http_status.yml deleted file mode 100644 index b1f64f7aa18..00000000000 --- a/.rubocop_todo/rails/http_status.yml +++ /dev/null @@ -1,9 +0,0 @@ ---- -# Cop supports --autocorrect. -Rails/HttpStatus: - Exclude: - - 'app/controllers/concerns/invisible_captcha_on_signup.rb' - - 'app/controllers/projects/runner_projects_controller.rb' - - 'app/controllers/projects/service_ping_controller.rb' - - 'app/controllers/repositories/lfs_storage_controller.rb' - - 'ee/app/controllers/trials_controller.rb' diff --git a/app/assets/javascripts/gitlab_pages/components/pages_pipeline_wizard.vue b/app/assets/javascripts/gitlab_pages/components/pages_pipeline_wizard.vue index f17a05999b0..bf71f682048 100644 --- a/app/assets/javascripts/gitlab_pages/components/pages_pipeline_wizard.vue +++ b/app/assets/javascripts/gitlab_pages/components/pages_pipeline_wizard.vue @@ -2,7 +2,7 @@ import { GlLoadingIcon } from '@gitlab/ui'; import { captureException } from '@sentry/browser'; import PipelineWizard from '~/pipeline_wizard/pipeline_wizard.vue'; -import PagesWizardTemplate from '~/pipeline_wizard/templates/pages.yml'; +import PagesWizardTemplate from '~/pipeline_wizard/templates/pages.yml?raw'; import { logError } from '~/lib/logger'; import { s__ } from '~/locale'; import { redirectTo } from '~/lib/utils/url_utility'; diff --git a/app/assets/javascripts/groups/components/group_item.vue b/app/assets/javascripts/groups/components/group_item.vue index 3874d06da91..d9781ef9c84 100644 --- a/app/assets/javascripts/groups/components/group_item.vue +++ b/app/assets/javascripts/groups/components/group_item.vue @@ -200,11 +200,9 @@ export default { class="no-expand gl-mr-3 gl-text-gray-900!" :itemprop="microdata.nameItemprop" > - {{ - // ending bracket must be by closing tag to prevent - // link hover text-decoration from over-extending - group.name - }} + <!-- ending bracket must be by closing tag to prevent --> + <!-- link hover text-decoration from over-extending --> + {{ group.name }} </a> <gl-icon v-gl-tooltip.hover.bottom diff --git a/app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue b/app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue index b344c4f1891..79a9bbb84c2 100644 --- a/app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue +++ b/app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue @@ -23,6 +23,12 @@ import ProjectSettingRow from './project_setting_row.vue'; const FEATURE_ACCESS_LEVEL_ANONYMOUS = [30, s__('ProjectSettings|Everyone')]; +const PACKAGE_REGISTRY_ACCESS_LEVEL_DEFAULT_BY_PROJECT_VISIBILITY = { + [VISIBILITY_LEVEL_PRIVATE_INTEGER]: featureAccessLevel.PROJECT_MEMBERS, + [VISIBILITY_LEVEL_INTERNAL_INTEGER]: featureAccessLevel.EVERYONE, + [VISIBILITY_LEVEL_PUBLIC_INTEGER]: FEATURE_ACCESS_LEVEL_ANONYMOUS[0], +}; + export default { i18n: { ...CVE_ID_REQUEST_BUTTON_I18N, @@ -47,11 +53,15 @@ export default { packagesHelpText: s__( 'ProjectSettings|Every project can have its own space to store its packages. Note: The Package Registry is always visible when a project is public.', ), - packageRegistryHelpText: s__( - 'ProjectSettings|Every project can have its own space to store its packages.', + packageRegistryHelpText: s__('ProjectSettings|Publish, store, and view packages in a project.'), + packageRegistryForEveryoneHelpText: s__( + 'ProjectSettings|Anyone can pull packages with a package manager API.', ), packagesLabel: s__('ProjectSettings|Packages'), packageRegistryLabel: s__('ProjectSettings|Package registry'), + packageRegistryForEveryoneLabel: s__( + 'ProjectSettings|Allow anyone to pull from Package Registry', + ), pagesLabel: s__('ProjectSettings|Pages'), ciCdLabel: __('CI/CD'), repositoryLabel: s__('ProjectSettings|Repository'), @@ -287,18 +297,6 @@ export default { ); }, - packageRegistryFeatureAccessLevelOptions() { - const options = [FEATURE_ACCESS_LEVEL_ANONYMOUS]; - - if (this.visibilityLevel === VISIBILITY_LEVEL_PRIVATE_INTEGER) { - options.unshift(featureAccessLevelMembers); - } else if (this.visibilityLevel === VISIBILITY_LEVEL_INTERNAL_INTEGER) { - options.unshift(featureAccessLevelEveryone); - } - - return options; - }, - pagesFeatureAccessLevelOptions() { const options = [featureAccessLevelMembers]; @@ -366,6 +364,15 @@ export default { packageRegistryAccessLevelEnabled() { return this.glFeatures.packageRegistryAccessLevel; }, + packageRegistryEnabled() { + return this.packageRegistryAccessLevel > featureAccessLevel.NOT_ENABLED; + }, + packageRegistryApiForEveryoneEnabled() { + return this.packageRegistryAccessLevel === FEATURE_ACCESS_LEVEL_ANONYMOUS[0]; + }, + packageRegistryApiForEveryoneEnabledShown() { + return this.visibilityLevel !== VISIBILITY_LEVEL_PUBLIC_INTEGER; + }, splitOperationsEnabled() { return this.glFeatures.splitOperationsVisibilityPermissions; }, @@ -474,9 +481,8 @@ export default { this.packageRegistryAccessLevelEnabled && this.packageRegistryAccessLevel === featureAccessLevel.PROJECT_MEMBERS ) { - this.packageRegistryAccessLevel = Math.min( - ...this.packageRegistryFeatureAccessLevelOptions.map((option) => option[0]), - ); + this.packageRegistryAccessLevel = + PACKAGE_REGISTRY_ACCESS_LEVEL_DEFAULT_BY_PROJECT_VISIBILITY[value]; } if (this.buildsAccessLevel > featureAccessLevel.NOT_ENABLED) this.buildsAccessLevel = featureAccessLevel.EVERYONE; @@ -561,6 +567,22 @@ export default { visibilityAllowed(option) { return this.allowedVisibilityOptions.includes(option); }, + onPackageRegistryEnabledToggle(value) { + this.packageRegistryAccessLevel = value + ? this.packageRegistryAccessLevelDefault() + : featureAccessLevel.NOT_ENABLED; + }, + onPackageRegistryApiForEveryoneEnabledToggle(value) { + this.packageRegistryAccessLevel = value + ? FEATURE_ACCESS_LEVEL_ANONYMOUS[0] + : this.packageRegistryAccessLevelDefault(); + }, + packageRegistryAccessLevelDefault() { + return ( + PACKAGE_REGISTRY_ACCESS_LEVEL_DEFAULT_BY_PROJECT_VISIBILITY[this.visibilityLevel] ?? + featureAccessLevel.NOT_ENABLED + ); + }, }, }; </script> @@ -897,10 +919,36 @@ export default { :help-text="$options.i18n.packageRegistryHelpText" data-testid="package-registry-access-level" > - <project-feature-setting - v-model="packageRegistryAccessLevel" + <gl-toggle + class="gl-my-2" + :value="packageRegistryEnabled" :label="$options.i18n.packageRegistryLabel" - :options="packageRegistryFeatureAccessLevelOptions" + label-position="hidden" + name="package_registry_enabled" + @change="onPackageRegistryEnabledToggle" + /> + <div + v-if="packageRegistryApiForEveryoneEnabledShown" + class="project-feature-setting-group gl-pl-7 gl-sm-pl-5 gl-my-3" + > + <project-setting-row + :label="$options.i18n.packageRegistryForEveryoneLabel" + :help-text="$options.i18n.packageRegistryForEveryoneHelpText" + > + <gl-toggle + class="gl-my-2" + :value="packageRegistryApiForEveryoneEnabled" + :disabled="!packageRegistryEnabled" + :label="$options.i18n.packageRegistryForEveryoneLabel" + label-position="hidden" + name="package_registry_api_for_everyone_enabled" + @change="onPackageRegistryApiForEveryoneEnabledToggle" + /> + </project-setting-row> + </div> + <input + :value="packageRegistryAccessLevel" + type="hidden" name="project[project_feature_attributes][package_registry_access_level]" /> </project-setting-row> @@ -927,7 +975,7 @@ export default { ref="monitor-settings" :label="$options.i18n.monitorLabel" :help-text=" - s__('ProjectSettings|Configure your project resources and monitor their health.') + s__('ProjectSettings|Monitor the health of your project and respond to incidents.') " > <project-feature-setting diff --git a/app/assets/javascripts/pipelines/components/graph/job_item.vue b/app/assets/javascripts/pipelines/components/graph/job_item.vue index 377f21b299f..4f2be27486c 100644 --- a/app/assets/javascripts/pipelines/components/graph/job_item.vue +++ b/app/assets/javascripts/pipelines/components/graph/job_item.vue @@ -252,7 +252,7 @@ export default { @click="jobItemClick" @mouseout="hideTooltips" > - <div class="ci-job-name-component gl-display-flex gl-align-items-center"> + <div class="gl-display-flex gl-align-items-center gl-flex-grow-1"> <ci-icon :size="24" :status="job.status" class="gl-line-height-0" /> <div class="gl-pl-3 gl-pr-3 gl-display-flex gl-flex-direction-column gl-pipeline-job-width"> <div class="gl-text-truncate gl-pr-9 gl-line-height-normal">{{ job.name }}</div> diff --git a/app/assets/javascripts/pipelines/components/jobs_shared/job_name_component.vue b/app/assets/javascripts/pipelines/components/jobs_shared/job_name_component.vue index f4fc6893520..1c7f5a7476d 100644 --- a/app/assets/javascripts/pipelines/components/jobs_shared/job_name_component.vue +++ b/app/assets/javascripts/pipelines/components/jobs_shared/job_name_component.vue @@ -29,7 +29,7 @@ export default { }; </script> <template> - <span class="ci-job-name-component mw-100 gl-display-flex gl-align-items-center"> + <span class="mw-100 gl-display-flex gl-align-items-center gl-flex-grow-1"> <ci-icon :size="iconSize" :status="status" class="gl-line-height-0" /> <span class="gl-text-truncate mw-70p gl-pl-3 gl-display-inline-block"> {{ name }} diff --git a/app/assets/javascripts/pipelines/components/pipeline_mini_graph/job_item.vue b/app/assets/javascripts/pipelines/components/pipeline_mini_graph/job_item.vue index 211c5f117c7..efa2b3a4fff 100644 --- a/app/assets/javascripts/pipelines/components/pipeline_mini_graph/job_item.vue +++ b/app/assets/javascripts/pipelines/components/pipeline_mini_graph/job_item.vue @@ -163,7 +163,7 @@ export default { @click.stop="hideTooltips" @mouseout="hideTooltips" > - <job-name-component :name="job.name" :status="job.status" :icon-size="24" /> + <job-name-component :name="job.name" :status="job.status" /> </gl-link> <div @@ -175,7 +175,7 @@ export default { data-testid="job-without-link" @mouseout="hideTooltips" > - <job-name-component :name="job.name" :status="job.status" :icon-size="24" /> + <job-name-component :name="job.name" :status="job.status" /> </div> <action-component diff --git a/app/assets/javascripts/pipelines/components/pipeline_mini_graph/pipeline_stage.vue b/app/assets/javascripts/pipelines/components/pipeline_mini_graph/pipeline_stage.vue index ba150919e58..98f558c7df5 100644 --- a/app/assets/javascripts/pipelines/components/pipeline_mini_graph/pipeline_stage.vue +++ b/app/assets/javascripts/pipelines/components/pipeline_mini_graph/pipeline_stage.vue @@ -149,7 +149,7 @@ export default { class="js-builds-dropdown-list scrollable-menu" data-testid="mini-pipeline-graph-dropdown-menu-list" > - <div class="gl--flex-center gl-border-b gl-font-weight-bold gl-pb-3"> + <div class="gl--flex-center gl-border-b gl-font-weight-bold gl-mb-3 gl-pb-3"> <span class="gl-mr-1">{{ $options.i18n.stage }}</span> <span data-testid="pipeline-stage-dropdown-menu-title">{{ stageName }}</span> </div> diff --git a/app/assets/javascripts/search/topbar/components/app.vue b/app/assets/javascripts/search/topbar/components/app.vue index d0fcbb0d83b..22ebf998620 100644 --- a/app/assets/javascripts/search/topbar/components/app.vue +++ b/app/assets/javascripts/search/topbar/components/app.vue @@ -20,12 +20,12 @@ export default { }, mixins: [glFeatureFlagsMixin()], props: { - groupInitialData: { + groupInitialJson: { type: Object, required: false, default: () => ({}), }, - projectInitialData: { + projectInitialJson: { type: Object, required: false, default: () => ({}), @@ -72,11 +72,11 @@ export default { </div> <div v-if="showFilters" class="gl-mb-4 gl-lg-mb-0 gl-lg-mx-2"> <label class="gl-display-block">{{ __('Group') }}</label> - <group-filter :initial-data="groupInitialData" /> + <group-filter :initial-data="groupInitialJson" /> </div> <div v-if="showFilters" class="gl-mb-4 gl-lg-mb-0 gl-lg-mx-2"> <label class="gl-display-block">{{ __('Project') }}</label> - <project-filter :initial-data="projectInitialData" /> + <project-filter :initial-data="projectInitialJson" /> </div> </div> <hr v-if="hasVerticalNav" class="gl-mt-5 gl-mb-0 gl-border-gray-100" /> diff --git a/app/assets/javascripts/search/topbar/index.js b/app/assets/javascripts/search/topbar/index.js index 87316e10e8d..d6e16085c28 100644 --- a/app/assets/javascripts/search/topbar/index.js +++ b/app/assets/javascripts/search/topbar/index.js @@ -11,10 +11,18 @@ export const initTopbar = (store) => { return false; } - let { groupInitialData, projectInitialData } = el.dataset; + const { + groupInitialJson, + projectInitialJson, + elasticsearchEnabled, + defaultBranchName, + } = el.dataset; - groupInitialData = JSON.parse(groupInitialData); - projectInitialData = JSON.parse(projectInitialData); + const groupInitialJsonParsed = JSON.parse(groupInitialJson); + const projectInitialJsonParsed = JSON.parse(projectInitialJson); + const elasticsearchEnabledParsed = elasticsearchEnabled + ? JSON.parse(elasticsearchEnabled) + : false; return new Vue({ el, @@ -22,8 +30,10 @@ export const initTopbar = (store) => { render(createElement) { return createElement(GlobalSearchTopbar, { props: { - groupInitialData, - projectInitialData, + groupInitialJson: groupInitialJsonParsed, + projectInitialJson: projectInitialJsonParsed, + elasticsearchEnabled: elasticsearchEnabledParsed, + defaultBranchName, }, }); }, diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss index f817ad8f24f..97ad342997b 100644 --- a/app/assets/stylesheets/framework/variables.scss +++ b/app/assets/stylesheets/framework/variables.scss @@ -822,7 +822,6 @@ Pipeline Graph $ci-action-icon-size: 22px; $ci-action-icon-size-lg: 24px; $pipeline-dropdown-line-height: 20px; -$pipeline-dropdown-status-icon-size: 18px; $ci-action-dropdown-button-size: 24px; $ci-action-dropdown-svg-size: 12px; diff --git a/app/assets/stylesheets/page_bundles/_pipeline_mixins.scss b/app/assets/stylesheets/page_bundles/_pipeline_mixins.scss index 613d27a2f39..ed15e352b7d 100644 --- a/app/assets/stylesheets/page_bundles/_pipeline_mixins.scss +++ b/app/assets/stylesheets/page_bundles/_pipeline_mixins.scss @@ -33,8 +33,8 @@ .ci-action-icon-container { position: absolute; - right: 8px; - top: 8px; + right: 11px; + top: 7px; &.ci-action-icon-wrapper { height: $ci-action-dropdown-button-size; @@ -84,25 +84,6 @@ &.non-details-job-component { padding: $gl-padding-8 $gl-btn-horz-padding; } - - .ci-job-name-component { - align-items: center; - display: flex; - flex: 1; - } - - .ci-status-icon { - position: relative; - - > svg { - width: $pipeline-dropdown-status-icon-size; - height: $pipeline-dropdown-status-icon-size; - margin: 3px 0; - position: relative; - overflow: visible; - display: block; - } - } } // ensure .mini-pipeline-graph-dropdown-item has hover style when action-icon is hovered diff --git a/app/assets/stylesheets/startup/startup-dark.scss b/app/assets/stylesheets/startup/startup-dark.scss index fdd4df27a2e..e986fd9316e 100644 --- a/app/assets/stylesheets/startup/startup-dark.scss +++ b/app/assets/stylesheets/startup/startup-dark.scss @@ -2,25 +2,6 @@ // Please see the feedback issue for more details and help: // https://gitlab.com/gitlab-org/gitlab/-/issues/331812 @charset "UTF-8"; -:root { - color-scheme: dark; -} -body.gl-dark { - --gray-10: #1f1e24; - --gray-50: #333238; - --gray-100: #434248; - --gray-200: #535158; - --gray-700: #bfbfc3; - --gray-900: #ececef; - --green-100: #0d532a; - --green-700: #91d4a8; - --gl-text-color: #ececef; - --border-color: #4f4f4f; - --black: #fff; -} -:root { - --white: #333238; -} *, *::before, *::after { @@ -1705,97 +1686,18 @@ svg.s16 { } :root { color-scheme: dark; -} -body.gl-dark { --gray-10: #1f1e24; --gray-50: #333238; --gray-100: #434248; --gray-200: #535158; - --gray-300: #626168; - --gray-400: #737278; - --gray-500: #89888d; - --gray-600: #a4a3a8; --gray-700: #bfbfc3; - --gray-800: #dcdcde; --gray-900: #ececef; - --gray-950: #fbfafd; - --green-50: #0a4020; --green-100: #0d532a; - --green-200: #24663b; - --green-300: #217645; - --green-400: #108548; - --green-500: #2da160; - --green-600: #52b87a; --green-700: #91d4a8; - --green-800: #c3e6cd; - --green-900: #ecf4ee; - --green-950: #f1fdf6; - --blue-50: #033464; - --blue-100: #064787; - --blue-200: #0b5cad; - --blue-300: #1068bf; - --blue-400: #1f75cb; - --blue-500: #428fdc; - --blue-600: #63a6e9; - --blue-700: #9dc7f1; - --blue-800: #cbe2f9; - --blue-900: #e9f3fc; - --blue-950: #f2f9ff; - --orange-50: #5c2900; - --orange-100: #703800; - --orange-200: #8f4700; - --orange-300: #9e5400; - --orange-400: #ab6100; - --orange-500: #c17d10; - --orange-600: #d99530; - --orange-700: #e9be74; - --orange-800: #f5d9a8; - --orange-900: #fdf1dd; - --orange-950: #fff4e1; - --red-50: #660e00; - --red-100: #8d1300; - --red-200: #ae1800; - --red-300: #c91c00; - --red-400: #dd2b0e; - --red-500: #ec5941; - --red-600: #f57f6c; - --red-700: #fcb5aa; - --red-800: #fdd4cd; - --red-900: #fcf1ef; - --red-950: #fff4f3; - --indigo-50: #1a1a40; - --indigo-100: #292961; - --indigo-200: #393982; - --indigo-300: #4b4ba3; - --indigo-400: #5b5bbd; - --indigo-500: #6666c4; - --indigo-600: #7c7ccc; - --indigo-700: #a6a6de; - --indigo-800: #d1d1f0; - --indigo-900: #ebebfa; - --indigo-950: #f7f7ff; - --purple-50: #232150; - --purple-100: #2f2a6b; - --purple-200: #453894; - --purple-300: #5943b6; - --purple-400: #694cc0; - --purple-500: #7b58cf; - --purple-600: #9475db; - --purple-700: #ac93e6; - --purple-800: #cbbbf2; - --purple-900: #e1d8f9; - --purple-950: #f4f0ff; - --dark-icon-color-purple-1: #524a68; - --dark-icon-color-purple-2: #715bae; - --dark-icon-color-purple-3: #9a79f7; - --dark-icon-color-orange-1: #665349; - --dark-icon-color-orange-2: #b37a5d; --gl-text-color: #ececef; - --border-color: #4f4f4f; + --border-color: #434248; --white: #333238; --black: #fff; - --gray-light: #333238; - --svg-status-bg: #333238; } .nav-sidebar, .toggle-sidebar-button, @@ -1947,100 +1849,6 @@ body.gl-dark .navbar-gitlab .search form .search-input { color: var(--gl-text-color); } -:root { - color-scheme: dark; -} -body.gl-dark { - --gray-10: #1f1e24; - --gray-50: #333238; - --gray-100: #434248; - --gray-200: #535158; - --gray-300: #626168; - --gray-400: #737278; - --gray-500: #89888d; - --gray-600: #a4a3a8; - --gray-700: #bfbfc3; - --gray-800: #dcdcde; - --gray-900: #ececef; - --gray-950: #fbfafd; - --green-50: #0a4020; - --green-100: #0d532a; - --green-200: #24663b; - --green-300: #217645; - --green-400: #108548; - --green-500: #2da160; - --green-600: #52b87a; - --green-700: #91d4a8; - --green-800: #c3e6cd; - --green-900: #ecf4ee; - --green-950: #f1fdf6; - --blue-50: #033464; - --blue-100: #064787; - --blue-200: #0b5cad; - --blue-300: #1068bf; - --blue-400: #1f75cb; - --blue-500: #428fdc; - --blue-600: #63a6e9; - --blue-700: #9dc7f1; - --blue-800: #cbe2f9; - --blue-900: #e9f3fc; - --blue-950: #f2f9ff; - --orange-50: #5c2900; - --orange-100: #703800; - --orange-200: #8f4700; - --orange-300: #9e5400; - --orange-400: #ab6100; - --orange-500: #c17d10; - --orange-600: #d99530; - --orange-700: #e9be74; - --orange-800: #f5d9a8; - --orange-900: #fdf1dd; - --orange-950: #fff4e1; - --red-50: #660e00; - --red-100: #8d1300; - --red-200: #ae1800; - --red-300: #c91c00; - --red-400: #dd2b0e; - --red-500: #ec5941; - --red-600: #f57f6c; - --red-700: #fcb5aa; - --red-800: #fdd4cd; - --red-900: #fcf1ef; - --red-950: #fff4f3; - --indigo-50: #1a1a40; - --indigo-100: #292961; - --indigo-200: #393982; - --indigo-300: #4b4ba3; - --indigo-400: #5b5bbd; - --indigo-500: #6666c4; - --indigo-600: #7c7ccc; - --indigo-700: #a6a6de; - --indigo-800: #d1d1f0; - --indigo-900: #ebebfa; - --indigo-950: #f7f7ff; - --purple-50: #232150; - --purple-100: #2f2a6b; - --purple-200: #453894; - --purple-300: #5943b6; - --purple-400: #694cc0; - --purple-500: #7b58cf; - --purple-600: #9475db; - --purple-700: #ac93e6; - --purple-800: #cbbbf2; - --purple-900: #e1d8f9; - --purple-950: #f4f0ff; - --dark-icon-color-purple-1: #524a68; - --dark-icon-color-purple-2: #715bae; - --dark-icon-color-purple-3: #9a79f7; - --dark-icon-color-orange-1: #665349; - --dark-icon-color-orange-2: #b37a5d; - --gl-text-color: #ececef; - --border-color: #4f4f4f; - --white: #333238; - --black: #fff; - --gray-light: #333238; - --svg-status-bg: #333238; -} .tab-width-8 { tab-size: 8; } diff --git a/app/assets/stylesheets/themes/_dark.scss b/app/assets/stylesheets/themes/_dark.scss index cdb72c79d6a..8db91fd9908 100644 --- a/app/assets/stylesheets/themes/_dark.scss +++ b/app/assets/stylesheets/themes/_dark.scss @@ -113,141 +113,6 @@ $data-viz-blue-800: #b7c6ff; $data-viz-blue-900: #d2dcff; $data-viz-blue-950: #e9ebff; -:root { - color-scheme: dark; -} - -body.gl-dark { - --gray-10: #{$gray-10}; - --gray-50: #{$gray-50}; - --gray-100: #{$gray-100}; - --gray-200: #{$gray-200}; - --gray-300: #{$gray-300}; - --gray-400: #{$gray-400}; - --gray-500: #{$gray-500}; - --gray-600: #{$gray-600}; - --gray-700: #{$gray-700}; - --gray-800: #{$gray-800}; - --gray-900: #{$gray-900}; - --gray-950: #{$gray-950}; - - --green-50: #{$green-50}; - --green-100: #{$green-100}; - --green-200: #{$green-200}; - --green-300: #{$green-300}; - --green-400: #{$green-400}; - --green-500: #{$green-500}; - --green-600: #{$green-600}; - --green-700: #{$green-700}; - --green-800: #{$green-800}; - --green-900: #{$green-900}; - --green-950: #{$green-950}; - - --blue-50: #{$blue-50}; - --blue-100: #{$blue-100}; - --blue-200: #{$blue-200}; - --blue-300: #{$blue-300}; - --blue-400: #{$blue-400}; - --blue-500: #{$blue-500}; - --blue-600: #{$blue-600}; - --blue-700: #{$blue-700}; - --blue-800: #{$blue-800}; - --blue-900: #{$blue-900}; - --blue-950: #{$blue-950}; - - --orange-50: #{$orange-50}; - --orange-100: #{$orange-100}; - --orange-200: #{$orange-200}; - --orange-300: #{$orange-300}; - --orange-400: #{$orange-400}; - --orange-500: #{$orange-500}; - --orange-600: #{$orange-600}; - --orange-700: #{$orange-700}; - --orange-800: #{$orange-800}; - --orange-900: #{$orange-900}; - --orange-950: #{$orange-950}; - - --red-50: #{$red-50}; - --red-100: #{$red-100}; - --red-200: #{$red-200}; - --red-300: #{$red-300}; - --red-400: #{$red-400}; - --red-500: #{$red-500}; - --red-600: #{$red-600}; - --red-700: #{$red-700}; - --red-800: #{$red-800}; - --red-900: #{$red-900}; - --red-950: #{$red-950}; - - --indigo-50: #{$indigo-50}; - --indigo-100: #{$indigo-100}; - --indigo-200: #{$indigo-200}; - --indigo-300: #{$indigo-300}; - --indigo-400: #{$indigo-400}; - --indigo-500: #{$indigo-500}; - --indigo-600: #{$indigo-600}; - --indigo-700: #{$indigo-700}; - --indigo-800: #{$indigo-800}; - --indigo-900: #{$indigo-900}; - --indigo-950: #{$indigo-950}; - - --purple-50: #{$purple-50}; - --purple-100: #{$purple-100}; - --purple-200: #{$purple-200}; - --purple-300: #{$purple-300}; - --purple-400: #{$purple-400}; - --purple-500: #{$purple-500}; - --purple-600: #{$purple-600}; - --purple-700: #{$purple-700}; - --purple-800: #{$purple-800}; - --purple-900: #{$purple-900}; - --purple-950: #{$purple-950}; - - --dark-icon-color-purple-1: #524a68; - --dark-icon-color-purple-2: #715bae; - --dark-icon-color-purple-3: #9a79f7; - --dark-icon-color-orange-1: #665349; - --dark-icon-color-orange-2: #b37a5d; - - --gl-text-color: #{$gray-900}; - --border-color: #{$border-color}; - - --white: #{$white}; - --black: #{$black}; - --gray-light: #{$gray-50}; - - --svg-status-bg: #{$white}; - - .gl-button.gl-button, - .gl-button.gl-button.btn-block { - &.btn-default, - &.btn-dashed, - &.btn-info, - &.btn-success, - &.btn-danger, - &.btn-confirm { - &-tertiary { - mix-blend-mode: screen; - } - } - } - - .gl-datepicker-theme { - .pika-prev, - .pika-next { - filter: invert(0.9); - } - - .is-selected > .pika-button { - color: $gray-900; - } - - :not(.is-selected) > .pika-button:hover { - background-color: $gray-200; - } - } -} - $border-white-normal: $border-color; $body-bg: $gray-10; diff --git a/app/assets/stylesheets/themes/dark_mode_overrides.scss b/app/assets/stylesheets/themes/dark_mode_overrides.scss index a0d19c3de2a..3395eb7bda2 100644 --- a/app/assets/stylesheets/themes/dark_mode_overrides.scss +++ b/app/assets/stylesheets/themes/dark_mode_overrides.scss @@ -2,6 +2,140 @@ @import 'page_bundles/mixins_and_variables_and_functions'; @import './themes/theme_helper'; +:root { + color-scheme: dark; + --gray-10: #{$gray-10}; + --gray-50: #{$gray-50}; + --gray-100: #{$gray-100}; + --gray-200: #{$gray-200}; + --gray-300: #{$gray-300}; + --gray-400: #{$gray-400}; + --gray-500: #{$gray-500}; + --gray-600: #{$gray-600}; + --gray-700: #{$gray-700}; + --gray-800: #{$gray-800}; + --gray-900: #{$gray-900}; + --gray-950: #{$gray-950}; + + --green-50: #{$green-50}; + --green-100: #{$green-100}; + --green-200: #{$green-200}; + --green-300: #{$green-300}; + --green-400: #{$green-400}; + --green-500: #{$green-500}; + --green-600: #{$green-600}; + --green-700: #{$green-700}; + --green-800: #{$green-800}; + --green-900: #{$green-900}; + --green-950: #{$green-950}; + + --blue-50: #{$blue-50}; + --blue-100: #{$blue-100}; + --blue-200: #{$blue-200}; + --blue-300: #{$blue-300}; + --blue-400: #{$blue-400}; + --blue-500: #{$blue-500}; + --blue-600: #{$blue-600}; + --blue-700: #{$blue-700}; + --blue-800: #{$blue-800}; + --blue-900: #{$blue-900}; + --blue-950: #{$blue-950}; + + --orange-50: #{$orange-50}; + --orange-100: #{$orange-100}; + --orange-200: #{$orange-200}; + --orange-300: #{$orange-300}; + --orange-400: #{$orange-400}; + --orange-500: #{$orange-500}; + --orange-600: #{$orange-600}; + --orange-700: #{$orange-700}; + --orange-800: #{$orange-800}; + --orange-900: #{$orange-900}; + --orange-950: #{$orange-950}; + + --red-50: #{$red-50}; + --red-100: #{$red-100}; + --red-200: #{$red-200}; + --red-300: #{$red-300}; + --red-400: #{$red-400}; + --red-500: #{$red-500}; + --red-600: #{$red-600}; + --red-700: #{$red-700}; + --red-800: #{$red-800}; + --red-900: #{$red-900}; + --red-950: #{$red-950}; + + --indigo-50: #{$indigo-50}; + --indigo-100: #{$indigo-100}; + --indigo-200: #{$indigo-200}; + --indigo-300: #{$indigo-300}; + --indigo-400: #{$indigo-400}; + --indigo-500: #{$indigo-500}; + --indigo-600: #{$indigo-600}; + --indigo-700: #{$indigo-700}; + --indigo-800: #{$indigo-800}; + --indigo-900: #{$indigo-900}; + --indigo-950: #{$indigo-950}; + + --purple-50: #{$purple-50}; + --purple-100: #{$purple-100}; + --purple-200: #{$purple-200}; + --purple-300: #{$purple-300}; + --purple-400: #{$purple-400}; + --purple-500: #{$purple-500}; + --purple-600: #{$purple-600}; + --purple-700: #{$purple-700}; + --purple-800: #{$purple-800}; + --purple-900: #{$purple-900}; + --purple-950: #{$purple-950}; + + --dark-icon-color-purple-1: #524a68; + --dark-icon-color-purple-2: #715bae; + --dark-icon-color-purple-3: #9a79f7; + --dark-icon-color-orange-1: #665349; + --dark-icon-color-orange-2: #b37a5d; + + --gl-text-color: #{$gray-900}; + --border-color: #{$border-color}; + + --white: #{$white}; + --black: #{$black}; + --gray-light: #{$gray-50}; + + --svg-status-bg: #{$white}; +} + +.gl-dark { + .gl-button.gl-button, + .gl-button.gl-button.btn-block { + &.btn-default, + &.btn-dashed, + &.btn-info, + &.btn-success, + &.btn-danger, + &.btn-confirm { + &-tertiary { + mix-blend-mode: screen; + } + } + } + + .gl-datepicker-theme { + .pika-prev, + .pika-next { + filter: invert(0.9); + } + + .is-selected > .pika-button { + color: $gray-900; + } + + :not(.is-selected) > .pika-button:hover { + background-color: $gray-200; + } + } +} + // Some hacks and overrides for things that don't properly support dark mode .gl-label { filter: brightness(0.9) contrast(1.1); diff --git a/app/controllers/concerns/invisible_captcha_on_signup.rb b/app/controllers/concerns/invisible_captcha_on_signup.rb index c7fd6d08744..b78869e02d0 100644 --- a/app/controllers/concerns/invisible_captcha_on_signup.rb +++ b/app/controllers/concerns/invisible_captcha_on_signup.rb @@ -13,7 +13,7 @@ module InvisibleCaptchaOnSignup invisible_captcha_honeypot_counter.increment log_request('Invisible_Captcha_Honeypot_Request') - head(200) + head(:ok) end def on_timestamp_spam_callback diff --git a/app/controllers/dashboard/snippets_controller.rb b/app/controllers/dashboard/snippets_controller.rb index 5a885349467..d72a5e44b9f 100644 --- a/app/controllers/dashboard/snippets_controller.rb +++ b/app/controllers/dashboard/snippets_controller.rb @@ -7,7 +7,7 @@ class Dashboard::SnippetsController < Dashboard::ApplicationController skip_cross_project_access_check :index - feature_category :snippets + feature_category :source_code_management def index @snippet_counts = Snippets::CountService diff --git a/app/controllers/explore/snippets_controller.rb b/app/controllers/explore/snippets_controller.rb index 617cc2e7f3d..dee94b53cc1 100644 --- a/app/controllers/explore/snippets_controller.rb +++ b/app/controllers/explore/snippets_controller.rb @@ -3,7 +3,7 @@ class Explore::SnippetsController < Explore::ApplicationController include Gitlab::NoteableMetadata - feature_category :snippets + feature_category :source_code_management def index @snippets = SnippetsFinder.new(current_user, explore: true) diff --git a/app/controllers/projects/autocomplete_sources_controller.rb b/app/controllers/projects/autocomplete_sources_controller.rb index 7755effe1da..ef20c71cd77 100644 --- a/app/controllers/projects/autocomplete_sources_controller.rb +++ b/app/controllers/projects/autocomplete_sources_controller.rb @@ -7,7 +7,7 @@ class Projects::AutocompleteSourcesController < Projects::ApplicationController feature_category :team_planning, [:issues, :labels, :milestones, :commands, :contacts] feature_category :code_review, [:merge_requests] feature_category :users, [:members] - feature_category :snippets, [:snippets] + feature_category :source_code_management, [:snippets] urgency :low, [:merge_requests, :members] urgency :low, [:issues, :labels, :milestones, :commands, :contacts] diff --git a/app/controllers/projects/runner_projects_controller.rb b/app/controllers/projects/runner_projects_controller.rb index 5946c43b134..6f896244acb 100644 --- a/app/controllers/projects/runner_projects_controller.rb +++ b/app/controllers/projects/runner_projects_controller.rb @@ -11,7 +11,7 @@ class Projects::RunnerProjectsController < Projects::ApplicationController def create @runner = Ci::Runner.find(params[:runner_project][:runner_id]) - return head(403) unless can?(current_user, :assign_runner, @runner) + return head(:forbidden) unless can?(current_user, :assign_runner, @runner) path = project_runners_path(project) diff --git a/app/controllers/projects/service_ping_controller.rb b/app/controllers/projects/service_ping_controller.rb index 43c249afd8e..cfc322b47e7 100644 --- a/app/controllers/projects/service_ping_controller.rb +++ b/app/controllers/projects/service_ping_controller.rb @@ -10,7 +10,7 @@ class Projects::ServicePingController < Projects::ApplicationController Gitlab::UsageDataCounters::WebIdeCounter.increment_previews_count - head(200) + head(:ok) end def web_ide_clientside_preview_success @@ -20,12 +20,12 @@ class Projects::ServicePingController < Projects::ApplicationController Gitlab::UsageDataCounters::EditorUniqueCounter.track_live_preview_edit_action(author: current_user, project: project) - head(200) + head(:ok) end def web_ide_pipelines_count Gitlab::UsageDataCounters::WebIdeCounter.increment_pipelines_count - head(200) + head(:ok) end end diff --git a/app/controllers/projects/snippets/application_controller.rb b/app/controllers/projects/snippets/application_controller.rb index 8ee12bf3795..b8faf464531 100644 --- a/app/controllers/projects/snippets/application_controller.rb +++ b/app/controllers/projects/snippets/application_controller.rb @@ -4,7 +4,7 @@ class Projects::Snippets::ApplicationController < Projects::ApplicationControlle include FindSnippet include SnippetAuthorizations - feature_category :snippets + feature_category :source_code_management private diff --git a/app/controllers/repositories/lfs_storage_controller.rb b/app/controllers/repositories/lfs_storage_controller.rb index d54b51b463a..22f1a81b95b 100644 --- a/app/controllers/repositories/lfs_storage_controller.rb +++ b/app/controllers/repositories/lfs_storage_controller.rb @@ -49,7 +49,7 @@ module Repositories validate_uploaded_file! if store_file!(oid, size) - head 200, content_type: LfsRequest::CONTENT_TYPE + head :ok, content_type: LfsRequest::CONTENT_TYPE else render plain: 'Unprocessable entity', status: :unprocessable_entity end diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb index 5351e3e9e77..9fb7a183597 100644 --- a/app/controllers/search_controller.rb +++ b/app/controllers/search_controller.rb @@ -32,7 +32,7 @@ class SearchController < ApplicationController before_action only: :show do push_frontend_feature_flag(:search_page_vertical_nav, current_user) end - + before_action :elasticsearch_in_use, only: :show rescue_from ActiveRecord::QueryCanceled, with: :render_timeout layout 'search' @@ -118,6 +118,11 @@ class SearchController < ApplicationController def opensearch end + def elasticsearch_in_use + search_service.respond_to?(:use_elasticsearch?) && search_service.use_elasticsearch? + end + strong_memoize_attr :elasticsearch_in_use + private # overridden in EE diff --git a/app/controllers/snippets/application_controller.rb b/app/controllers/snippets/application_controller.rb index f259f4569ef..64adc4e6611 100644 --- a/app/controllers/snippets/application_controller.rb +++ b/app/controllers/snippets/application_controller.rb @@ -4,7 +4,7 @@ class Snippets::ApplicationController < ApplicationController include FindSnippet include SnippetAuthorizations - feature_category :snippets + feature_category :source_code_management private diff --git a/app/controllers/snippets/notes_controller.rb b/app/controllers/snippets/notes_controller.rb index 8a4e8edbf3c..9e23eef4178 100644 --- a/app/controllers/snippets/notes_controller.rb +++ b/app/controllers/snippets/notes_controller.rb @@ -8,7 +8,7 @@ class Snippets::NotesController < ApplicationController before_action :authorize_read_snippet!, only: [:show, :index] before_action :authorize_create_note!, only: [:create] - feature_category :snippets + feature_category :source_code_management private diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 0f03333d793..f23e513e419 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -31,8 +31,7 @@ class UsersController < ApplicationController :followers, :following, :calendar, :calendar_activities, :exists, :activity, :follow, :unfollow, :ssh_keys] - feature_category :snippets, [:snippets] - feature_category :source_code_management, [:gpg_keys] + feature_category :source_code_management, [:snippets, :gpg_keys] # TODO: Set higher urgency after resolving https://gitlab.com/gitlab-org/gitlab/-/issues/357914 urgency :low, [:show, :calendar_activities, :contributed, :activity, :projects, :groups, :calendar, :snippets] diff --git a/app/models/user.rb b/app/models/user.rb index ea7a9cd5742..939b5430769 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -58,16 +58,16 @@ class User < ApplicationRecord add_authentication_token_field :feed_token add_authentication_token_field :static_object_token, encrypted: :optional - default_value_for :admin, false - default_value_for(:external) { Gitlab::CurrentSettings.user_default_external } - default_value_for(:can_create_group) { Gitlab::CurrentSettings.can_create_group } - default_value_for :can_create_team, false - default_value_for :hide_no_ssh_key, false - default_value_for :hide_no_password, false - default_value_for :project_view, :files - default_value_for :notified_of_own_activity, false - default_value_for :preferred_language, I18n.default_locale - default_value_for :theme_id, gitlab_config.default_theme + attribute :admin, default: false + attribute :external, default: -> { Gitlab::CurrentSettings.user_default_external } + attribute :can_create_group, default: -> { Gitlab::CurrentSettings.can_create_group } + attribute :can_create_team, default: false + attribute :hide_no_ssh_key, default: false + attribute :hide_no_password, default: false + attribute :project_view, default: :files + attribute :notified_of_own_activity, default: false + attribute :preferred_language, default: -> { I18n.default_locale } + attribute :theme_id, default: -> { gitlab_config.default_theme } attr_encrypted :otp_secret, key: Gitlab::Application.secrets.otp_key_base, @@ -376,6 +376,14 @@ class User < ApplicationRecord accepts_nested_attributes_for :credit_card_validation, update_only: true, allow_destroy: true state_machine :state, initial: :active do + # state_machine uses this method at class loading time to fetch the default + # value for the `state` column but in doing so it also evaluates all other + # columns default values which could trigger the recursive generation of + # ApplicationSetting records. We're setting it to `nil` here because we + # don't have a database default for the `state` column. + # + def owner_class_attribute_default; end + event :block do transition active: :blocked transition deactivated: :blocked diff --git a/app/models/user_preference.rb b/app/models/user_preference.rb index c6ebd550daf..bc2c6b526b8 100644 --- a/app/models/user_preference.rb +++ b/app/models/user_preference.rb @@ -26,10 +26,10 @@ class UserPreference < ApplicationRecord ignore_columns :experience_level, remove_with: '14.10', remove_after: '2021-03-22' - default_value_for :tab_width, value: Gitlab::TabWidth::DEFAULT, allows_nil: false - default_value_for :time_display_relative, value: true, allows_nil: false - default_value_for :time_format_in_24h, value: false, allows_nil: false - default_value_for :render_whitespace_in_code, value: false, allows_nil: false + attribute :tab_width, default: -> { Gitlab::TabWidth::DEFAULT } + attribute :time_display_relative, default: true + attribute :time_format_in_24h, default: false + attribute :render_whitespace_in_code, default: false class << self def notes_filters @@ -59,6 +59,67 @@ class UserPreference < ApplicationRecord self[notes_filter_field_for(resource)] end + def tab_width + read_attribute(:tab_width) || self.class.column_defaults['tab_width'] + end + + def tab_width=(value) + if value.nil? + default = self.class.column_defaults['tab_width'] + super(default) + else + super(value) + end + end + + def time_display_relative + value = read_attribute(:time_display_relative) + return value unless value.nil? + + self.class.column_defaults['time_display_relative'] + end + + def time_display_relative=(value) + if value.nil? + default = self.class.column_defaults['time_display_relative'] + super(default) + else + super(value) + end + end + + def time_format_in_24h + value = read_attribute(:time_format_in_24h) + return value unless value.nil? + + self.class.column_defaults['time_format_in_24h'] + end + + def time_format_in_24h=(value) + if value.nil? + default = self.class.column_defaults['time_format_in_24h'] + super(default) + else + super(value) + end + end + + def render_whitespace_in_code + value = read_attribute(:render_whitespace_in_code) + return value unless value.nil? + + self.class.column_defaults['render_whitespace_in_code'] + end + + def render_whitespace_in_code=(value) + if value.nil? + default = self.class.column_defaults['render_whitespace_in_code'] + super(default) + else + super(value) + end + end + private def notes_filter_field_for(resource) diff --git a/app/services/chat_names/find_user_service.rb b/app/services/chat_names/find_user_service.rb index 3dd3ba7f01c..ba6ebb7206b 100644 --- a/app/services/chat_names/find_user_service.rb +++ b/app/services/chat_names/find_user_service.rb @@ -19,6 +19,13 @@ module ChatNames # rubocop: disable CodeReuse/ActiveRecord def find_chat_name + if @integration.nil? + return ChatName.find_by( + team_id: @params[:team_id], + chat_id: @params[:user_id] + ) + end + ChatName.find_by( integration: @integration, team_id: @params[:team_id], diff --git a/app/views/search/show.html.haml b/app/views/search/show.html.haml index 9d812e77ad4..c58f492f633 100644 --- a/app/views/search/show.html.haml +++ b/app/views/search/show.html.haml @@ -20,7 +20,7 @@ = render_if_exists 'search/form_elasticsearch', attrs: { class: 'mb-2 mb-sm-0 align-self-center' } .gl-mt-3 - #js-search-topbar{ data: { "group-initial-data": group_attributes.to_json, "project-initial-data": project_attributes.to_json } } + #js-search-topbar{ data: { "group-initial-json": group_attributes.to_json, "project-initial-json": project_attributes.to_json, "elasticsearch-enabled": @elasticsearch_in_use.to_s, "default-branch-name": @project&.default_branch } } - if @search_term - if Feature.disabled?(:search_page_vertical_nav, current_user) = render 'search/category' diff --git a/config/feature_categories.yml b/config/feature_categories.yml index 94a50dc416e..0aa77bdb66b 100644 --- a/config/feature_categories.yml +++ b/config/feature_categories.yml @@ -67,7 +67,6 @@ - geo_replication - git_lfs - gitaly -- gitlab_docs - global_search - helm_chart_registry - importers @@ -105,6 +104,7 @@ - pubsec_services - purchase - quality_management +- rate_limiting - redis - release_evidence - release_orchestration @@ -116,6 +116,7 @@ - runner_fleet - runner_saas - saas_provisioning +- sbom - scalability - secret_detection - secrets_management @@ -124,7 +125,6 @@ - service_desk - service_ping - sm_provisioning -- snippets - source_code_management - static_application_security_testing - subgroups diff --git a/config/webpack.config.js b/config/webpack.config.js index c8a159605d1..4564530120c 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -435,6 +435,7 @@ module.exports = { }, { test: /\.(yml|yaml)$/, + resourceQuery: /raw/, loader: 'raw-loader', }, ].filter(Boolean), diff --git a/doc/api/product_analytics.md b/doc/api/product_analytics.md index b7401f83128..90df1090f62 100644 --- a/doc/api/product_analytics.md +++ b/doc/api/product_analytics.md @@ -31,7 +31,7 @@ POST /projects/:id/product_analytics/request/dry-run ### Request body -The body of the load request should be a valid Cube query. +The body of the load request must be a valid Cube query. ```json { @@ -68,9 +68,9 @@ The body of the load request should be a valid Cube query. } ``` -## Send meta request to Cube +## Send metadata request to Cube -Returns Cube Meta data for the Analytics data. For example: +Return Cube Metadata for the Analytics data. For example: ```plaintext GET /projects/:id/product_analytics/request/meta diff --git a/doc/operations/incident_management/alerts.md b/doc/operations/incident_management/alerts.md index 41dacd327a7..44e619ed166 100644 --- a/doc/operations/incident_management/alerts.md +++ b/doc/operations/incident_management/alerts.md @@ -225,18 +225,7 @@ and clear the user from the list of assignees, or select **Unassigned**. > [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/3066) in GitLab 13.1. -You can manually create [To-Do list items](../../user/todos.md) for yourself -from the Alert details screen, and view them later on your **To-Do List**. To -add a to-do item: +You can manually create a [to-do item](../../user/todos.md) for yourself +from an alert, and view it later on your **To-Do List**. -1. Display the list of current alerts: - - 1. On the top bar, select **Main menu > Projects** and find your project. - 1. On the left sidebar, select **Monitor > Alerts**. - -1. Select your desired alert to display its **Alert Management Details View**. -1. On the right sidebar, select **Add a to do**: - - ![Alert Details Add a to do](img/alert_detail_add_todo_v13_9.png) - -To view your To-Do List, on the top bar, select **To-Do List** (**{todo-done}**). +To add a to-do item, on the right sidebar, select **Add a to do**. diff --git a/doc/operations/incident_management/img/alert_detail_add_todo_v13_9.png b/doc/operations/incident_management/img/alert_detail_add_todo_v13_9.png Binary files differdeleted file mode 100644 index 5beb1cd0bfb..00000000000 --- a/doc/operations/incident_management/img/alert_detail_add_todo_v13_9.png +++ /dev/null diff --git a/doc/user/product_analytics/index.md b/doc/user/product_analytics/index.md index ebeb1f171a8..fa2dfc2e271 100644 --- a/doc/user/product_analytics/index.md +++ b/doc/user/product_analytics/index.md @@ -32,24 +32,24 @@ Prerequisite: 1. Select **Enable product analytics** and enter the configuration values. The following table shows the required configuration parameters and example values: - | Name | Value | - |------------------------------|----------------------------| - | Jitsu host | `https://jitsu.gitlab.com` | - | Jitsu project ID | `g0maofw84gx5sjxgse2k` | - | Jitsu administrator email | `jitsu.admin@gitlab.com` | - | Jitsu administrator password | `<your_password>` | + | Name | Value | + |------------------------------|------------------------------------------------------------| + | Jitsu host | `https://jitsu.gitlab.com` | + | Jitsu project ID | `g0maofw84gx5sjxgse2k` | + | Jitsu administrator email | `jitsu.admin@gitlab.com` | + | Jitsu administrator password | `<your_password>` | | Clickhouse URL | `https://<username>:<password>@clickhouse.gitlab.com:8123` | - | Cube API URL | `https://cube.gitlab.com` | - | Cube API key | `25718201b3e9...ae6bbdc62dbb` | + | Cube API URL | `https://cube.gitlab.com` | + | Cube API key | `25718201b3e9...ae6bbdc62dbb` | 1. Select **Save changes**. ## Product analytics dashboards Each project can define an unlimited number of dashboards. These dashboards are defined using our YAML schema and stored -in the `.gitlab/product_analytics/dashboards/` directory. The name of the file is the name of the dashboard, and visualizations are shared across dashboards.. +in the `.gitlab/product_analytics/dashboards/` directory of a project repository. The name of the file is the name of the dashboard, and visualizations are shared across dashboards. -Project maintainers can enforce approval rules on dashboard changes, and dashboards can be versioned in source control. +Project maintainers can enforce approval rules on dashboard changes using features such as code owners and approval rules. Dashboards are versioned in source control with the rest of a project's code. ### Define a dashboard @@ -57,8 +57,8 @@ To define a dashboard: 1. In `.gitlab/product_analytics/dashboards/`, create a directory named like the dashboard. Each dashboard should have its own directory. 1. In the new directory, create a `.yaml` file with the same name as the directory. This file contains the dashboard definition, and must conform to the JSON schema defined in `ee/app/validators/json_schemas/product_analytics_dashboard.json`. -1. In the `.gitlab/product_analytics/dashboards/visualizations/` directory, create a `yaml` file. This file defines the visualization type for the dashboard, and must conform to the schema in -`ee/app/validators/json_schemas/product_analytics_visualization.json`. +1. In the `.gitlab/product_analytics/dashboards/visualizations/` directory, create a `yaml` file. This file defines the visualization type for the dashboard, and must conform to the schema in + `ee/app/validators/json_schemas/product_analytics_visualization.json`. The example below includes three dashboards and one visualization that applies to all dashboards. diff --git a/jest.config.base.js b/jest.config.base.js index 56473d1643f..0f77517a9e3 100644 --- a/jest.config.base.js +++ b/jest.config.base.js @@ -43,6 +43,8 @@ module.exports = (path, options = {}) => { const TEST_FIXTURES_PATTERN = 'test_fixtures(/.*)$'; const moduleNameMapper = { + '^~(/.*)\\?raw$': '<rootDir>/app/assets/javascripts$1', + '^(.*)\\?raw$': '$1', '^~(/.*)$': '<rootDir>/app/assets/javascripts$1', '^ee_component(/.*)$': '<rootDir>/app/assets/javascripts/vue_shared/components/empty_component.js', diff --git a/lib/api/helpers/award_emoji.rb b/lib/api/helpers/award_emoji.rb index 3ea35381c97..625635f768b 100644 --- a/lib/api/helpers/award_emoji.rb +++ b/lib/api/helpers/award_emoji.rb @@ -7,7 +7,7 @@ module API [ { type: 'issue', resource: :projects, find_by: :iid, feature_category: :team_planning }, { type: 'merge_request', resource: :projects, find_by: :iid, feature_category: :code_review }, - { type: 'snippet', resource: :projects, find_by: :id, feature_category: :snippets } + { type: 'snippet', resource: :projects, find_by: :id, feature_category: :source_code_management } ] end diff --git a/lib/api/helpers/discussions_helpers.rb b/lib/api/helpers/discussions_helpers.rb index c94199b17bc..182ada54a12 100644 --- a/lib/api/helpers/discussions_helpers.rb +++ b/lib/api/helpers/discussions_helpers.rb @@ -8,7 +8,7 @@ module API # extend it. { Issue => :team_planning, - Snippet => :snippets, + Snippet => :source_code_management, MergeRequest => :code_review, Commit => :code_review } diff --git a/lib/api/helpers/notes_helpers.rb b/lib/api/helpers/notes_helpers.rb index 45671b09be9..9c4128509c8 100644 --- a/lib/api/helpers/notes_helpers.rb +++ b/lib/api/helpers/notes_helpers.rb @@ -9,7 +9,7 @@ module API { Issue => :team_planning, MergeRequest => :code_review, - Snippet => :snippets + Snippet => :source_code_management } end diff --git a/lib/api/project_snippets.rb b/lib/api/project_snippets.rb index 93ffb23fea8..7ef722301ca 100644 --- a/lib/api/project_snippets.rb +++ b/lib/api/project_snippets.rb @@ -6,7 +6,7 @@ module API before { check_snippets_enabled } - feature_category :snippets + feature_category :source_code_management params do requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project' diff --git a/lib/api/snippets.rb b/lib/api/snippets.rb index 36698a220bd..104848206a3 100644 --- a/lib/api/snippets.rb +++ b/lib/api/snippets.rb @@ -5,7 +5,7 @@ module API class Snippets < ::API::Base include PaginationParams - feature_category :snippets + feature_category :source_code_management urgency :low resource :snippets do diff --git a/lib/gitlab/memory/watchdog.rb b/lib/gitlab/memory/watchdog.rb index 435b416e7e9..2e0add73478 100644 --- a/lib/gitlab/memory/watchdog.rb +++ b/lib/gitlab/memory/watchdog.rb @@ -50,8 +50,6 @@ module Gitlab def initialize @configuration = Configuration.new @alive = true - - init_prometheus_metrics end ## @@ -62,7 +60,7 @@ module Gitlab end def call - logger.info(log_labels.merge(message: 'started')) + event_reporter.started(log_labels) while @alive sleep(sleep_time_seconds) @@ -70,7 +68,7 @@ module Gitlab monitor if Feature.enabled?(:gitlab_memory_watchdog, type: :ops) end - logger.info(log_labels.merge(message: 'stopped')) + event_reporter.stopped(log_labels) end def stop @@ -85,18 +83,16 @@ module Gitlab next unless result.threshold_violated? - @counter_violations.increment(reason: result.monitor_name) + event_reporter.threshold_violated(result.monitor_name) next unless result.strikes_exceeded? - @alive = !memory_limit_exceeded_callback(result.monitor_name, result.payload) + @alive = !strike_exceeded_callback(result.monitor_name, result.payload) end end - def memory_limit_exceeded_callback(monitor_name, monitor_payload) - all_labels = log_labels.merge(monitor_payload) - logger.warn(all_labels) - @counter_violations_handled.increment(reason: monitor_name) + def strike_exceeded_callback(monitor_name, monitor_payload) + event_reporter.strikes_exceeded(monitor_name, log_labels(monitor_payload)) Gitlab::Memory::Reports::HeapDump.enqueue! if @configuration.write_heap_dumps? @@ -111,43 +107,18 @@ module Gitlab @configuration.handler end - def logger - @configuration.logger + def event_reporter + @configuration.event_reporter end def sleep_time_seconds @configuration.sleep_time_seconds end - def log_labels - { - pid: $$, - worker_id: worker_id, + def log_labels(extra = {}) + extra.merge( memwd_handler_class: handler.class.name, - memwd_sleep_time_s: sleep_time_seconds, - memwd_rss_bytes: process_rss_bytes - } - end - - def process_rss_bytes - Gitlab::Metrics::System.memory_usage_rss[:total] - end - - def worker_id - ::Prometheus::PidProvider.worker_id - end - - def init_prometheus_metrics - default_labels = { pid: worker_id } - @counter_violations = Gitlab::Metrics.counter( - :gitlab_memwd_violations_total, - 'Total number of times a Ruby process violated a memory threshold', - default_labels - ) - @counter_violations_handled = Gitlab::Metrics.counter( - :gitlab_memwd_violations_handled_total, - 'Total number of times Ruby process memory violations were handled', - default_labels + memwd_sleep_time_s: sleep_time_seconds ) end end diff --git a/lib/gitlab/memory/watchdog/configuration.rb b/lib/gitlab/memory/watchdog/configuration.rb index 885772d6119..980b6bf750b 100644 --- a/lib/gitlab/memory/watchdog/configuration.rb +++ b/lib/gitlab/memory/watchdog/configuration.rb @@ -35,7 +35,7 @@ module Gitlab DEFAULT_SLEEP_TIME_SECONDS = 60 - attr_writer :logger, :handler, :sleep_time_seconds, :write_heap_dumps + attr_writer :event_reporter, :handler, :sleep_time_seconds, :write_heap_dumps def monitors @monitor_stack ||= MonitorStack.new @@ -47,8 +47,8 @@ module Gitlab @handler ||= NullHandler.instance end - def logger - @logger ||= Gitlab::Logger.new($stdout) + def event_reporter + @event_reporter ||= EventReporter.new end # Used to control the frequency with which the watchdog will wake up and poll the GC. diff --git a/lib/gitlab/memory/watchdog/configurator.rb b/lib/gitlab/memory/watchdog/configurator.rb index 610d8ca9e97..880f9800d96 100644 --- a/lib/gitlab/memory/watchdog/configurator.rb +++ b/lib/gitlab/memory/watchdog/configurator.rb @@ -17,7 +17,6 @@ module Gitlab class << self def configure_for_puma ->(config) do - config.logger = Gitlab::AppLogger config.handler = Gitlab::Memory::Watchdog::PumaHandler.new config.write_heap_dumps = write_heap_dumps? config.sleep_time_seconds = ENV.fetch('GITLAB_MEMWD_SLEEP_TIME_SEC', DEFAULT_SLEEP_INTERVAL_S).to_i @@ -27,11 +26,11 @@ module Gitlab def configure_for_sidekiq ->(config) do - config.logger = Sidekiq.logger config.handler = Gitlab::Memory::Watchdog::TermProcessHandler.new config.write_heap_dumps = write_heap_dumps? config.sleep_time_seconds = sidekiq_sleep_time config.monitors(&configure_monitors_for_sidekiq) + config.event_reporter = EventReporter.new(logger: ::Sidekiq.logger) end end diff --git a/lib/gitlab/memory/watchdog/event_reporter.rb b/lib/gitlab/memory/watchdog/event_reporter.rb new file mode 100644 index 00000000000..4d37a5e14fd --- /dev/null +++ b/lib/gitlab/memory/watchdog/event_reporter.rb @@ -0,0 +1,73 @@ +# frozen_string_literal: true + +module Gitlab + module Memory + class Watchdog + class EventReporter + include ::Gitlab::Utils::StrongMemoize + + attr_reader :logger + + def initialize(logger: Gitlab::AppLogger) + @logger = logger + end + + def started(labels = {}) + logger.info(message: 'started', **log_labels(labels)) + end + + def stopped(labels = {}) + logger.info(message: 'stopped', **log_labels(labels)) + end + + def threshold_violated(monitor_name) + counter_violations.increment(reason: monitor_name) + end + + def strikes_exceeded(monitor_name, labels = {}) + logger.warn(log_labels(labels)) + + counter_violations_handled.increment(reason: monitor_name) + end + + private + + def log_labels(extra = {}) + extra.merge( + pid: $$, + worker_id: worker_id, + memwd_rss_bytes: process_rss_bytes + ) + end + + def process_rss_bytes + Gitlab::Metrics::System.memory_usage_rss[:total] + end + + def worker_id + ::Prometheus::PidProvider.worker_id + end + + def counter_violations + strong_memoize("counter_violations") do + ::Gitlab::Metrics.counter( + :gitlab_memwd_violations_total, + 'Total number of times a Ruby process violated a memory threshold', + { pid: worker_id } + ) + end + end + + def counter_violations_handled + strong_memoize("counter_violations_handled") do + ::Gitlab::Metrics.counter( + :gitlab_memwd_violations_handled_total, + 'Total number of times Ruby process memory violations were handled', + { pid: worker_id } + ) + end + end + end + end + end +end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 053b4b150e9..0256549ddbe 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -27129,6 +27129,9 @@ msgstr "" msgid "New incident" msgstr "" +msgid "New incident has been created" +msgstr "" + msgid "New issue" msgstr "" @@ -32209,12 +32212,18 @@ msgstr "" msgid "ProjectSettings|Allow" msgstr "" +msgid "ProjectSettings|Allow anyone to pull from Package Registry" +msgstr "" + msgid "ProjectSettings|Always show thumbs-up and thumbs-down award emoji buttons on issues, merge requests, and snippets." msgstr "" msgid "ProjectSettings|Analytics" msgstr "" +msgid "ProjectSettings|Anyone can pull packages with a package manager API." +msgstr "" + msgid "ProjectSettings|Auto-close referenced issues on default branch" msgstr "" @@ -32296,9 +32305,6 @@ msgstr "" msgid "ProjectSettings|Every project can have its own space to store its Docker images" msgstr "" -msgid "ProjectSettings|Every project can have its own space to store its packages." -msgstr "" - msgid "ProjectSettings|Every project can have its own space to store its packages. Note: The Package Registry is always visible when a project is public." msgstr "" @@ -32413,6 +32419,9 @@ msgstr "" msgid "ProjectSettings|Monitor" msgstr "" +msgid "ProjectSettings|Monitor the health of your project and respond to incidents." +msgstr "" + msgid "ProjectSettings|No merge commits are created." msgstr "" @@ -32458,6 +32467,9 @@ msgstr "" msgid "ProjectSettings|Public" msgstr "" +msgid "ProjectSettings|Publish, store, and view packages in a project." +msgstr "" + msgid "ProjectSettings|Releases" msgstr "" @@ -38667,6 +38679,9 @@ msgstr "" msgid "Something went wrong when reordering designs. Please try again" msgstr "" +msgid "Something went wrong when sending the incident link to Slack." +msgstr "" + msgid "Something went wrong while adding timeline event." msgstr "" @@ -41488,6 +41503,9 @@ msgstr "" msgid "There was a problem communicating with your device." msgstr "" +msgid "There was a problem creating the incident. Please try again." +msgstr "" + msgid "There was a problem fetching CRM contacts." msgstr "" diff --git a/package.json b/package.json index 4d67b5b1a23..66ffcc85012 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "@cubejs-client/core": "^0.31.0", "@gitlab/at.js": "1.5.7", "@gitlab/favicon-overlay": "2.0.0", - "@gitlab/svgs": "3.11.0", + "@gitlab/svgs": "3.12.0", "@gitlab/ui": "50.1.2", "@gitlab/visual-review-tools": "1.7.3", "@gitlab/web-ide": "0.0.1-dev-20221114183058", diff --git a/rubocop/cop/rspec/timecop_freeze.rb b/rubocop/cop/rspec/timecop_freeze.rb deleted file mode 100644 index b13f5050040..00000000000 --- a/rubocop/cop/rspec/timecop_freeze.rb +++ /dev/null @@ -1,41 +0,0 @@ -# frozen_string_literal: true - -require 'rubocop-rspec' - -module RuboCop - module Cop - module RSpec - # This cop checks for `Timecop.freeze` usage in specs. - # - # @example - # - # # bad - # Timecop.freeze(Time.current) { example.run } - # - # # good - # freeze_time(Time.current) { example.run } - # - class TimecopFreeze < RuboCop::Cop::Base - extend RuboCop::Cop::AutoCorrector - - include MatchRange - MESSAGE = 'Do not use `Timecop.freeze`, use `freeze_time` instead. ' \ - 'See https://gitlab.com/gitlab-org/gitlab/-/issues/214432 for more info.' - - def_node_matcher :timecop_freeze?, <<~PATTERN - (send (const nil? :Timecop) :freeze ?_) - PATTERN - - def on_send(node) - return unless timecop_freeze?(node) - - add_offense(node, message: MESSAGE) do |corrector| - each_match_range(node.source_range, /^(Timecop\.freeze)/) do |match_range| - corrector.replace(match_range, 'freeze_time') - end - end - end - end - end - end -end diff --git a/rubocop/cop/rspec/timecop_travel.rb b/rubocop/cop/rspec/timecop_travel.rb deleted file mode 100644 index 03f978be349..00000000000 --- a/rubocop/cop/rspec/timecop_travel.rb +++ /dev/null @@ -1,41 +0,0 @@ -# frozen_string_literal: true - -require 'rubocop-rspec' - -module RuboCop - module Cop - module RSpec - # This cop checks for `Timecop.travel` usage in specs. - # - # @example - # - # # bad - # Timecop.travel(1.day.ago) { create(:issue) } - # - # # good - # travel_to(1.day.ago) { create(:issue) } - # - class TimecopTravel < RuboCop::Cop::Base - extend RuboCop::Cop::AutoCorrector - - include MatchRange - MESSAGE = 'Do not use `Timecop.travel`, use `travel_to` instead. ' \ - 'See https://gitlab.com/gitlab-org/gitlab/-/issues/214432 for more info.' - - def_node_matcher :timecop_travel?, <<~PATTERN - (send (const nil? :Timecop) :travel _) - PATTERN - - def on_send(node) - return unless timecop_travel?(node) - - add_offense(node, message: MESSAGE) do |corrector| - each_match_range(node.source_range, /^(Timecop\.travel)/) do |match_range| - corrector.replace(match_range, 'travel_to') - end - end - end - end - end - end -end diff --git a/spec/features/dashboard/snippets_spec.rb b/spec/features/dashboard/snippets_spec.rb index fcfd6ca9cf1..ab2cfc0573e 100644 --- a/spec/features/dashboard/snippets_spec.rb +++ b/spec/features/dashboard/snippets_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Dashboard snippets', feature_category: :snippets do +RSpec.describe 'Dashboard snippets', feature_category: :source_code_management do let_it_be(:user) { create(:user) } context 'when the project has snippets' do diff --git a/spec/features/projects/settings/packages_settings_spec.rb b/spec/features/projects/settings/packages_settings_spec.rb index 1c2b0faa215..57e9816ddd1 100644 --- a/spec/features/projects/settings/packages_settings_spec.rb +++ b/spec/features/projects/settings/packages_settings_spec.rb @@ -33,6 +33,10 @@ RSpec.describe 'Projects > Settings > Packages', :js do it 'displays the packages access level setting' do expect(page).to have_selector('[data-testid="package-registry-access-level"] > label', text: 'Package registry') + expect(page).to have_selector('input[name="package_registry_enabled"]', visible: false) + expect(page).to have_selector('input[name="package_registry_enabled"] + button', visible: true) + expect(page).to have_selector('input[name="package_registry_api_for_everyone_enabled"]', visible: false) + expect(page).to have_selector('input[name="package_registry_api_for_everyone_enabled"] + button', visible: true) expect(page).to have_selector( 'input[name="project[project_feature_attributes][package_registry_access_level]"]', visible: false diff --git a/spec/features/snippets/embedded_snippet_spec.rb b/spec/features/snippets/embedded_snippet_spec.rb index 7bd61824494..73b29ffd575 100644 --- a/spec/features/snippets/embedded_snippet_spec.rb +++ b/spec/features/snippets/embedded_snippet_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Embedded Snippets', feature_category: :snippets do +RSpec.describe 'Embedded Snippets', feature_category: :source_code_management do let_it_be(:snippet) { create(:personal_snippet, :public, :repository) } let(:blobs) { snippet.blobs.first(3) } diff --git a/spec/features/snippets/explore_spec.rb b/spec/features/snippets/explore_spec.rb index d0f4d888d94..ef4b75ac3b4 100644 --- a/spec/features/snippets/explore_spec.rb +++ b/spec/features/snippets/explore_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Explore Snippets', feature_category: :snippets do +RSpec.describe 'Explore Snippets', feature_category: :source_code_management do let!(:public_snippet) { create(:personal_snippet, :public) } let!(:internal_snippet) { create(:personal_snippet, :internal) } let!(:private_snippet) { create(:personal_snippet, :private) } diff --git a/spec/features/snippets/internal_snippet_spec.rb b/spec/features/snippets/internal_snippet_spec.rb index 5169cc2a0f8..9645c9c110d 100644 --- a/spec/features/snippets/internal_snippet_spec.rb +++ b/spec/features/snippets/internal_snippet_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Internal Snippets', :js, feature_category: :snippets do +RSpec.describe 'Internal Snippets', :js, feature_category: :source_code_management do let(:internal_snippet) { create(:personal_snippet, :internal, :repository) } let(:content) { internal_snippet.blobs.first.data.strip! } diff --git a/spec/features/snippets/notes_on_personal_snippets_spec.rb b/spec/features/snippets/notes_on_personal_snippets_spec.rb index b9d5e56d432..c281e5906ad 100644 --- a/spec/features/snippets/notes_on_personal_snippets_spec.rb +++ b/spec/features/snippets/notes_on_personal_snippets_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Comments on personal snippets', :js, feature_category: :snippets do +RSpec.describe 'Comments on personal snippets', :js, feature_category: :source_code_management do include NoteInteractionHelpers include Spec::Support::Helpers::ModalHelpers diff --git a/spec/features/snippets/private_snippets_spec.rb b/spec/features/snippets/private_snippets_spec.rb index 198ea11972d..0620a50ea72 100644 --- a/spec/features/snippets/private_snippets_spec.rb +++ b/spec/features/snippets/private_snippets_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Private Snippets', :js, feature_category: :snippets do +RSpec.describe 'Private Snippets', :js, feature_category: :source_code_management do let(:user) { create(:user) } let(:private_snippet) { create(:personal_snippet, :repository, :private, author: user) } let(:content) { private_snippet.blobs.first.data.strip! } diff --git a/spec/features/snippets/public_snippets_spec.rb b/spec/features/snippets/public_snippets_spec.rb index 627a12aa765..be6d6b2c0fa 100644 --- a/spec/features/snippets/public_snippets_spec.rb +++ b/spec/features/snippets/public_snippets_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Public Snippets', :js, feature_category: :snippets do +RSpec.describe 'Public Snippets', :js, feature_category: :source_code_management do let(:public_snippet) { create(:personal_snippet, :public, :repository) } let(:content) { public_snippet.blobs.first.data.strip! } diff --git a/spec/features/snippets/search_snippets_spec.rb b/spec/features/snippets/search_snippets_spec.rb index 002fe05fcb0..98842f54015 100644 --- a/spec/features/snippets/search_snippets_spec.rb +++ b/spec/features/snippets/search_snippets_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Search Snippets', :js, feature_category: :snippets do +RSpec.describe 'Search Snippets', :js, feature_category: :source_code_management do it 'user searches for snippets by title' do public_snippet = create(:personal_snippet, :public, title: 'Beginning and Middle') private_snippet = create(:personal_snippet, :private, title: 'Middle and End') diff --git a/spec/features/snippets/show_spec.rb b/spec/features/snippets/show_spec.rb index 6cce60fbef3..a6e0bc32d42 100644 --- a/spec/features/snippets/show_spec.rb +++ b/spec/features/snippets/show_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Snippet', :js, feature_category: :snippets do +RSpec.describe 'Snippet', :js, feature_category: :source_code_management do let_it_be(:user) { create(:user) } let_it_be(:snippet) { create(:personal_snippet, :public, :repository, author: user) } diff --git a/spec/features/snippets/spam_snippets_spec.rb b/spec/features/snippets/spam_snippets_spec.rb index 9e74df3ac05..5d49b36f4fe 100644 --- a/spec/features/snippets/spam_snippets_spec.rb +++ b/spec/features/snippets/spam_snippets_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe 'snippet editor with spam', skip: "Will be handled in https://gitlab.com/gitlab-org/gitlab/-/issues/217722", - feature_category: :snippets do + feature_category: :source_code_management do include_context 'includes Spam constants' let_it_be(:user) { create(:user) } diff --git a/spec/features/snippets/user_creates_snippet_spec.rb b/spec/features/snippets/user_creates_snippet_spec.rb index 4aa099e5737..064250c5673 100644 --- a/spec/features/snippets/user_creates_snippet_spec.rb +++ b/spec/features/snippets/user_creates_snippet_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'User creates snippet', :js, feature_category: :snippets do +RSpec.describe 'User creates snippet', :js, feature_category: :source_code_management do include DropzoneHelper include Spec::Support::Helpers::Features::SnippetSpecHelpers diff --git a/spec/features/snippets/user_deletes_snippet_spec.rb b/spec/features/snippets/user_deletes_snippet_spec.rb index 23436a8933c..3c4c41b0181 100644 --- a/spec/features/snippets/user_deletes_snippet_spec.rb +++ b/spec/features/snippets/user_deletes_snippet_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'User deletes snippet', :js, feature_category: :snippets do +RSpec.describe 'User deletes snippet', :js, feature_category: :source_code_management do let(:user) { create(:user) } let(:content) { 'puts "test"' } let(:snippet) { create(:personal_snippet, :repository, :public, content: content, author: user) } diff --git a/spec/features/snippets/user_edits_snippet_spec.rb b/spec/features/snippets/user_edits_snippet_spec.rb index 561f1cce26b..5096472ebe1 100644 --- a/spec/features/snippets/user_edits_snippet_spec.rb +++ b/spec/features/snippets/user_edits_snippet_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'User edits snippet', :js, feature_category: :snippets do +RSpec.describe 'User edits snippet', :js, feature_category: :source_code_management do include DropzoneHelper include Spec::Support::Helpers::Features::SnippetSpecHelpers diff --git a/spec/features/snippets/user_snippets_spec.rb b/spec/features/snippets/user_snippets_spec.rb index 9839f8a472a..09e0e30666d 100644 --- a/spec/features/snippets/user_snippets_spec.rb +++ b/spec/features/snippets/user_snippets_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'User Snippets', feature_category: :snippets do +RSpec.describe 'User Snippets', feature_category: :source_code_management do let(:author) { create(:user) } let!(:public_snippet) { create(:personal_snippet, :public, author: author, title: "This is a public snippet") } let!(:internal_snippet) { create(:personal_snippet, :internal, author: author, title: "This is an internal snippet") } diff --git a/spec/frontend/pages/projects/shared/permissions/components/settings_panel_spec.js b/spec/frontend/pages/projects/shared/permissions/components/settings_panel_spec.js index 155f1ff4ef3..8e0ca544a1c 100644 --- a/spec/frontend/pages/projects/shared/permissions/components/settings_panel_spec.js +++ b/spec/frontend/pages/projects/shared/permissions/components/settings_panel_spec.js @@ -114,9 +114,14 @@ describe('Settings Panel', () => { const findPackageSettings = () => wrapper.findComponent({ ref: 'package-settings' }); const findPackageAccessLevel = () => wrapper.find('[data-testid="package-registry-access-level"]'); - const findPackageAccessLevels = () => - wrapper.find('[name="project[project_feature_attributes][package_registry_access_level]"]'); const findPackagesEnabledInput = () => wrapper.find('[name="project[packages_enabled]"]'); + const findPackageRegistryEnabledInput = () => wrapper.find('[name="package_registry_enabled"]'); + const findPackageRegistryAccessLevelHiddenInput = () => + wrapper.find( + 'input[name="project[project_feature_attributes][package_registry_access_level]"]', + ); + const findPackageRegistryApiForEveryoneEnabledInput = () => + wrapper.find('[name="package_registry_api_for_everyone_enabled"]'); const findPagesSettings = () => wrapper.findComponent({ ref: 'pages-settings' }); const findPagesAccessLevels = () => wrapper.find('[name="project[project_feature_attributes][pages_access_level]"]'); @@ -587,28 +592,63 @@ describe('Settings Panel', () => { expect(findPackageAccessLevel().exists()).toBe(true); }); + it('has hidden input field for package registry access level', () => { + wrapper = mountComponent({ + glFeatures: { packageRegistryAccessLevel: true }, + packagesAvailable: true, + }); + + expect(findPackageRegistryAccessLevelHiddenInput().exists()).toBe(true); + }); + it.each` - visibilityLevel | output - ${VISIBILITY_LEVEL_PRIVATE_INTEGER} | ${[[featureAccessLevel.PROJECT_MEMBERS, 'Only Project Members'], [30, 'Everyone']]} - ${VISIBILITY_LEVEL_INTERNAL_INTEGER} | ${[[featureAccessLevel.EVERYONE, 'Everyone With Access'], [30, 'Everyone']]} - ${VISIBILITY_LEVEL_PUBLIC_INTEGER} | ${[[30, 'Everyone']]} + projectVisibilityLevel | packageRegistryEnabled | packageRegistryApiForEveryoneEnabled | expectedAccessLevel + ${VISIBILITY_LEVEL_PRIVATE_INTEGER} | ${false} | ${'disabled'} | ${featureAccessLevel.NOT_ENABLED} + ${VISIBILITY_LEVEL_PRIVATE_INTEGER} | ${true} | ${false} | ${featureAccessLevel.PROJECT_MEMBERS} + ${VISIBILITY_LEVEL_PRIVATE_INTEGER} | ${true} | ${true} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS} + ${VISIBILITY_LEVEL_INTERNAL_INTEGER} | ${false} | ${'disabled'} | ${featureAccessLevel.NOT_ENABLED} + ${VISIBILITY_LEVEL_INTERNAL_INTEGER} | ${true} | ${false} | ${featureAccessLevel.EVERYONE} + ${VISIBILITY_LEVEL_INTERNAL_INTEGER} | ${true} | ${true} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS} + ${VISIBILITY_LEVEL_PUBLIC_INTEGER} | ${false} | ${'hidden'} | ${featureAccessLevel.NOT_ENABLED} + ${VISIBILITY_LEVEL_PUBLIC_INTEGER} | ${true} | ${'hidden'} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS} `( - 'renders correct options when visibilityLevel is $visibilityLevel', - async ({ visibilityLevel, output }) => { + 'sets correct access level', + async ({ + projectVisibilityLevel, + packageRegistryEnabled, + packageRegistryApiForEveryoneEnabled, + expectedAccessLevel, + }) => { wrapper = mountComponent({ glFeatures: { packageRegistryAccessLevel: true }, packagesAvailable: true, currentSettings: { - visibilityLevel, + visibilityLevel: projectVisibilityLevel, }, }); - expect(findPackageAccessLevels().props('options')).toStrictEqual(output); + await findPackageRegistryEnabledInput().vm.$emit('change', packageRegistryEnabled); + + const packageRegistryApiForEveryoneEnabledInput = findPackageRegistryApiForEveryoneEnabledInput(); + + if (packageRegistryApiForEveryoneEnabled === 'hidden') { + expect(packageRegistryApiForEveryoneEnabledInput.exists()).toBe(false); + } else if (packageRegistryApiForEveryoneEnabled === 'disabled') { + expect(packageRegistryApiForEveryoneEnabledInput.props('disabled')).toBe(true); + } else { + expect(packageRegistryApiForEveryoneEnabledInput.props('disabled')).toBe(false); + await packageRegistryApiForEveryoneEnabledInput.vm.$emit( + 'change', + packageRegistryApiForEveryoneEnabled, + ); + } + + expect(wrapper.vm.packageRegistryAccessLevel).toBe(expectedAccessLevel); }, ); it.each` - initialProjectVisibilityLevel | newProjectVisibilityLevel | initialPackageRegistryOption | expectedPackageRegistryOption + initialProjectVisibilityLevel | newProjectVisibilityLevel | initialAccessLevel | expectedAccessLevel ${VISIBILITY_LEVEL_PRIVATE_INTEGER} | ${VISIBILITY_LEVEL_INTERNAL_INTEGER} | ${featureAccessLevel.NOT_ENABLED} | ${featureAccessLevel.NOT_ENABLED} ${VISIBILITY_LEVEL_PRIVATE_INTEGER} | ${VISIBILITY_LEVEL_INTERNAL_INTEGER} | ${featureAccessLevel.PROJECT_MEMBERS} | ${featureAccessLevel.EVERYONE} ${VISIBILITY_LEVEL_PRIVATE_INTEGER} | ${VISIBILITY_LEVEL_INTERNAL_INTEGER} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS} @@ -626,27 +666,25 @@ describe('Settings Panel', () => { ${VISIBILITY_LEVEL_PUBLIC_INTEGER} | ${VISIBILITY_LEVEL_INTERNAL_INTEGER} | ${featureAccessLevel.NOT_ENABLED} | ${featureAccessLevel.NOT_ENABLED} ${VISIBILITY_LEVEL_PUBLIC_INTEGER} | ${VISIBILITY_LEVEL_INTERNAL_INTEGER} | ${FEATURE_ACCESS_LEVEL_ANONYMOUS} | ${featureAccessLevel.EVERYONE} `( - 'changes option from $initialPackageRegistryOption to $expectedPackageRegistryOption when visibilityLevel changed from $initialProjectVisibilityLevel to $newProjectVisibilityLevel', + 'changes access level when project visibility level changed', async ({ initialProjectVisibilityLevel, newProjectVisibilityLevel, - initialPackageRegistryOption, - expectedPackageRegistryOption, + initialAccessLevel, + expectedAccessLevel, }) => { wrapper = mountComponent({ glFeatures: { packageRegistryAccessLevel: true }, packagesAvailable: true, currentSettings: { visibilityLevel: initialProjectVisibilityLevel, - packageRegistryAccessLevel: initialPackageRegistryOption, + packageRegistryAccessLevel: initialAccessLevel, }, }); await findProjectVisibilityLevelInput().setValue(newProjectVisibilityLevel); - expect(findPackageAccessLevels().props('value')).toStrictEqual( - expectedPackageRegistryOption, - ); + expect(wrapper.vm.packageRegistryAccessLevel).toBe(expectedAccessLevel); }, ); }); diff --git a/spec/lib/api/every_api_endpoint_spec.rb b/spec/lib/api/every_api_endpoint_spec.rb index 5fe14823a29..c45ff9eb628 100644 --- a/spec/lib/api/every_api_endpoint_spec.rb +++ b/spec/lib/api/every_api_endpoint_spec.rb @@ -32,10 +32,21 @@ RSpec.describe 'Every API endpoint' do next unless used_category next if used_category == :not_owned - [path, used_category] unless feature_categories.include?(used_category) + [klass, path, used_category] unless feature_categories.include?(used_category) end.compact - expect(routes_unknown_category).to be_empty, "#{routes_unknown_category.first(10)} had an unknown category" + message = -> do + list = routes_unknown_category.map do |klass, path, category| + "- #{klass} (#{path}): #{category}" + end + + <<~MESSAGE + Unknown categories found for: + #{list.join("\n")} + MESSAGE + end + + expect(routes_unknown_category).to be_empty, message end # This is required for API::Base.path_for_app to work, as it picks diff --git a/spec/lib/gitlab/memory/watchdog/configuration_spec.rb b/spec/lib/gitlab/memory/watchdog/configuration_spec.rb index 8c9b26ce2c4..f1405ca7d68 100644 --- a/spec/lib/gitlab/memory/watchdog/configuration_spec.rb +++ b/spec/lib/gitlab/memory/watchdog/configuration_spec.rb @@ -20,10 +20,10 @@ RSpec.describe Gitlab::Memory::Watchdog::Configuration do end end - describe '#logger' do - context 'when logger is not set, defaults to stdout logger' do - it 'defaults to Logger' do - expect(configuration.logger).to be_an_instance_of(::Gitlab::Logger) + describe '#event_reporter' do + context 'when event reporter is not set' do + it 'defaults to EventReporter' do + expect(configuration.event_reporter).to be_an_instance_of(::Gitlab::Memory::Watchdog::EventReporter) end end end diff --git a/spec/lib/gitlab/memory/watchdog/configurator_spec.rb b/spec/lib/gitlab/memory/watchdog/configurator_spec.rb index ec61d027329..892bad603a8 100644 --- a/spec/lib/gitlab/memory/watchdog/configurator_spec.rb +++ b/spec/lib/gitlab/memory/watchdog/configurator_spec.rb @@ -6,17 +6,23 @@ require 'sidekiq' require_dependency 'gitlab/cluster/lifecycle_events' RSpec.describe Gitlab::Memory::Watchdog::Configurator do - shared_examples 'as configurator' do |handler_class, sleep_time_env, sleep_time| + shared_examples 'as configurator' do |handler_class, event_reporter_class, sleep_time_env, sleep_time| it 'configures the correct handler' do configurator.call(configuration) expect(configuration.handler).to be_an_instance_of(handler_class) end + it 'configures the correct event reporter' do + configurator.call(configuration) + + expect(configuration.event_reporter).to be_an_instance_of(event_reporter_class) + end + it 'configures the correct logger' do configurator.call(configuration) - expect(configuration.logger).to eq(logger) + expect(configuration.event_reporter.logger).to eq(logger) end it 'does not enable writing heap dumps by default' do @@ -129,6 +135,7 @@ RSpec.describe Gitlab::Memory::Watchdog::Configurator do it_behaves_like 'as configurator', Gitlab::Memory::Watchdog::PumaHandler, + Gitlab::Memory::Watchdog::EventReporter, 'GITLAB_MEMWD_SLEEP_TIME_SEC', described_class::DEFAULT_SLEEP_INTERVAL_S @@ -236,6 +243,7 @@ RSpec.describe Gitlab::Memory::Watchdog::Configurator do it_behaves_like 'as configurator', Gitlab::Memory::Watchdog::TermProcessHandler, + Gitlab::Memory::Watchdog::EventReporter, 'SIDEKIQ_MEMORY_KILLER_CHECK_INTERVAL', described_class::DEFAULT_SIDEKIQ_SLEEP_INTERVAL_S diff --git a/spec/lib/gitlab/memory/watchdog/event_reporter_spec.rb b/spec/lib/gitlab/memory/watchdog/event_reporter_spec.rb new file mode 100644 index 00000000000..f667bc724d2 --- /dev/null +++ b/spec/lib/gitlab/memory/watchdog/event_reporter_spec.rb @@ -0,0 +1,118 @@ +# frozen_string_literal: true + +require 'fast_spec_helper' +require 'prometheus/client' + +RSpec.describe Gitlab::Memory::Watchdog::EventReporter, feature_category: :application_performance do + let(:logger) { instance_double(::Logger) } + let(:violations_counter) { instance_double(::Prometheus::Client::Counter) } + let(:violations_handled_counter) { instance_double(::Prometheus::Client::Counter) } + let(:reporter) { described_class.new(logger: logger) } + + def stub_prometheus_metrics + allow(Gitlab::Metrics).to receive(:counter) + .with(:gitlab_memwd_violations_total, anything, anything) + .and_return(violations_counter) + allow(Gitlab::Metrics).to receive(:counter) + .with(:gitlab_memwd_violations_handled_total, anything, anything) + .and_return(violations_handled_counter) + + allow(violations_counter).to receive(:increment) + allow(violations_handled_counter).to receive(:increment) + end + + before do + stub_prometheus_metrics + allow(Gitlab::Metrics::System).to receive(:memory_usage_rss).at_least(:once).and_return( + total: 1024 + ) + allow(::Prometheus::PidProvider).to receive(:worker_id).and_return('worker_1') + end + + describe '#logger' do + context 'when logger is not provided' do + let(:reporter) { described_class.new } + + it 'uses default Gitlab::AppLogger' do + expect(reporter.logger).to eq(Gitlab::AppLogger) + end + end + end + + describe '#started' do + it 'logs start message once' do + expect(logger).to receive(:info).once + .with( + pid: Process.pid, + worker_id: 'worker_1', + custom_label: 'dummy_label', + memwd_rss_bytes: 1024, + message: 'started') + + reporter.started(custom_label: 'dummy_label') + end + end + + describe '#stopped' do + subject { reporter.stopped(custom_label: 'dummy_label') } + + it 'logs stop message once' do + expect(logger).to receive(:info).once + .with( + pid: Process.pid, + worker_id: 'worker_1', + custom_label: 'dummy_label', + memwd_rss_bytes: 1024, + message: 'stopped') + + reporter.stopped(custom_label: 'dummy_label') + end + end + + describe '#threshold_violated' do + subject { reporter.threshold_violated(:monitor_name) } + + it 'increments violations counter' do + expect(violations_counter).to receive(:increment).with(reason: :monitor_name) + + subject + end + + it 'does not increment handled violations counter' do + expect(violations_handled_counter).not_to receive(:increment) + + subject + end + + it 'does not log violation' do + expect(logger).not_to receive(:warn) + + subject + end + end + + describe '#strikes_exceeded' do + subject { reporter.strikes_exceeded(:monitor_name, { message: 'dummy_text' }) } + + before do + allow(logger).to receive(:warn) + end + + it 'increments handled violations counter' do + expect(violations_handled_counter).to receive(:increment).with(reason: :monitor_name) + + subject + end + + it 'logs violation' do + expect(logger).to receive(:warn) + .with( + pid: Process.pid, + worker_id: 'worker_1', + memwd_rss_bytes: 1024, + message: 'dummy_text') + + subject + end + end +end diff --git a/spec/lib/gitlab/memory/watchdog_spec.rb b/spec/lib/gitlab/memory/watchdog_spec.rb index 8703bf8b00b..fca31d590f5 100644 --- a/spec/lib/gitlab/memory/watchdog_spec.rb +++ b/spec/lib/gitlab/memory/watchdog_spec.rb @@ -6,12 +6,10 @@ RSpec.describe Gitlab::Memory::Watchdog, :aggregate_failures do context 'watchdog' do let(:configuration) { instance_double(described_class::Configuration) } let(:handler) { instance_double(described_class::NullHandler) } - let(:logger) { instance_double(::Logger) } + let(:reporter) { instance_double(described_class::EventReporter) } let(:sleep_time_seconds) { 60 } let(:write_heap_dumps) { false } let(:threshold_violated) { false } - let(:violations_counter) { instance_double(::Prometheus::Client::Counter) } - let(:violations_handled_counter) { instance_double(::Prometheus::Client::Counter) } let(:watchdog_iterations) { 1 } let(:name) { :monitor_name } let(:payload) { { message: 'dummy_text' } } @@ -38,18 +36,6 @@ RSpec.describe Gitlab::Memory::Watchdog, :aggregate_failures do end end - def stub_prometheus_metrics - allow(Gitlab::Metrics).to receive(:counter) - .with(:gitlab_memwd_violations_total, anything, anything) - .and_return(violations_counter) - allow(Gitlab::Metrics).to receive(:counter) - .with(:gitlab_memwd_violations_handled_total, anything, anything) - .and_return(violations_handled_counter) - - allow(violations_counter).to receive(:increment) - allow(violations_handled_counter).to receive(:increment) - end - describe '#initialize' do it 'initialize new configuration' do expect(described_class::Configuration).to receive(:new) @@ -60,34 +46,27 @@ RSpec.describe Gitlab::Memory::Watchdog, :aggregate_failures do describe '#call' do before do - stub_prometheus_metrics - allow(Gitlab::Metrics::System).to receive(:memory_usage_rss).at_least(:once).and_return( - total: 1024 - ) - allow(::Prometheus::PidProvider).to receive(:worker_id).and_return('worker_1') - watchdog.configure do |config| config.handler = handler - config.logger = logger + config.event_reporter = reporter config.sleep_time_seconds = sleep_time_seconds config.write_heap_dumps = write_heap_dumps config.monitors.push monitor_class, threshold_violated, payload, max_strikes: max_strikes end allow(handler).to receive(:call).and_return(true) - allow(logger).to receive(:info) - allow(logger).to receive(:warn) + allow(reporter).to receive(:started) + allow(reporter).to receive(:stopped) + allow(reporter).to receive(:threshold_violated) + allow(reporter).to receive(:strikes_exceeded) end - it 'logs start message once' do - expect(logger).to receive(:info).once + it 'reports started event once' do + expect(reporter).to receive(:started).once .with( - pid: Process.pid, - worker_id: 'worker_1', memwd_handler_class: handler.class.name, - memwd_sleep_time_s: sleep_time_seconds, - memwd_rss_bytes: 1024, - message: 'started') + memwd_sleep_time_s: sleep_time_seconds + ) watchdog.call end @@ -109,15 +88,9 @@ RSpec.describe Gitlab::Memory::Watchdog, :aggregate_failures do end context 'when process does not exceed threshold' do - it 'does not increment violations counters' do - expect(violations_counter).not_to receive(:increment) - expect(violations_handled_counter).not_to receive(:increment) - - watchdog.call - end - - it 'does not log violation' do - expect(logger).not_to receive(:warn) + it 'does not report violations event' do + expect(reporter).not_to receive(:threshold_violated) + expect(reporter).not_to receive(:strikes_exceeded) watchdog.call end @@ -132,21 +105,15 @@ RSpec.describe Gitlab::Memory::Watchdog, :aggregate_failures do context 'when process exceeds threshold' do let(:threshold_violated) { true } - it 'increments violations counter' do - expect(violations_counter).to receive(:increment).with(reason: name) + it 'reports threshold violated event' do + expect(reporter).to receive(:threshold_violated).with(name) watchdog.call end context 'when process does not exceed the allowed number of strikes' do - it 'does not increment handled violations counter' do - expect(violations_handled_counter).not_to receive(:increment) - - watchdog.call - end - - it 'does not log violation' do - expect(logger).not_to receive(:warn) + it 'does not report strikes exceeded event' do + expect(reporter).not_to receive(:strikes_exceeded) watchdog.call end @@ -171,23 +138,16 @@ RSpec.describe Gitlab::Memory::Watchdog, :aggregate_failures do context 'when monitor exceeds the allowed number of strikes' do let(:max_strikes) { 0 } - it 'increments handled violations counter' do - expect(violations_handled_counter).to receive(:increment).with(reason: name) - - watchdog.call - end - - it 'logs violation' do - expect(logger).to receive(:warn) + it 'reports strikes exceeded event' do + expect(reporter).to receive(:strikes_exceeded) .with( - pid: Process.pid, - worker_id: 'worker_1', + name, memwd_handler_class: handler.class.name, memwd_sleep_time_s: sleep_time_seconds, - memwd_rss_bytes: 1024, memwd_cur_strikes: 1, memwd_max_strikes: max_strikes, - message: 'dummy_text') + message: "dummy_text" + ) watchdog.call end @@ -225,7 +185,7 @@ RSpec.describe Gitlab::Memory::Watchdog, :aggregate_failures do before do watchdog.configure do |config| config.handler = handler - config.logger = logger + config.event_reporter = reporter config.sleep_time_seconds = sleep_time_seconds config.monitors.push monitor_class, threshold_violated, payload, max_strikes: max_strikes config.monitors.push monitor_class, threshold_violated, payload, max_strikes: max_strikes @@ -241,15 +201,12 @@ RSpec.describe Gitlab::Memory::Watchdog, :aggregate_failures do end end - it 'logs stop message once' do - expect(logger).to receive(:info).once + it 'reports stopped event once' do + expect(reporter).to receive(:stopped).once .with( - pid: Process.pid, - worker_id: 'worker_1', memwd_handler_class: handler.class.name, - memwd_sleep_time_s: sleep_time_seconds, - memwd_rss_bytes: 1024, - message: 'stopped') + memwd_sleep_time_s: sleep_time_seconds + ) watchdog.call end diff --git a/spec/models/user_preference_spec.rb b/spec/models/user_preference_spec.rb index d76334d7c9e..a6f64c90657 100644 --- a/spec/models/user_preference_spec.rb +++ b/spec/models/user_preference_spec.rb @@ -3,7 +3,9 @@ require 'spec_helper' RSpec.describe UserPreference do - let(:user_preference) { create(:user_preference) } + let_it_be(:user) { create(:user) } + + let(:user_preference) { create(:user_preference, user: user) } describe 'validations' do describe 'diffs_deletion_color and diffs_addition_color' do @@ -132,10 +134,24 @@ RSpec.describe UserPreference do describe '#tab_width' do it 'is set to 8 by default' do # Intentionally not using factory here to test the constructor. - pref = UserPreference.new + pref = described_class.new + + expect(pref.tab_width).to eq(8) + end + + it 'returns default value when assigning nil' do + pref = described_class.new(tab_width: nil) + expect(pref.tab_width).to eq(8) end + it 'returns default value when the value is NULL' do + pref = create(:user_preference, user: user) + pref.update_column(:tab_width, nil) + + expect(pref.reload.tab_width).to eq(8) + end + it do is_expected.to validate_numericality_of(:tab_width) .only_integer @@ -143,4 +159,141 @@ RSpec.describe UserPreference do .is_less_than_or_equal_to(12) end end + + describe '#tab_width=' do + it 'sets to default value when nil' do + pref = described_class.new(tab_width: nil) + + expect(pref.read_attribute(:tab_width)).to eq(8) + end + + it 'sets user values' do + pref = described_class.new(tab_width: 12) + + expect(pref.read_attribute(:tab_width)).to eq(12) + end + end + + describe '#time_display_relative' do + it 'is set to true by default' do + pref = described_class.new + + expect(pref.time_display_relative).to eq(true) + end + + it 'returns default value when assigning nil' do + pref = described_class.new(time_display_relative: nil) + + expect(pref.time_display_relative).to eq(true) + end + + it 'returns default value when the value is NULL' do + pref = create(:user_preference, user: user) + pref.update_column(:time_display_relative, nil) + + expect(pref.reload.time_display_relative).to eq(true) + end + + it 'returns assigned value' do + pref = described_class.new(time_display_relative: false) + + expect(pref.time_display_relative).to eq(false) + end + end + + describe '#time_display_relative=' do + it 'sets to default value when nil' do + pref = described_class.new(time_display_relative: nil) + + expect(pref.read_attribute(:time_display_relative)).to eq(true) + end + + it 'sets user values' do + pref = described_class.new(time_display_relative: false) + + expect(pref.read_attribute(:time_display_relative)).to eq(false) + end + end + + describe '#time_format_in_24h' do + it 'is set to false by default' do + pref = described_class.new + + expect(pref.time_format_in_24h).to eq(false) + end + + it 'returns default value when assigning nil' do + pref = described_class.new(time_format_in_24h: nil) + + expect(pref.time_format_in_24h).to eq(false) + end + + it 'returns default value when the value is NULL' do + pref = create(:user_preference, user: user) + pref.update_column(:time_format_in_24h, nil) + + expect(pref.reload.time_format_in_24h).to eq(false) + end + + it 'returns assigned value' do + pref = described_class.new(time_format_in_24h: true) + + expect(pref.time_format_in_24h).to eq(true) + end + end + + describe '#time_format_in_24h=' do + it 'sets to default value when nil' do + pref = described_class.new(time_format_in_24h: nil) + + expect(pref.read_attribute(:time_format_in_24h)).to eq(false) + end + + it 'sets user values' do + pref = described_class.new(time_format_in_24h: true) + + expect(pref.read_attribute(:time_format_in_24h)).to eq(true) + end + end + + describe '#render_whitespace_in_code' do + it 'is set to false by default' do + pref = described_class.new + + expect(pref.render_whitespace_in_code).to eq(false) + end + + it 'returns default value when assigning nil' do + pref = described_class.new(render_whitespace_in_code: nil) + + expect(pref.render_whitespace_in_code).to eq(false) + end + + it 'returns default value when the value is NULL' do + pref = create(:user_preference, user: user) + pref.update_column(:render_whitespace_in_code, nil) + + expect(pref.reload.render_whitespace_in_code).to eq(false) + end + + it 'returns assigned value' do + pref = described_class.new(render_whitespace_in_code: true) + + expect(pref.render_whitespace_in_code).to eq(true) + end + end + + describe '#render_whitespace_in_code=' do + it 'sets to default value when nil' do + pref = described_class.new(render_whitespace_in_code: nil) + + expect(pref.read_attribute(:render_whitespace_in_code)).to eq(false) + end + + it 'sets user values' do + pref = described_class.new(render_whitespace_in_code: true) + + expect(pref.read_attribute(:render_whitespace_in_code)).to eq(true) + end + end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 0f2f5d65dda..7faf9b51720 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -146,6 +146,21 @@ RSpec.describe User do it { is_expected.to have_many(:project_callouts).class_name('Users::ProjectCallout') } it { is_expected.to have_many(:created_projects).dependent(:nullify).class_name('Project') } + describe 'default values' do + let(:user) { described_class.new } + + it { expect(user.admin).to be_falsey } + it { expect(user.external).to eq(Gitlab::CurrentSettings.user_default_external) } + it { expect(user.can_create_group).to eq(Gitlab::CurrentSettings.can_create_group) } + it { expect(user.can_create_team).to be_falsey } + it { expect(user.hide_no_ssh_key).to be_falsey } + it { expect(user.hide_no_password).to be_falsey } + it { expect(user.project_view).to eq('files') } + it { expect(user.notified_of_own_activity).to be_falsey } + it { expect(user.preferred_language).to eq(I18n.default_locale.to_s) } + it { expect(user.theme_id).to eq(described_class.gitlab_config.default_theme) } + end + describe '#user_detail' do it 'does not persist `user_detail` by default' do expect(create(:user).user_detail).not_to be_persisted @@ -398,7 +413,7 @@ RSpec.describe User do end it 'falls back to english when I18n.default_locale is not an available language' do - I18n.default_locale = :kl + allow(I18n).to receive(:default_locale) { :kl } default_preferred_language = user.send(:default_preferred_language) expect(user.preferred_language).to eq default_preferred_language @@ -7307,4 +7322,51 @@ RSpec.describe User do expect(user.account_age_in_days).to be(1) end end + + describe 'state machine and default attributes' do + let(:model) do + Class.new(ApplicationRecord) do + self.table_name = User.table_name + + attribute :external, default: -> { 1 / 0 } + + state_machine :state, initial: :active do + end + end + end + + it 'raises errors by default' do + expect { model }.to raise_error(ZeroDivisionError) + end + + context 'with state machine default attributes override' do + let(:model) do + Class.new(ApplicationRecord) do + self.table_name = User.table_name + + attribute :external, default: -> { 1 / 0 } + + state_machine :state, initial: :active do + def owner_class_attribute_default; end + end + end + end + + it 'does not raise errors' do + expect { model }.not_to raise_error + end + + it 'raises errors when default attributes are used' do + expect { model.new.attributes }.to raise_error(ZeroDivisionError) + end + + it 'does not evaluate default attributes when values are provided' do + expect { model.new(external: false).attributes }.not_to raise_error + end + + it 'sets the state machine default value' do + expect(model.new(external: true).state).to eq('active') + end + end + end end diff --git a/spec/rubocop/cop/rspec/timecop_freeze_spec.rb b/spec/rubocop/cop/rspec/timecop_freeze_spec.rb deleted file mode 100644 index 4361f587da3..00000000000 --- a/spec/rubocop/cop/rspec/timecop_freeze_spec.rb +++ /dev/null @@ -1,28 +0,0 @@ -# frozen_string_literal: true - -require 'rubocop_spec_helper' - -require_relative '../../../../rubocop/cop/rspec/timecop_freeze' - -RSpec.describe RuboCop::Cop::RSpec::TimecopFreeze do - context 'when calling Timecop.freeze' do - it 'registers an offense and corrects', :aggregate_failures do - expect_offense(<<~CODE) - Timecop.freeze(Time.current) { example.run } - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Do not use `Timecop.freeze`, use `freeze_time` instead. [...] - CODE - - expect_correction(<<~CODE) - freeze_time(Time.current) { example.run } - CODE - end - end - - context 'when calling a different method on Timecop' do - it 'does not register an offense' do - expect_no_offenses(<<~CODE) - Timecop.travel(Time.current) - CODE - end - end -end diff --git a/spec/rubocop/cop/rspec/timecop_travel_spec.rb b/spec/rubocop/cop/rspec/timecop_travel_spec.rb deleted file mode 100644 index 89c46ff6c59..00000000000 --- a/spec/rubocop/cop/rspec/timecop_travel_spec.rb +++ /dev/null @@ -1,28 +0,0 @@ -# frozen_string_literal: true - -require 'rubocop_spec_helper' - -require_relative '../../../../rubocop/cop/rspec/timecop_travel' - -RSpec.describe RuboCop::Cop::RSpec::TimecopTravel do - context 'when calling Timecop.travel' do - it 'registers an offense and corrects', :aggregate_failures do - expect_offense(<<~CODE) - Timecop.travel(1.day.ago) { create(:issue) } - ^^^^^^^^^^^^^^^^^^^^^^^^^ Do not use `Timecop.travel`, use `travel_to` instead. [...] - CODE - - expect_correction(<<~CODE) - travel_to(1.day.ago) { create(:issue) } - CODE - end - end - - context 'when calling a different method on Timecop' do - it 'does not register an offense' do - expect_no_offenses(<<~CODE) - Timecop.freeze { create(:issue) } - CODE - end - end -end diff --git a/spec/services/chat_names/find_user_service_spec.rb b/spec/services/chat_names/find_user_service_spec.rb index 4b0a1204558..b65a76ca37c 100644 --- a/spec/services/chat_names/find_user_service_spec.rb +++ b/spec/services/chat_names/find_user_service_spec.rb @@ -40,6 +40,14 @@ RSpec.describe ChatNames::FindUserService, :clean_gitlab_redis_shared_state do expect(chat_name.reload.last_used_at).to eq(time) end + + context 'when integration is not passed' do + it 'returns chat name' do + requested_chat_name = described_class.new(nil, params).execute + + expect(requested_chat_name).to eq(chat_name) + end + end end context 'when different user is requested' do diff --git a/workhorse/go.mod b/workhorse/go.mod index 05d0db1cfac..88e6748ee8e 100644 --- a/workhorse/go.mod +++ b/workhorse/go.mod @@ -10,7 +10,7 @@ require ( github.com/aws/aws-sdk-go v1.44.145 github.com/disintegration/imaging v1.6.2 github.com/getsentry/raven-go v0.2.0 - github.com/golang-jwt/jwt/v4 v4.4.2 + github.com/golang-jwt/jwt/v4 v4.4.3 github.com/golang/gddo v0.0.0-20210115222349-20d68f94ee1f github.com/golang/protobuf v1.5.2 github.com/gomodule/redigo v2.0.0+incompatible diff --git a/workhorse/go.sum b/workhorse/go.sum index 2c96dc02e88..a9090fa0706 100644 --- a/workhorse/go.sum +++ b/workhorse/go.sum @@ -686,8 +686,9 @@ github.com/golang-jwt/jwt v3.2.1+incompatible h1:73Z+4BJcrTC+KczS6WvTPvRGOp1WmfE github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= -github.com/golang-jwt/jwt/v4 v4.4.2 h1:rcc4lwaZgFMCZ5jxF9ABolDcIHdBytAFgqFPbSJQAYs= github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v4 v4.4.3 h1:Hxl6lhQFj4AnOX6MLrsCb/+7tCj7DxP7VA+2rDIq5AU= +github.com/golang-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI= github.com/golang/gddo v0.0.0-20210115222349-20d68f94ee1f h1:16RtHeWGkJMc80Etb8RPCcKevXGldr57+LOyZt8zOlg= diff --git a/yarn.lock b/yarn.lock index f47edb442bc..083d117f274 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1120,10 +1120,10 @@ stylelint-declaration-strict-value "1.8.0" stylelint-scss "4.2.0" -"@gitlab/svgs@3.11.0": - version "3.11.0" - resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-3.11.0.tgz#91e8e25583cddef48c0c79175203e5b0a4eaa519" - integrity sha512-1cJu1WXPoOHfGgv5fT3nmA9cgAQ3U1Fm/oMSVYUgBxU35R0I8W704GMLsIZwBuQ/S/Ow7WLwIkoOhLb/spNKPg== +"@gitlab/svgs@3.12.0": + version "3.12.0" + resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-3.12.0.tgz#cebd2ebf21e803d0d9e674d43fcb2d868f5d5a62" + integrity sha512-7GDMXuBoOL380sjdBSpPufUzwd5dJgkzqgpx26JBlrO2ShSW0k5KnmIurSXSe8gpqwAEIEw/BbpjCz0SRRRwQg== "@gitlab/ui@50.1.2": version "50.1.2" |