Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
5a9468a4e5
commit
4ee706fcd1
16
.rubocop.yml
16
.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:
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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 }}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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" />
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
},
|
||||
});
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ class Projects::Snippets::ApplicationController < Projects::ApplicationControlle
|
|||
include FindSnippet
|
||||
include SnippetAuthorizations
|
||||
|
||||
feature_category :snippets
|
||||
feature_category :source_code_management
|
||||
|
||||
private
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ class Snippets::ApplicationController < ApplicationController
|
|||
include FindSnippet
|
||||
include SnippetAuthorizations
|
||||
|
||||
feature_category :snippets
|
||||
feature_category :source_code_management
|
||||
|
||||
private
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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],
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -435,6 +435,7 @@ module.exports = {
|
|||
},
|
||||
{
|
||||
test: /\.(yml|yaml)$/,
|
||||
resourceQuery: /raw/,
|
||||
loader: 'raw-loader',
|
||||
},
|
||||
].filter(Boolean),
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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**:
|
||||
|
||||

|
||||
|
||||
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**.
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 26 KiB |
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ module API
|
|||
# extend it.
|
||||
{
|
||||
Issue => :team_planning,
|
||||
Snippet => :snippets,
|
||||
Snippet => :source_code_management,
|
||||
MergeRequest => :code_review,
|
||||
Commit => :code_review
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ module API
|
|||
{
|
||||
Issue => :team_planning,
|
||||
MergeRequest => :code_review,
|
||||
Snippet => :snippets
|
||||
Snippet => :source_code_management
|
||||
}
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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 ""
|
||||
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) }
|
||||
|
|
|
|||
|
|
@ -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) }
|
||||
|
|
|
|||
|
|
@ -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! }
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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! }
|
||||
|
|
|
|||
|
|
@ -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! }
|
||||
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
|
|
|||
|
|
@ -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) }
|
||||
|
||||
|
|
|
|||
|
|
@ -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) }
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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) }
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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") }
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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=
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
Loading…
Reference in New Issue