Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-03-30 18:12:04 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-03-30 18:12:04 +0300
commit93501e7509fb61b25f091d81381d3e86842a9cdd (patch)
treee11e5528450c3e3815f59c13d8799722d8d754c1
parentbfa1adf9773ba7ea7cde546ea545b72721d36faa (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.gitlab-ci.yml2
-rw-r--r--.gitlab/ci/rules.gitlab-ci.yml1
-rw-r--r--.gitlab/issue_templates/Geo Replicate a new Git repository type.md1
-rw-r--r--.gitlab/issue_templates/Geo Replicate a new blob type.md1
-rw-r--r--GITALY_SERVER_VERSION2
-rw-r--r--app/assets/javascripts/design_management/pages/index.vue9
-rw-r--r--app/assets/javascripts/diffs/components/app.vue13
-rw-r--r--app/assets/javascripts/diffs/components/diff_code_quality.vue32
-rw-r--r--app/assets/javascripts/diffs/components/diff_code_quality_item.vue54
-rw-r--r--app/assets/javascripts/diffs/components/shared/findings_drawer.vue110
-rw-r--r--app/assets/javascripts/environments/components/environment_actions.vue49
-rw-r--r--app/assets/javascripts/environments/components/new_environment_item.vue1
-rw-r--r--app/assets/javascripts/graphql_shared/possible_types.json4
-rw-r--r--app/assets/javascripts/ide/index.js1
-rw-r--r--app/assets/javascripts/ide/stores/modules/commit/actions.js5
-rw-r--r--app/assets/javascripts/ide/stores/state.js1
-rw-r--r--app/assets/javascripts/mr_notes/stores/drawer/actions.js5
-rw-r--r--app/assets/javascripts/mr_notes/stores/drawer/getters.js1
-rw-r--r--app/assets/javascripts/mr_notes/stores/drawer/index.js13
-rw-r--r--app/assets/javascripts/mr_notes/stores/drawer/mutation_types.js3
-rw-r--r--app/assets/javascripts/mr_notes/stores/drawer/mutations.js7
-rw-r--r--app/assets/javascripts/mr_notes/stores/index.js2
-rw-r--r--app/controllers/projects/merge_requests_controller.rb1
-rw-r--r--app/controllers/projects/pipelines_controller.rb20
-rw-r--r--app/graphql/types/work_items/widget_interface.rb5
-rw-r--r--app/graphql/types/work_items/widgets/current_user_todos_type.rb26
-rw-r--r--app/helpers/ide_helper.rb2
-rw-r--r--app/helpers/sidebars_helper.rb19
-rw-r--r--app/models/group.rb13
-rw-r--r--app/models/work_items/widget_definition.rb3
-rw-r--r--app/models/work_items/widgets/current_user_todos.rb8
-rw-r--r--app/services/bulk_imports/create_service.rb11
-rw-r--r--app/services/ci/pipeline_processing/atomic_processing_service.rb2
-rw-r--r--app/services/ci/pipeline_processing/atomic_processing_service/status_collection.rb14
-rw-r--r--app/views/projects/pipelines/new.html.haml1
-rw-r--r--app/views/shared/_ref_switcher.html.haml4
-rw-r--r--config/feature_flags/development/ci_simplify_dag_status_calculation_for_processing.yml8
-rw-r--r--config/feature_flags/development/code_quality_inline_drawer.yml8
-rw-r--r--config/routes/pipelines.rb1
-rw-r--r--db/migrate/20230317162059_add_current_user_todos_work_item_widget.rb57
-rw-r--r--db/post_migrate/20230328111013_re_migrate_redis_slot_keys.rb73
-rw-r--r--db/schema_migrations/202303171620591
-rw-r--r--db/schema_migrations/202303281110131
-rw-r--r--doc/api/graphql/reference/index.md31
-rw-r--r--doc/architecture/blueprints/database_testing/index.md2
-rw-r--r--lib/gitlab/ci/status/composite.rb11
-rw-r--r--lib/gitlab/database_importers/work_items/base_type_importer.rb24
-rw-r--r--lib/gitlab/usage_data_counters/known_events/analytics.yml13
-rw-r--r--lib/gitlab/usage_data_counters/known_events/ci_templates.yml151
-rw-r--r--lib/gitlab/usage_data_counters/known_events/ci_users.yml2
-rw-r--r--lib/gitlab/usage_data_counters/known_events/code_review_events.yml112
-rw-r--r--lib/gitlab/usage_data_counters/known_events/common.yml69
-rw-r--r--lib/gitlab/usage_data_counters/known_events/container_registry_events.yml5
-rw-r--r--lib/gitlab/usage_data_counters/known_events/ecosystem.yml11
-rw-r--r--lib/gitlab/usage_data_counters/known_events/error_tracking.yml2
-rw-r--r--lib/gitlab/usage_data_counters/known_events/importer_events.yml4
-rw-r--r--lib/gitlab/usage_data_counters/known_events/kubernetes_agent.yml1
-rw-r--r--lib/gitlab/usage_data_counters/known_events/package_events.yml22
-rw-r--r--lib/gitlab/usage_data_counters/known_events/quickactions.yml63
-rw-r--r--lib/gitlab/usage_data_counters/known_events/work_items.yml7
-rw-r--r--lib/tasks/gitlab/assets.rake3
-rw-r--r--locale/gitlab.pot15
-rw-r--r--qa/qa/page/project/show.rb13
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/branch_with_unusual_name_spec.rb5
-rw-r--r--spec/controllers/projects/pipelines_controller_spec.rb142
-rw-r--r--spec/frontend/design_management/pages/index_spec.js35
-rw-r--r--spec/frontend/diffs/components/app_spec.js17
-rw-r--r--spec/frontend/diffs/components/diff_code_quality_item_spec.js66
-rw-r--r--spec/frontend/diffs/components/diff_code_quality_spec.js40
-rw-r--r--spec/frontend/diffs/components/shared/__snapshots__/findings_drawer_spec.js.snap126
-rw-r--r--spec/frontend/diffs/components/shared/findings_drawer_spec.js19
-rw-r--r--spec/frontend/diffs/create_diffs_store.js2
-rw-r--r--spec/frontend/diffs/mock_data/diff_code_quality.js5
-rw-r--r--spec/frontend/diffs/mock_data/findings_drawer.js21
-rw-r--r--spec/frontend/environments/environment_actions_spec.js114
-rw-r--r--spec/frontend/environments/new_environment_item_spec.js16
-rw-r--r--spec/frontend/ide/stores/modules/commit/actions_spec.js66
-rw-r--r--spec/frontend/notes/components/discussion_filter_spec.js122
-rw-r--r--spec/graphql/types/work_items/widget_interface_spec.rb1
-rw-r--r--spec/graphql/types/work_items/widgets/current_user_todos_type_spec.rb11
-rw-r--r--spec/helpers/sidebars_helper_spec.rb23
-rw-r--r--spec/lib/gitlab/ci/status/composite_spec.rb4
-rw-r--r--spec/migrations/20230302811133_re_migrate_redis_slot_keys_spec.rb77
-rw-r--r--spec/migrations/20230317162059_add_current_user_todos_work_item_widget_spec.rb27
-rw-r--r--spec/models/group_spec.rb16
-rw-r--r--spec/models/work_items/widget_definition_spec.rb3
-rw-r--r--spec/requests/api/graphql/work_item_spec.rb87
-rw-r--r--spec/services/bulk_imports/create_service_spec.rb40
-rw-r--r--spec/services/ci/pipeline_processing/atomic_processing_service/status_collection_spec.rb15
-rw-r--r--spec/services/ci/pipeline_processing/atomic_processing_service_spec.rb19
-rw-r--r--spec/support/helpers/test_env.rb2
-rw-r--r--workhorse/.tool-versions2
-rw-r--r--workhorse/internal/httprs/httprs.go1
-rw-r--r--workhorse/internal/queueing/queue.go5
-rw-r--r--workhorse/internal/queueing/requests.go4
95 files changed, 1725 insertions, 564 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index b9442c00e59..fbc0aa31341 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -152,7 +152,7 @@ variables:
DOCKER_VERSION: "23.0.1"
RUBY_VERSION: "2.7"
RUBYGEMS_VERSION: "3.4"
- GO_VERSION: "1.18"
+ GO_VERSION: "1.19"
RUST_VERSION: "1.65"
FLAKY_RSPEC_SUITE_REPORT_PATH: rspec/flaky/report-suite.json
diff --git a/.gitlab/ci/rules.gitlab-ci.yml b/.gitlab/ci/rules.gitlab-ci.yml
index cdb455c8c31..d8162d108ba 100644
--- a/.gitlab/ci/rules.gitlab-ci.yml
+++ b/.gitlab/ci/rules.gitlab-ci.yml
@@ -283,6 +283,7 @@
# This list should match the list in Tasks::Gitlab::Assets.assets_impacting_compilation
.assets-compilation-patterns: &assets-compilation-patterns
- "{package.json,yarn.lock}"
+ - "{Gemfile,Gemfile.lock}"
- ".browserslistrc"
- "babel.config.js"
- "config/webpack.config.js"
diff --git a/.gitlab/issue_templates/Geo Replicate a new Git repository type.md b/.gitlab/issue_templates/Geo Replicate a new Git repository type.md
index c33e5f8eb68..60b091b04a2 100644
--- a/.gitlab/issue_templates/Geo Replicate a new Git repository type.md
+++ b/.gitlab/issue_templates/Geo Replicate a new Git repository type.md
@@ -465,6 +465,7 @@ That's all of the required database changes.
state { Geo::CoolWidgetRegistry.state_value(:failed) }
last_synced_at { 1.day.ago }
retry_count { 2 }
+ retry_at { 2.hours.from_now }
last_sync_failure { 'Random error' }
end
diff --git a/.gitlab/issue_templates/Geo Replicate a new blob type.md b/.gitlab/issue_templates/Geo Replicate a new blob type.md
index 0c5dbaebacf..df2d1871a85 100644
--- a/.gitlab/issue_templates/Geo Replicate a new blob type.md
+++ b/.gitlab/issue_templates/Geo Replicate a new blob type.md
@@ -425,6 +425,7 @@ That's all of the required database changes.
state { Geo::CoolWidgetRegistry.state_value(:failed) }
last_synced_at { 1.day.ago }
retry_count { 2 }
+ retry_at { 2.hours.from_now }
last_sync_failure { 'Random error' }
end
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION
index 3019d72ae6f..e09b2dc4deb 100644
--- a/GITALY_SERVER_VERSION
+++ b/GITALY_SERVER_VERSION
@@ -1 +1 @@
-140ee5c9aa5f4fb7dd4a0017677788ee88ce7149
+64d8d3472d0e490a914018438d4f531cc1b659f5
diff --git a/app/assets/javascripts/design_management/pages/index.vue b/app/assets/javascripts/design_management/pages/index.vue
index 2b98c7b708c..beefdba6d1f 100644
--- a/app/assets/javascripts/design_management/pages/index.vue
+++ b/app/assets/javascripts/design_management/pages/index.vue
@@ -104,7 +104,7 @@ export default {
return this.permissions.createDesign;
},
showToolbar() {
- return this.canCreateDesign && this.allVersions.length > 0;
+ return this.allVersions.length > 0;
},
hasDesigns() {
return this.designs.length > 0;
@@ -375,6 +375,7 @@ export default {
<design-version-dropdown />
</div>
<div
+ v-if="canCreateDesign"
v-show="hasDesigns"
class="gl-display-flex gl-align-items-center"
data-testid="design-selector-toolbar"
@@ -489,7 +490,11 @@ export default {
/>
</li>
<template #header>
- <li :class="designDropzoneWrapperClass" data-testid="design-dropzone-wrapper">
+ <li
+ v-if="canCreateDesign"
+ :class="designDropzoneWrapperClass"
+ data-testid="design-dropzone-wrapper"
+ >
<design-dropzone
:enable-drag-behavior="isDraggingDesign"
:class="{ 'design-list-item design-list-item-new': !isDesignListEmpty }"
diff --git a/app/assets/javascripts/diffs/components/app.vue b/app/assets/javascripts/diffs/components/app.vue
index 5951912af55..99bc3780b55 100644
--- a/app/assets/javascripts/diffs/components/app.vue
+++ b/app/assets/javascripts/diffs/components/app.vue
@@ -47,6 +47,7 @@ import { reviewStatuses } from '../utils/file_reviews';
import { diffsApp } from '../utils/performance';
import { updateChangesTabCount } from '../utils/merge_request';
import { queueRedisHllEvents } from '../utils/queue_events';
+import FindingsDrawer from './shared/findings_drawer.vue';
import CollapsedFilesWarning from './collapsed_files_warning.vue';
import CommitWidget from './commit_widget.vue';
import CompareVersions from './compare_versions.vue';
@@ -60,6 +61,7 @@ import PreRenderer from './pre_renderer.vue';
export default {
name: 'DiffsApp',
components: {
+ FindingsDrawer,
DynamicScroller,
DynamicScrollerItem,
PreRenderer,
@@ -200,6 +202,7 @@ export default {
numTotalFiles: 'realSize',
numVisibleFiles: 'size',
}),
+ ...mapState('findingsDrawer', ['activeDrawer']),
...mapState('diffs', [
'showTreeList',
'isLoading',
@@ -234,6 +237,7 @@ export default {
'flatBlobsList',
]),
...mapGetters(['isNotesFetched', 'getNoteableData']),
+ ...mapGetters('findingsDrawer', ['activeDrawer']),
diffs() {
if (!this.viewDiffsFileByFile) {
return this.diffFiles;
@@ -437,6 +441,10 @@ export default {
'setFileByFile',
'disableVirtualScroller',
]),
+ ...mapActions('findingsDrawer', ['setDrawer']),
+ closeDrawer() {
+ this.setDrawer({});
+ },
subscribeToEvents() {
notesEventHub.$once('fetchDiffData', this.fetchData);
notesEventHub.$on('refetchDiffData', this.refetchDiffData);
@@ -631,6 +639,11 @@ export default {
<template>
<div v-show="shouldShow">
+ <findings-drawer
+ v-if="glFeatures.codeQualityInlineDrawer"
+ :drawer="activeDrawer"
+ @close="closeDrawer"
+ />
<div v-if="isLoading || !isTreeLoaded" class="loading"><gl-loading-icon size="lg" /></div>
<div v-else id="diffs" :class="{ active: shouldShow }" class="diffs tab-pane">
<compare-versions :diff-files-count-text="numTotalFiles" />
diff --git a/app/assets/javascripts/diffs/components/diff_code_quality.vue b/app/assets/javascripts/diffs/components/diff_code_quality.vue
index 5392c631c14..f3f05e3d9d9 100644
--- a/app/assets/javascripts/diffs/components/diff_code_quality.vue
+++ b/app/assets/javascripts/diffs/components/diff_code_quality.vue
@@ -1,27 +1,19 @@
<script>
-import { GlButton, GlIcon } from '@gitlab/ui';
-import { SEVERITY_CLASSES, SEVERITY_ICONS } from '~/ci/reports/codequality_report/constants';
+import { GlButton } from '@gitlab/ui';
import { NEW_CODE_QUALITY_FINDINGS } from '../i18n';
+import DiffCodeQualityItem from './diff_code_quality_item.vue';
export default {
i18n: {
newFindings: NEW_CODE_QUALITY_FINDINGS,
},
- components: { GlButton, GlIcon },
+ components: { GlButton, DiffCodeQualityItem },
props: {
codeQuality: {
type: Array,
required: true,
},
},
- methods: {
- severityClass(severity) {
- return SEVERITY_CLASSES[severity] || SEVERITY_CLASSES.unknown;
- },
- severityIcon(severity) {
- return SEVERITY_ICONS[severity] || SEVERITY_ICONS.unknown;
- },
- },
};
</script>
@@ -37,23 +29,11 @@ export default {
{{ $options.i18n.newFindings }}
</h4>
<ul class="gl-list-style-none gl-mb-0 gl-p-0">
- <li
+ <diff-code-quality-item
v-for="finding in codeQuality"
:key="finding.description"
- class="gl-pt-1 gl-pb-1 gl-font-regular gl-display-flex"
- >
- <span class="gl-mr-3">
- <gl-icon
- :size="12"
- :name="severityIcon(finding.severity)"
- :class="severityClass(finding.severity)"
- class="codequality-severity-icon"
- />
- </span>
- <span>
- <span class="severity-copy">{{ finding.severity }}</span> - {{ finding.description }}
- </span>
- </li>
+ :finding="finding"
+ />
</ul>
<gl-button
data-testid="diff-codequality-close"
diff --git a/app/assets/javascripts/diffs/components/diff_code_quality_item.vue b/app/assets/javascripts/diffs/components/diff_code_quality_item.vue
new file mode 100644
index 00000000000..eede110f46c
--- /dev/null
+++ b/app/assets/javascripts/diffs/components/diff_code_quality_item.vue
@@ -0,0 +1,54 @@
+<script>
+import { GlLink, GlIcon } from '@gitlab/ui';
+import { mapActions } from 'vuex';
+import { SEVERITY_CLASSES, SEVERITY_ICONS } from '~/ci/reports/codequality_report/constants';
+import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
+
+export default {
+ components: { GlLink, GlIcon },
+ mixins: [glFeatureFlagsMixin()],
+ props: {
+ finding: {
+ type: Object,
+ required: true,
+ },
+ },
+ methods: {
+ severityClass(severity) {
+ return SEVERITY_CLASSES[severity] || SEVERITY_CLASSES.unknown;
+ },
+ severityIcon(severity) {
+ return SEVERITY_ICONS[severity] || SEVERITY_ICONS.unknown;
+ },
+ toggleDrawer() {
+ this.setDrawer(this.finding);
+ },
+ ...mapActions('findingsDrawer', ['setDrawer']),
+ },
+};
+</script>
+
+<template>
+ <li class="gl-py-1 gl-font-regular gl-display-flex">
+ <span class="gl-mr-3">
+ <gl-icon
+ :size="12"
+ :name="severityIcon(finding.severity)"
+ :class="severityClass(finding.severity)"
+ class="codequality-severity-icon"
+ />
+ </span>
+ <span
+ v-if="glFeatures.codeQualityInlineDrawer"
+ data-testid="description-button-section"
+ class="gl-display-flex"
+ >
+ <gl-link category="primary" variant="link" @click="toggleDrawer">
+ {{ finding.severity }} - {{ finding.description }}</gl-link
+ >
+ </span>
+ <span v-else data-testid="description-plain-text" class="gl-display-flex">
+ {{ finding.severity }} - {{ finding.description }}
+ </span>
+ </li>
+</template>
diff --git a/app/assets/javascripts/diffs/components/shared/findings_drawer.vue b/app/assets/javascripts/diffs/components/shared/findings_drawer.vue
new file mode 100644
index 00000000000..da880c6f3ca
--- /dev/null
+++ b/app/assets/javascripts/diffs/components/shared/findings_drawer.vue
@@ -0,0 +1,110 @@
+<script>
+import { GlDrawer, GlIcon, GlLink } from '@gitlab/ui';
+import SafeHtml from '~/vue_shared/directives/safe_html';
+import { s__ } from '~/locale';
+import { DRAWER_Z_INDEX } from '~/lib/utils/constants';
+import { SEVERITY_CLASSES, SEVERITY_ICONS } from '~/ci/reports/codequality_report/constants';
+import { getContentWrapperHeight } from '~/lib/utils/dom_utils';
+
+export const i18n = {
+ severity: s__('FindingsDrawer|Severity:'),
+ engine: s__('FindingsDrawer|Engine:'),
+ category: s__('FindingsDrawer|Category:'),
+ otherLocations: s__('FindingsDrawer|Other locations:'),
+};
+
+export default {
+ i18n,
+ components: { GlDrawer, GlIcon, GlLink },
+ directives: {
+ SafeHtml,
+ },
+ props: {
+ drawer: {
+ type: Object,
+ required: true,
+ },
+ },
+ safeHtmlConfig: {
+ ALLOWED_TAGS: ['a', 'h1', 'h2', 'p'],
+ ALLOWED_ATTR: ['href', 'rel'],
+ },
+ computed: {
+ drawerOffsetTop() {
+ return getContentWrapperHeight('.content-wrapper');
+ },
+ },
+ DRAWER_Z_INDEX,
+ methods: {
+ severityClass(severity) {
+ return SEVERITY_CLASSES[severity] || SEVERITY_CLASSES.unknown;
+ },
+ severityIcon(severity) {
+ return SEVERITY_ICONS[severity] || SEVERITY_ICONS.unknown;
+ },
+ },
+};
+</script>
+<template>
+ <gl-drawer
+ :header-height="drawerOffsetTop"
+ :z-index="$options.DRAWER_Z_INDEX"
+ class="findings-drawer"
+ :open="Object.keys(drawer).length !== 0"
+ @close="$emit('close')"
+ >
+ <template #title>
+ <h2 data-testid="findings-drawer-heading" class="gl-font-size-h2 gl-mt-0 gl-mb-0">
+ {{ drawer.description }}
+ </h2>
+ </template>
+
+ <template #default>
+ <ul class="gl-list-style-none gl-border-b-initial gl-mb-0 gl-pb-0!">
+ <li data-testid="findings-drawer-severity" class="gl-mb-4">
+ <span class="gl-font-weight-bold">{{ $options.i18n.severity }}</span>
+ <gl-icon
+ data-testid="findings-drawer-severity-icon"
+ :size="12"
+ :name="severityIcon(drawer.severity)"
+ :class="severityClass(drawer.severity)"
+ class="codequality-severity-icon"
+ />
+
+ {{ drawer.severity }}
+ </li>
+ <li data-testid="findings-drawer-engine" class="gl-mb-4">
+ <span class="gl-font-weight-bold">{{ $options.i18n.engine }}</span>
+ {{ drawer.engineName }}
+ </li>
+ <li data-testid="findings-drawer-category" class="gl-mb-4">
+ <span class="gl-font-weight-bold">{{ $options.i18n.category }}</span>
+ {{ drawer.categories ? drawer.categories[0] : '' }}
+ </li>
+ <li data-testid="findings-drawer-other-locations" class="gl-mb-4">
+ <span class="gl-font-weight-bold gl-mb-3 gl-display-block">{{
+ $options.i18n.otherLocations
+ }}</span>
+ <ul class="gl-pl-6">
+ <li
+ v-for="otherLocation in drawer.otherLocations"
+ :key="otherLocation.path"
+ class="gl-mb-1"
+ >
+ <gl-link
+ data-testid="findings-drawer-other-locations-link"
+ :href="otherLocation.href"
+ >{{ otherLocation.path }}</gl-link
+ >
+ </li>
+ </ul>
+ </li>
+ </ul>
+ <span
+ v-safe-html:[$options.safeHtmlConfig]="drawer.content ? drawer.content.body : ''"
+ data-testid="findings-drawer-body"
+ class="drawer-body gl-display-block gl-px-3 gl-py-0!"
+ ></span>
+ </template>
+ </gl-drawer>
+</template>
diff --git a/app/assets/javascripts/environments/components/environment_actions.vue b/app/assets/javascripts/environments/components/environment_actions.vue
index 74eef50ebaf..d49598d2f21 100644
--- a/app/assets/javascripts/environments/components/environment_actions.vue
+++ b/app/assets/javascripts/environments/components/environment_actions.vue
@@ -1,5 +1,5 @@
<script>
-import { GlDropdown, GlDropdownItem, GlIcon, GlTooltipDirective } from '@gitlab/ui';
+import { GlIcon, GlDisclosureDropdown, GlDisclosureDropdownItem } from '@gitlab/ui';
import { confirmAction } from '~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal';
import { formatTime } from '~/lib/utils/datetime_utility';
import { __, s__, sprintf } from '~/locale';
@@ -7,12 +7,9 @@ import eventHub from '../event_hub';
import actionMutation from '../graphql/mutations/action.mutation.graphql';
export default {
- directives: {
- GlTooltip: GlTooltipDirective,
- },
components: {
- GlDropdown,
- GlDropdownItem,
+ GlDisclosureDropdownItem,
+ GlDisclosureDropdown,
GlIcon,
},
props: {
@@ -36,6 +33,16 @@ export default {
title() {
return __('Deploy to...');
},
+ actionItems() {
+ return this.actions.map((actionItem) => ({
+ text: actionItem.name,
+ action: () => this.onClickAction(actionItem),
+ extraAttrs: {
+ disabled: this.isActionDisabled(actionItem),
+ },
+ ...actionItem,
+ }));
+ },
},
methods: {
async onClickAction(action) {
@@ -48,7 +55,6 @@ export default {
);
const confirmed = await confirmAction(confirmationMessage);
-
if (!confirmed) {
return;
}
@@ -80,30 +86,31 @@ export default {
};
</script>
<template>
- <gl-dropdown
- v-gl-tooltip
+ <gl-disclosure-dropdown
:text="title"
:title="title"
:loading="isLoading"
:aria-label="title"
+ :items="actionItems"
icon="play"
text-sr-only
right
data-container="body"
data-testid="environment-actions-button"
>
- <gl-dropdown-item
- v-for="(action, i) in actions"
- :key="i"
- :disabled="isActionDisabled(action)"
+ <gl-disclosure-dropdown-item
+ v-for="item in actionItems"
+ :key="item.name"
+ :item="item"
data-testid="manual-action-link"
- @click="onClickAction(action)"
>
- <span class="gl-flex-grow-1">{{ action.name }}</span>
- <span v-if="action.scheduledAt" class="gl-text-gray-500 float-right">
- <gl-icon name="clock" />
- {{ remainingTime(action) }}
- </span>
- </gl-dropdown-item>
- </gl-dropdown>
+ <template #list-item>
+ <span class="gl-flex-grow-1">{{ item.text }}</span>
+ <span v-if="item.scheduledAt" class="gl-text-gray-500 float-right">
+ <gl-icon name="clock" />
+ {{ remainingTime(item) }}
+ </span>
+ </template>
+ </gl-disclosure-dropdown-item>
+ </gl-disclosure-dropdown>
</template>
diff --git a/app/assets/javascripts/environments/components/new_environment_item.vue b/app/assets/javascripts/environments/components/new_environment_item.vue
index a945e89393b..f46bd0e3780 100644
--- a/app/assets/javascripts/environments/components/new_environment_item.vue
+++ b/app/assets/javascripts/environments/components/new_environment_item.vue
@@ -270,7 +270,6 @@ export default {
<stop-component
v-if="canStop"
:environment="environment"
- class="gl-z-index-2"
data-track-action="click_button"
data-track-label="environment_stop"
graphql
diff --git a/app/assets/javascripts/graphql_shared/possible_types.json b/app/assets/javascripts/graphql_shared/possible_types.json
index 22629dfb7d8..105a02a021c 100644
--- a/app/assets/javascripts/graphql_shared/possible_types.json
+++ b/app/assets/javascripts/graphql_shared/possible_types.json
@@ -21,7 +21,8 @@
"Epic",
"EpicIssue",
"Issue",
- "MergeRequest"
+ "MergeRequest",
+ "WorkItemWidgetCurrentUserTodos"
],
"DependencyLinkMetadata": [
"NugetDependencyLinkMetadata"
@@ -145,6 +146,7 @@
],
"WorkItemWidget": [
"WorkItemWidgetAssignees",
+ "WorkItemWidgetCurrentUserTodos",
"WorkItemWidgetDescription",
"WorkItemWidgetHealthStatus",
"WorkItemWidgetHierarchy",
diff --git a/app/assets/javascripts/ide/index.js b/app/assets/javascripts/ide/index.js
index 967c83b320f..29c44d2f596 100644
--- a/app/assets/javascripts/ide/index.js
+++ b/app/assets/javascripts/ide/index.js
@@ -72,7 +72,6 @@ export const initLegacyWebIDE = (el, options = {}) => {
environmentsGuidanceAlertDismissed: !parseBoolean(el.dataset.enableEnvironmentsGuidance),
previewMarkdownPath: el.dataset.previewMarkdownPath,
userPreferencesPath: el.dataset.userPreferencesPath,
- learnGitlabSource: parseBoolean(el.dataset.learnGitlabSource),
});
},
beforeDestroy() {
diff --git a/app/assets/javascripts/ide/stores/modules/commit/actions.js b/app/assets/javascripts/ide/stores/modules/commit/actions.js
index 572465f7587..79a8ccf2285 100644
--- a/app/assets/javascripts/ide/stores/modules/commit/actions.js
+++ b/app/assets/javascripts/ide/stores/modules/commit/actions.js
@@ -1,7 +1,6 @@
import { createAlert } from '~/alert';
import { addNumericSuffix } from '~/ide/utils';
import { sprintf, __ } from '~/locale';
-import Tracking from '~/tracking';
import { leftSidebarViews } from '../../../constants';
import eventHub from '../../../eventhub';
import { parseCommitError } from '../../../lib/errors';
@@ -163,10 +162,6 @@ export const commitChanges = ({ commit, state, getters, dispatch, rootState, roo
);
}
- if (rootState.learnGitlabSource) {
- Tracking.event(undefined, 'commit', { label: 'web_ide_learn_gitlab_source' });
- }
-
dispatch('setLastCommitMessage', data);
dispatch('updateCommitMessage', '');
return dispatch('updateFilesAfterCommit', {
diff --git a/app/assets/javascripts/ide/stores/state.js b/app/assets/javascripts/ide/stores/state.js
index 013a0c3ce8f..356bbf28a48 100644
--- a/app/assets/javascripts/ide/stores/state.js
+++ b/app/assets/javascripts/ide/stores/state.js
@@ -32,5 +32,4 @@ export default () => ({
environmentsGuidanceAlertDetected: false,
previewMarkdownPath: '',
userPreferencesPath: '',
- learnGitlabSource: false,
});
diff --git a/app/assets/javascripts/mr_notes/stores/drawer/actions.js b/app/assets/javascripts/mr_notes/stores/drawer/actions.js
new file mode 100644
index 00000000000..4f8c3bb7f20
--- /dev/null
+++ b/app/assets/javascripts/mr_notes/stores/drawer/actions.js
@@ -0,0 +1,5 @@
+import * as types from './mutation_types';
+
+export const setDrawer = ({ commit }, data) => {
+ return commit(types.default.SET_DRAWER, data);
+};
diff --git a/app/assets/javascripts/mr_notes/stores/drawer/getters.js b/app/assets/javascripts/mr_notes/stores/drawer/getters.js
new file mode 100644
index 00000000000..dd61bc900fa
--- /dev/null
+++ b/app/assets/javascripts/mr_notes/stores/drawer/getters.js
@@ -0,0 +1 @@
+export const activeDrawer = (state) => state.activeDrawer;
diff --git a/app/assets/javascripts/mr_notes/stores/drawer/index.js b/app/assets/javascripts/mr_notes/stores/drawer/index.js
new file mode 100644
index 00000000000..c4a7eacb78a
--- /dev/null
+++ b/app/assets/javascripts/mr_notes/stores/drawer/index.js
@@ -0,0 +1,13 @@
+import * as actions from './actions';
+import * as getters from './getters';
+import mutations from './mutations';
+
+export default () => ({
+ namespaced: true,
+ state: {
+ activeDrawer: {},
+ },
+ mutations,
+ actions,
+ getters,
+});
diff --git a/app/assets/javascripts/mr_notes/stores/drawer/mutation_types.js b/app/assets/javascripts/mr_notes/stores/drawer/mutation_types.js
new file mode 100644
index 00000000000..5fe8a9ba20d
--- /dev/null
+++ b/app/assets/javascripts/mr_notes/stores/drawer/mutation_types.js
@@ -0,0 +1,3 @@
+export default {
+ SET_DRAWER: 'SET_DRAWER',
+};
diff --git a/app/assets/javascripts/mr_notes/stores/drawer/mutations.js b/app/assets/javascripts/mr_notes/stores/drawer/mutations.js
new file mode 100644
index 00000000000..eee43f2b316
--- /dev/null
+++ b/app/assets/javascripts/mr_notes/stores/drawer/mutations.js
@@ -0,0 +1,7 @@
+import types from './mutation_types';
+
+export default {
+ [types.SET_DRAWER](state, drawer) {
+ Object.assign(state, { activeDrawer: drawer });
+ },
+};
diff --git a/app/assets/javascripts/mr_notes/stores/index.js b/app/assets/javascripts/mr_notes/stores/index.js
index 7527c685c71..1f8e61beff0 100644
--- a/app/assets/javascripts/mr_notes/stores/index.js
+++ b/app/assets/javascripts/mr_notes/stores/index.js
@@ -4,6 +4,7 @@ import batchCommentsModule from '~/batch_comments/stores/modules/batch_comments'
import diffsModule from '~/diffs/store/modules';
import notesModule from '~/notes/stores/modules';
import mrPageModule from './modules';
+import findingsDrawer from './drawer';
Vue.use(Vuex);
@@ -12,6 +13,7 @@ export const createModules = () => ({
notes: notesModule(),
diffs: diffsModule(),
batchComments: batchCommentsModule(),
+ findingsDrawer: findingsDrawer(),
});
export const createStore = () =>
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index 35cf60a2c24..adadf422284 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -43,6 +43,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
push_frontend_feature_flag(:mr_experience_survey, project)
push_frontend_feature_flag(:realtime_mr_status_change, project)
push_frontend_feature_flag(:saved_replies, current_user)
+ push_frontend_feature_flag(:code_quality_inline_drawer, project)
end
around_action :allow_gitaly_ref_name_caching, only: [:index, :show, :diffs, :discussions]
diff --git a/app/controllers/projects/pipelines_controller.rb b/app/controllers/projects/pipelines_controller.rb
index c3c90f00ade..84eabd3a142 100644
--- a/app/controllers/projects/pipelines_controller.rb
+++ b/app/controllers/projects/pipelines_controller.rb
@@ -9,16 +9,16 @@ class Projects::PipelinesController < Projects::ApplicationController
urgency :low, [
:index, :new, :builds, :show, :failures, :create,
:stage, :retry, :dag, :cancel, :test_report,
- :charts, :config_variables, :destroy, :status
+ :charts, :destroy, :status
]
before_action :disable_query_limiting, only: [:create, :retry]
- before_action :pipeline, except: [:index, :new, :create, :charts, :config_variables]
+ before_action :pipeline, except: [:index, :new, :create, :charts]
before_action :set_pipeline_path, only: [:show]
before_action :authorize_read_pipeline!
before_action :authorize_read_build!, only: [:index, :show]
before_action :authorize_read_ci_cd_analytics!, only: [:charts]
- before_action :authorize_create_pipeline!, only: [:new, :create, :config_variables]
+ before_action :authorize_create_pipeline!, only: [:new, :create]
before_action :authorize_update_pipeline!, only: [:retry, :cancel]
before_action :ensure_pipeline, only: [:show, :downloadable_artifacts]
before_action :reject_if_build_artifacts_size_refreshing!, only: [:destroy]
@@ -45,7 +45,7 @@ class Projects::PipelinesController < Projects::ApplicationController
POLLING_INTERVAL = 10_000
feature_category :continuous_integration, [
- :charts, :show, :config_variables, :stage, :cancel, :retry,
+ :charts, :show, :stage, :cancel, :retry,
:builds, :dag, :failures, :status,
:index, :create, :new, :destroy
]
@@ -216,18 +216,6 @@ class Projects::PipelinesController < Projects::ApplicationController
end
end
- def config_variables
- respond_to do |format|
- format.json do
- # Even if the parameter name is `sha`, it is actually a ref name. We always send `ref` to the endpoint.
- # See: https://gitlab.com/gitlab-org/gitlab/-/issues/389065
- result = Ci::ListConfigVariablesService.new(@project, current_user).execute(params[:sha])
-
- result.nil? ? head(:no_content) : render(json: result)
- end
- end
- end
-
def downloadable_artifacts
render json: Ci::DownloadableArtifactSerializer.new(
project: project,
diff --git a/app/graphql/types/work_items/widget_interface.rb b/app/graphql/types/work_items/widget_interface.rb
index 50f8e4f7d8a..e562312d06e 100644
--- a/app/graphql/types/work_items/widget_interface.rb
+++ b/app/graphql/types/work_items/widget_interface.rb
@@ -19,7 +19,8 @@ module Types
::Types::WorkItems::Widgets::StartAndDueDateType,
::Types::WorkItems::Widgets::MilestoneType,
::Types::WorkItems::Widgets::NotesType,
- ::Types::WorkItems::Widgets::NotificationsType
+ ::Types::WorkItems::Widgets::NotificationsType,
+ ::Types::WorkItems::Widgets::CurrentUserTodosType
].freeze
def self.ce_orphan_types
@@ -47,6 +48,8 @@ module Types
::Types::WorkItems::Widgets::NotesType
when ::WorkItems::Widgets::Notifications
::Types::WorkItems::Widgets::NotificationsType
+ when ::WorkItems::Widgets::CurrentUserTodos
+ ::Types::WorkItems::Widgets::CurrentUserTodosType
else
raise "Unknown GraphQL type for widget #{object}"
end
diff --git a/app/graphql/types/work_items/widgets/current_user_todos_type.rb b/app/graphql/types/work_items/widgets/current_user_todos_type.rb
new file mode 100644
index 00000000000..1c7cdd631e2
--- /dev/null
+++ b/app/graphql/types/work_items/widgets/current_user_todos_type.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+module Types
+ module WorkItems
+ module Widgets
+ # Disabling widget level authorization as it might be too granular
+ # and we already authorize the parent work item
+ # rubocop:disable Graphql/AuthorizeTypes
+ class CurrentUserTodosType < BaseObject
+ graphql_name 'WorkItemWidgetCurrentUserTodos'
+ description 'Represents a todos widget'
+
+ implements Types::WorkItems::WidgetInterface
+ implements Types::CurrentUserTodos
+
+ private
+
+ # Overriden as `Types::CurrentUserTodos` relies on `unpresented` being the Issuable record.
+ def unpresented
+ object.work_item
+ end
+ end
+ # rubocop:enable Graphql/AuthorizeTypes
+ end
+ end
+end
diff --git a/app/helpers/ide_helper.rb b/app/helpers/ide_helper.rb
index 2157b3044eb..a8dbaa4325f 100644
--- a/app/helpers/ide_helper.rb
+++ b/app/helpers/ide_helper.rb
@@ -83,5 +83,3 @@ module IdeHelper
current_user.dismissed_callout?(feature_name: 'web_ide_ci_environments_guidance')
end
end
-
-IdeHelper.prepend_mod_with('IdeHelper')
diff --git a/app/helpers/sidebars_helper.rb b/app/helpers/sidebars_helper.rb
index 56f4187ae42..a37c4e057b3 100644
--- a/app/helpers/sidebars_helper.rb
+++ b/app/helpers/sidebars_helper.rb
@@ -4,6 +4,8 @@ module SidebarsHelper
include MergeRequestsHelper
include Nav::NewDropdownHelper
+ USER_BAR_COUNT_LIMIT = 99
+
def sidebar_tracking_attributes_by_object(object)
sidebar_attributes_for_object(object).fetch(:tracking_attrs, {})
end
@@ -62,10 +64,10 @@ module SidebarsHelper
},
can_sign_out: current_user_menu?(:sign_out),
sign_out_link: destroy_user_session_path,
- assigned_open_issues_count: user.assigned_open_issues_count,
- todos_pending_count: user.todos_pending_count,
+ assigned_open_issues_count: format_user_bar_count(user.assigned_open_issues_count),
+ todos_pending_count: format_user_bar_count(user.todos_pending_count),
issues_dashboard_path: issues_dashboard_path(assignee_username: user.username),
- total_merge_requests_count: user_merge_requests_counts[:total],
+ total_merge_requests_count: format_user_bar_count(user_merge_requests_counts[:total]),
create_new_menu_groups: create_new_menu_groups(group: group, project: project),
merge_request_menu: create_merge_request_menu(user),
projects_path: projects_path,
@@ -292,6 +294,17 @@ module SidebarsHelper
links
end
+
+ # Formats the counts to be shown in the super sidebar's top section (issues, MRs and todos).
+ # We want to avoid printing huge numbers there, so when the count exceeds USER_BAR_COUNT_LIMIT,
+ # we cap it to USER_BAR_COUNT_LIMIT and append a "+" to it.
+ def format_user_bar_count(count)
+ if count > USER_BAR_COUNT_LIMIT
+ "#{USER_BAR_COUNT_LIMIT}+"
+ else
+ count.to_s
+ end
+ end
end
SidebarsHelper.prepend_mod_with('SidebarsHelper')
diff --git a/app/models/group.rb b/app/models/group.rb
index 70199424b8c..8e0c267185d 100644
--- a/app/models/group.rb
+++ b/app/models/group.rb
@@ -201,13 +201,22 @@ class Group < Namespace
end
scope :project_creation_allowed, -> do
- permitted_levels = [
+ project_creation_allowed_on_levels = [
::Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS,
::Gitlab::Access::MAINTAINER_PROJECT_ACCESS,
nil
]
- where(project_creation_level: permitted_levels)
+ # When the value of application_settings.default_project_creation is set to `NO_ONE_PROJECT_ACCESS`,
+ # it means that a `nil` value for `groups.project_creation_level` is telling us:
+ # do not allow project creation in such groups.
+ # ie, `nil` is a placeholder value for inheriting the value from the ApplicationSetting.
+ # So we remove `nil` from the list when the application_setting's value is `NO_ONE_PROJECT_ACCESS`
+ if ::Gitlab::CurrentSettings.default_project_creation == ::Gitlab::Access::NO_ONE_PROJECT_ACCESS
+ project_creation_allowed_on_levels.delete(nil)
+ end
+
+ where(project_creation_level: project_creation_allowed_on_levels)
end
scope :shared_into_ancestors, -> (group) do
diff --git a/app/models/work_items/widget_definition.rb b/app/models/work_items/widget_definition.rb
index 9e8c421d740..9bfdb25ce47 100644
--- a/app/models/work_items/widget_definition.rb
+++ b/app/models/work_items/widget_definition.rb
@@ -29,7 +29,8 @@ module WorkItems
status: 11, # EE-only
requirement_legacy: 12, # EE-only
test_reports: 13, # EE-only
- notifications: 14
+ notifications: 14,
+ current_user_todos: 15
}
def self.available_widgets
diff --git a/app/models/work_items/widgets/current_user_todos.rb b/app/models/work_items/widgets/current_user_todos.rb
new file mode 100644
index 00000000000..61c4fcb453b
--- /dev/null
+++ b/app/models/work_items/widgets/current_user_todos.rb
@@ -0,0 +1,8 @@
+# frozen_string_literal: true
+
+module WorkItems
+ module Widgets
+ class CurrentUserTodos < Base
+ end
+ end
+end
diff --git a/app/services/bulk_imports/create_service.rb b/app/services/bulk_imports/create_service.rb
index 80293771b5f..348280030f4 100644
--- a/app/services/bulk_imports/create_service.rb
+++ b/app/services/bulk_imports/create_service.rb
@@ -45,7 +45,12 @@ module BulkImports
bulk_import = create_bulk_import
- Gitlab::Tracking.event(self.class.name, 'create', label: 'bulk_import_group')
+ Gitlab::Tracking.event(
+ self.class.name,
+ 'create',
+ label: 'bulk_import_group',
+ extra: { source_equals_destination: source_equals_destination? }
+ )
BulkImportWorker.perform_async(bulk_import.id)
@@ -126,6 +131,10 @@ module BulkImports
)
end
+ def source_equals_destination?
+ credentials[:url].starts_with?(Settings.gitlab.base_url)
+ end
+
def validate_destination_full_path(entity_params)
source_type = entity_params[:source_type]
diff --git a/app/services/ci/pipeline_processing/atomic_processing_service.rb b/app/services/ci/pipeline_processing/atomic_processing_service.rb
index a863e63c0e1..4c087d23a53 100644
--- a/app/services/ci/pipeline_processing/atomic_processing_service.rb
+++ b/app/services/ci/pipeline_processing/atomic_processing_service.rb
@@ -97,7 +97,7 @@ module Ci
def status_of_previous_jobs(job)
if job.scheduling_type_dag?
# job uses DAG, get status of all dependent needs
- @collection.status_of_jobs(job.aggregated_needs_names.to_a, dag: true)
+ @collection.status_of_jobs(job.aggregated_needs_names.to_a)
else
# job uses Stages, get status of prior stage
@collection.status_of_jobs_prior_to_stage(job.stage_idx.to_i)
diff --git a/app/services/ci/pipeline_processing/atomic_processing_service/status_collection.rb b/app/services/ci/pipeline_processing/atomic_processing_service/status_collection.rb
index ca3e198cfc7..85646b79254 100644
--- a/app/services/ci/pipeline_processing/atomic_processing_service/status_collection.rb
+++ b/app/services/ci/pipeline_processing/atomic_processing_service/status_collection.rb
@@ -25,7 +25,7 @@ module Ci
# This methods gets composite status of all jobs
def status_of_all
- status_for_array(all_jobs, dag: false)
+ status_for_array(all_jobs)
end
# This methods gets composite status for jobs at a given stage
@@ -33,15 +33,15 @@ module Ci
strong_memoize("status_of_stage_#{stage_position}") do
stage_jobs = all_jobs_grouped_by_stage_position[stage_position].to_a
- status_for_array(stage_jobs.flatten, dag: false)
+ status_for_array(stage_jobs.flatten)
end
end
# This methods gets composite status for jobs with given names
- def status_of_jobs(names, dag:)
+ def status_of_jobs(names)
jobs = all_jobs_by_name.slice(*names)
- status_for_array(jobs.values, dag: dag)
+ status_for_array(jobs.values, dag: true)
end
# This methods gets composite status for jobs before given stage
@@ -50,7 +50,7 @@ module Ci
stage_jobs = all_jobs_grouped_by_stage_position
.select { |position, _| position < stage_position }
- status_for_array(stage_jobs.values.flatten, dag: false)
+ status_for_array(stage_jobs.values.flatten)
end
end
@@ -75,9 +75,9 @@ module Ci
:stage_idx, :processed, :lock_version
].freeze
- def status_for_array(jobs, dag:)
+ def status_for_array(jobs, dag: false)
result = Gitlab::Ci::Status::Composite
- .new(jobs, dag: dag)
+ .new(jobs, dag: dag, project: pipeline.project)
.status
result || 'success'
end
diff --git a/app/views/projects/pipelines/new.html.haml b/app/views/projects/pipelines/new.html.haml
index ee51ee9b0e2..63b44de0d74 100644
--- a/app/views/projects/pipelines/new.html.haml
+++ b/app/views/projects/pipelines/new.html.haml
@@ -7,7 +7,6 @@
#js-new-pipeline{ data: { project_id: @project.id,
pipelines_path: project_pipelines_path(@project),
- config_variables_path: config_variables_namespace_project_pipelines_path(@project.namespace, @project),
default_branch: @project.default_branch,
pipelines_editor_path: project_ci_pipeline_editor_path(@project),
can_view_pipeline_editor: can_view_pipeline_editor?(@project),
diff --git a/app/views/shared/_ref_switcher.html.haml b/app/views/shared/_ref_switcher.html.haml
index fa718a9c907..48633ce0ce7 100644
--- a/app/views/shared/_ref_switcher.html.haml
+++ b/app/views/shared/_ref_switcher.html.haml
@@ -13,8 +13,8 @@
- @options && @options.each do |key, value|
= hidden_field_tag key, value, id: nil
.dropdown
- = dropdown_toggle dropdown_toggle_text, { toggle: "dropdown", selected: dropdown_toggle_text, ref: ref, ref_type: @ref_type, refs_url: refs_project_path(@project, sort: 'updated_desc'), field_name: field_name, submit_form_on_click: true, visit: true, qa_selector: "branches_dropdown", testid: "branches-select" }, { toggle_class: "js-project-refs-dropdown" }
- .dropdown-menu.dropdown-menu-selectable.git-revision-dropdown.dropdown-menu-paging{ class: ("dropdown-menu-right" if local_assigns[:align_right]), data: { qa_selector: "branches_dropdown_content" } }
+ = dropdown_toggle dropdown_toggle_text, { toggle: "dropdown", selected: dropdown_toggle_text, ref: ref, ref_type: @ref_type, refs_url: refs_project_path(@project, sort: 'updated_desc'), field_name: field_name, submit_form_on_click: true, visit: true, testid: "branches-select" }, { toggle_class: "js-project-refs-dropdown" }
+ .dropdown-menu.dropdown-menu-selectable.git-revision-dropdown.dropdown-menu-paging{ class: ("dropdown-menu-right" if local_assigns[:align_right]) }
.dropdown-page-one
= dropdown_title _("Switch branch/tag")
= dropdown_filter _("Search branches and tags")
diff --git a/config/feature_flags/development/ci_simplify_dag_status_calculation_for_processing.yml b/config/feature_flags/development/ci_simplify_dag_status_calculation_for_processing.yml
new file mode 100644
index 00000000000..bde5bce548f
--- /dev/null
+++ b/config/feature_flags/development/ci_simplify_dag_status_calculation_for_processing.yml
@@ -0,0 +1,8 @@
+---
+name: ci_simplify_dag_status_calculation_for_processing
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/115684
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/403005
+milestone: '15.11'
+type: development
+group: group::pipeline authoring
+default_enabled: false
diff --git a/config/feature_flags/development/code_quality_inline_drawer.yml b/config/feature_flags/development/code_quality_inline_drawer.yml
new file mode 100644
index 00000000000..0af4c98ada8
--- /dev/null
+++ b/config/feature_flags/development/code_quality_inline_drawer.yml
@@ -0,0 +1,8 @@
+---
+name: code_quality_inline_drawer
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/114649
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/397037
+milestone: '15.11'
+type: development
+group: group::static analysis
+default_enabled: false
diff --git a/config/routes/pipelines.rb b/config/routes/pipelines.rb
index ef390d7988b..10e0e948c62 100644
--- a/config/routes/pipelines.rb
+++ b/config/routes/pipelines.rb
@@ -7,7 +7,6 @@ resources :pipelines, only: [:index, :new, :create, :show, :destroy] do
scope '(*ref)', constraints: { ref: Gitlab::PathRegex.git_reference_regex } do
get :latest, action: :show, defaults: { latest: true }
end
- get :config_variables
end
member do
diff --git a/db/migrate/20230317162059_add_current_user_todos_work_item_widget.rb b/db/migrate/20230317162059_add_current_user_todos_work_item_widget.rb
new file mode 100644
index 00000000000..4ed1fd6869c
--- /dev/null
+++ b/db/migrate/20230317162059_add_current_user_todos_work_item_widget.rb
@@ -0,0 +1,57 @@
+# frozen_string_literal: true
+
+class AddCurrentUserTodosWorkItemWidget < Gitlab::Database::Migration[2.1]
+ class WorkItemType < MigrationRecord
+ self.table_name = 'work_item_types'
+ end
+
+ class WidgetDefinition < MigrationRecord
+ self.table_name = 'work_item_widget_definitions'
+ end
+
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+ disable_ddl_transaction!
+
+ WIDGET_NAME = 'Current user todos'
+ WIDGET_ENUM_VALUE = 15
+ WORK_ITEM_TYPES = [
+ 'Issue',
+ 'Incident',
+ 'Test Case',
+ 'Requirement',
+ 'Task',
+ 'Objective',
+ 'Key Result'
+ ].freeze
+
+ def up
+ widgets = []
+
+ WORK_ITEM_TYPES.each do |type_name|
+ type = WorkItemType.find_by_name_and_namespace_id(type_name, nil)
+
+ unless type
+ Gitlab::AppLogger.warn("type #{type_name} is missing, not adding widget")
+
+ next
+ end
+
+ widgets << {
+ work_item_type_id: type.id,
+ name: WIDGET_NAME,
+ widget_type: WIDGET_ENUM_VALUE
+ }
+ end
+
+ return if widgets.empty?
+
+ WidgetDefinition.upsert_all(
+ widgets,
+ unique_by: :index_work_item_widget_definitions_on_default_witype_and_name
+ )
+ end
+
+ def down
+ WidgetDefinition.where(name: WIDGET_NAME).delete_all
+ end
+end
diff --git a/db/post_migrate/20230328111013_re_migrate_redis_slot_keys.rb b/db/post_migrate/20230328111013_re_migrate_redis_slot_keys.rb
new file mode 100644
index 00000000000..0d4b31ecc99
--- /dev/null
+++ b/db/post_migrate/20230328111013_re_migrate_redis_slot_keys.rb
@@ -0,0 +1,73 @@
+# frozen_string_literal: true
+
+class ReMigrateRedisSlotKeys < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ def up
+ Gitlab::UsageDataCounters::HLLRedisCounter.known_events.each do |event|
+ if event[:aggregation].to_sym == :daily
+ migrate_daily_aggregated(event)
+ else
+ migrate_weekly_aggregated(event)
+ end
+ end
+ end
+
+ def down
+ # no-op
+ end
+
+ private
+
+ def migrate_daily_aggregated(event)
+ days_back = Gitlab::UsageDataCounters::HLLRedisCounter::DEFAULT_DAILY_KEY_EXPIRY_LENGTH
+ start_date = Date.today - days_back - 1.day
+ end_date = Date.today + 1.day
+
+ (start_date..end_date).each do |date|
+ rename_key(event, date)
+ end
+ end
+
+ def migrate_weekly_aggregated(event)
+ weeks_back = Gitlab::UsageDataCounters::HLLRedisCounter::DEFAULT_WEEKLY_KEY_EXPIRY_LENGTH
+ start_date = (Date.today - weeks_back).beginning_of_week - 1.day
+ end_date = Date.today.end_of_week + 1.day
+
+ (start_date..end_date).step(7).each { |date| rename_key(event, date) }
+ end
+
+ def rename_key(event, date)
+ old_key = old_redis_key(event, date)
+ new_key = Gitlab::UsageDataCounters::HLLRedisCounter.send(:redis_key, event, date)
+
+ # cannot simply rename due to different slots
+ Gitlab::Redis::SharedState.with do |redis|
+ hll_blob = redis.get(old_key)
+
+ break unless hll_blob
+
+ temp_key = new_key + "_#{Time.current.to_i}"
+ ttl = redis.ttl(old_key)
+ ttl = ttl > 0 ? ttl : Gitlab::UsageDataCounters::HLLRedisCounter.send(:expiry, event)
+
+ redis.multi do |multi|
+ multi.set(temp_key, hll_blob, ex: 1.day.to_i)
+ multi.pfmerge(new_key, new_key, temp_key)
+ multi.expire(new_key, ttl)
+ end
+
+ redis.del(temp_key)
+ end
+ end
+
+ def old_redis_key(event, time)
+ name_with_slot = if event[:redis_slot].present?
+ event[:name].to_s.gsub(event[:redis_slot], "{#{event[:redis_slot]}}")
+ else
+ "{#{event[:name]}}"
+ end
+
+ Gitlab::UsageDataCounters::HLLRedisCounter.send(:apply_time_aggregation, name_with_slot, time, event)
+ end
+end
diff --git a/db/schema_migrations/20230317162059 b/db/schema_migrations/20230317162059
new file mode 100644
index 00000000000..9adcabb9aeb
--- /dev/null
+++ b/db/schema_migrations/20230317162059
@@ -0,0 +1 @@
+86f8982c21b25cfc1914304b0083075226e0f8182b66a766a4f354b1b5fc8f7d \ No newline at end of file
diff --git a/db/schema_migrations/20230328111013 b/db/schema_migrations/20230328111013
new file mode 100644
index 00000000000..18b085e1df1
--- /dev/null
+++ b/db/schema_migrations/20230328111013
@@ -0,0 +1 @@
+6acd119e30d05fc794998cd4a80416cb91e11021659eb62ac93590175039a6cf \ No newline at end of file
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 98c9c1755f1..3fd73c8c0d6 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -22318,6 +22318,34 @@ Represents an assignees widget.
| <a id="workitemwidgetassigneescaninvitemembers"></a>`canInviteMembers` | [`Boolean!`](#boolean) | Indicates whether the current user can invite members to the work item's project. |
| <a id="workitemwidgetassigneestype"></a>`type` | [`WorkItemWidgetType`](#workitemwidgettype) | Widget type. |
+### `WorkItemWidgetCurrentUserTodos`
+
+Represents a todos widget.
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="workitemwidgetcurrentusertodostype"></a>`type` | [`WorkItemWidgetType`](#workitemwidgettype) | Widget type. |
+
+#### Fields with arguments
+
+##### `WorkItemWidgetCurrentUserTodos.currentUserTodos`
+
+To-do items for the current user.
+
+Returns [`TodoConnection!`](#todoconnection).
+
+This field returns a [connection](#connections). It accepts the
+four standard [pagination arguments](#connection-pagination-arguments):
+`before: String`, `after: String`, `first: Int`, `last: Int`.
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="workitemwidgetcurrentusertodoscurrentusertodosstate"></a>`state` | [`TodoStateEnum`](#todostateenum) | State of the to-do items. |
+
### `WorkItemWidgetDescription`
Represents a description widget.
@@ -24778,6 +24806,7 @@ Type of a work item widget.
| Value | Description |
| ----- | ----------- |
| <a id="workitemwidgettypeassignees"></a>`ASSIGNEES` | Assignees widget. |
+| <a id="workitemwidgettypecurrent_user_todos"></a>`CURRENT_USER_TODOS` | Current User Todos widget. |
| <a id="workitemwidgettypedescription"></a>`DESCRIPTION` | Description widget. |
| <a id="workitemwidgettypehealth_status"></a>`HEALTH_STATUS` | Health Status widget. |
| <a id="workitemwidgettypehierarchy"></a>`HIERARCHY` | Hierarchy widget. |
@@ -25654,6 +25683,7 @@ Implementations:
- [`EpicIssue`](#epicissue)
- [`Issue`](#issue)
- [`MergeRequest`](#mergerequest)
+- [`WorkItemWidgetCurrentUserTodos`](#workitemwidgetcurrentusertodos)
##### Fields with arguments
@@ -26149,6 +26179,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
Implementations:
- [`WorkItemWidgetAssignees`](#workitemwidgetassignees)
+- [`WorkItemWidgetCurrentUserTodos`](#workitemwidgetcurrentusertodos)
- [`WorkItemWidgetDescription`](#workitemwidgetdescription)
- [`WorkItemWidgetHealthStatus`](#workitemwidgethealthstatus)
- [`WorkItemWidgetHierarchy`](#workitemwidgethierarchy)
diff --git a/doc/architecture/blueprints/database_testing/index.md b/doc/architecture/blueprints/database_testing/index.md
index 21d22574302..4e142a9345c 100644
--- a/doc/architecture/blueprints/database_testing/index.md
+++ b/doc/architecture/blueprints/database_testing/index.md
@@ -10,7 +10,7 @@ participating-stages: []
# Database Testing
-**Notice:** This blueprints has been partially implemented. We still plan to
+**Notice:** This blueprint has been partially implemented. We still plan to
iterate on the tooling. The content below is a historical version of the
blueprint, written prior to incorporating database testing into our development
workflow.
diff --git a/lib/gitlab/ci/status/composite.rb b/lib/gitlab/ci/status/composite.rb
index ed2e29e257f..8e55b414364 100644
--- a/lib/gitlab/ci/status/composite.rb
+++ b/lib/gitlab/ci/status/composite.rb
@@ -8,7 +8,7 @@ module Gitlab
# This class accepts an array of arrays/hashes/or objects
# `with_allow_failure` will be removed when deleting ci_remove_ensure_stage_service
- def initialize(all_jobs, with_allow_failure: true, dag: false)
+ def initialize(all_jobs, with_allow_failure: true, dag: false, project: nil)
unless all_jobs.respond_to?(:pluck)
raise ArgumentError, "all_jobs needs to respond to `.pluck`"
end
@@ -17,6 +17,7 @@ module Gitlab
@status_key = 0
@allow_failure_key = 1 if with_allow_failure
@dag = dag
+ @project = project
consume_all_jobs(all_jobs)
end
@@ -28,11 +29,13 @@ module Gitlab
# based on what statuses are no longer valid based on the
# data set that we have
#
- # This method is used for two cases:
+ # This method is used for three cases:
# 1. When it is called for a stage or a pipeline (with `all_jobs` from all jobs in a stage or a pipeline),
# then, the returned status is assigned to the stage or pipeline.
# 2. When it is called for a job (with `all_jobs` from all previous jobs or all needed jobs),
# then, the returned status is used to determine if the job is processed or not.
+ # 3. When it is called for a group (of jobs that are related),
+ # then, the returned status is used to show the overall status of the group.
# rubocop: disable Metrics/CyclomaticComplexity
# rubocop: disable Metrics/PerceivedComplexity
def status
@@ -42,7 +45,9 @@ module Gitlab
if @dag && any_skipped_or_ignored?
# The DAG job is skipped if one of the needs does not run at all.
'skipped'
- elsif @dag && !only_of?(:success, :failed, :canceled, :skipped, :success_with_warnings)
+ elsif ::Feature.disabled?(:ci_simplify_dag_status_calculation_for_processing, @project) &&
+ @dag &&
+ !only_of?(:success, :failed, :canceled, :skipped, :success_with_warnings)
# DAG is blocked from executing if a dependent is not "complete"
'pending'
elsif only_of?(:skipped, :ignored)
diff --git a/lib/gitlab/database_importers/work_items/base_type_importer.rb b/lib/gitlab/database_importers/work_items/base_type_importer.rb
index 85ac816f712..c6c45ca4d05 100644
--- a/lib/gitlab/database_importers/work_items/base_type_importer.rb
+++ b/lib/gitlab/database_importers/work_items/base_type_importer.rb
@@ -19,7 +19,8 @@ module Gitlab
status: 'Status',
requirement_legacy: 'Requirement legacy',
test_reports: 'Test reports',
- notifications: 'Notifications'
+ notifications: 'Notifications',
+ current_user_todos: "Current user todos"
}.freeze
WIDGETS_FOR_TYPE = {
@@ -34,18 +35,21 @@ module Gitlab
:iteration,
:weight,
:health_status,
- :notifications
+ :notifications,
+ :current_user_todos
],
incident: [
:description,
:hierarchy,
:notes,
- :notifications
+ :notifications,
+ :current_user_todos
],
test_case: [
:description,
:notes,
- :notifications
+ :notifications,
+ :current_user_todos
],
requirement: [
:description,
@@ -53,7 +57,8 @@ module Gitlab
:status,
:requirement_legacy,
:test_reports,
- :notifications
+ :notifications,
+ :current_user_todos
],
task: [
:assignees,
@@ -65,7 +70,8 @@ module Gitlab
:notes,
:iteration,
:weight,
- :notifications
+ :notifications,
+ :current_user_todos
],
objective: [
:assignees,
@@ -76,7 +82,8 @@ module Gitlab
:notes,
:health_status,
:progress,
- :notifications
+ :notifications,
+ :current_user_todos
],
key_result: [
:assignees,
@@ -87,7 +94,8 @@ module Gitlab
:notes,
:health_status,
:progress,
- :notifications
+ :notifications,
+ :current_user_todos
]
}.freeze
diff --git a/lib/gitlab/usage_data_counters/known_events/analytics.yml b/lib/gitlab/usage_data_counters/known_events/analytics.yml
index 0b30308b552..1c390f2d7fd 100644
--- a/lib/gitlab/usage_data_counters/known_events/analytics.yml
+++ b/lib/gitlab/usage_data_counters/known_events/analytics.yml
@@ -1,26 +1,39 @@
- name: users_viewing_analytics_group_devops_adoption
+ redis_slot: analytics
aggregation: weekly
- name: i_analytics_dev_ops_adoption
+ redis_slot: analytics
aggregation: weekly
- name: i_analytics_dev_ops_score
+ redis_slot: analytics
aggregation: weekly
- name: i_analytics_instance_statistics
+ redis_slot: analytics
aggregation: weekly
- name: p_analytics_pipelines
+ redis_slot: analytics
aggregation: weekly
- name: p_analytics_valuestream
+ redis_slot: analytics
aggregation: weekly
- name: p_analytics_repo
+ redis_slot: analytics
aggregation: weekly
- name: i_analytics_cohorts
+ redis_slot: analytics
aggregation: weekly
- name: p_analytics_ci_cd_pipelines
+ redis_slot: analytics
aggregation: weekly
- name: p_analytics_ci_cd_deployment_frequency
+ redis_slot: analytics
aggregation: weekly
- name: p_analytics_ci_cd_lead_time
+ redis_slot: analytics
aggregation: weekly
- name: p_analytics_ci_cd_time_to_restore_service
+ redis_slot: analytics
aggregation: weekly
- name: p_analytics_ci_cd_change_failure_rate
+ redis_slot: analytics
aggregation: weekly
diff --git a/lib/gitlab/usage_data_counters/known_events/ci_templates.yml b/lib/gitlab/usage_data_counters/known_events/ci_templates.yml
index 82c023e6e38..e717679e3dc 100644
--- a/lib/gitlab/usage_data_counters/known_events/ci_templates.yml
+++ b/lib/gitlab/usage_data_counters/known_events/ci_templates.yml
@@ -4,304 +4,455 @@
# Do not edit it manually!
---
- name: p_ci_templates_terraform_base_latest
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_terraform_base
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_dotnet
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_nodejs
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_openshift
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_auto_devops
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_bash
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_rust
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_elixir
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_clojure
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_crystal
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_getting_started
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_code_quality
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_verify_load_performance_testing
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_verify_accessibility
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_verify_failfast
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_verify_browser_performance
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_verify_browser_performance_latest
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_grails
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_security_sast
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_security_dast_runner_validation
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_security_dast_on_demand_scan
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_security_secret_detection
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_security_license_scanning
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_security_coverage_fuzzing_latest
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_security_dast_on_demand_api_scan
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_security_coverage_fuzzing
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_security_api_fuzzing_latest
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_security_secure_binaries
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_security_dast_api
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_security_container_scanning
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_security_dast_latest
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_security_sast_iac
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_security_dependency_scanning
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_security_dast_api_latest
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_security_container_scanning_latest
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_security_api_fuzzing
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_security_dast
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_security_api_discovery
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_security_fortify_fod_sast
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_security_sast_iac_latest
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_qualys_iac_security
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_ios_fastlane
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_composer
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_c
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_python
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_android_fastlane
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_android_latest
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_django
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_maven
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_liquibase
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_flutter
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_workflows_branch_pipelines
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_workflows_mergerequest_pipelines
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_laravel
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_kaniko
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_php
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_packer
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_themekit
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_terraform
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_katalon
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_mono
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_go
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_scala
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_latex
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_android
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_indeni_cloudrail
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_matlab
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_deploy_ecs
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_aws_cf_provision_and_deploy_ec2
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_aws_deploy_ecs
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_gradle
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_chef
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_dast_default_branch_deploy
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_load_performance_testing
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_helm_2to3
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_sast
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_secret_detection
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_license_scanning
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_code_intelligence
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_code_quality
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_deploy_ecs
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_deploy_ec2
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_license_scanning_latest
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_deploy
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_build
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_browser_performance_testing
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_container_scanning
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_container_scanning_latest
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_dependency_scanning_latest
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_test
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_sast_latest
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_sast_iac
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_secret_detection_latest
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_dependency_scanning
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_deploy_latest
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_browser_performance_testing_latest
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_cf_provision
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_build_latest
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_jobs_sast_iac_latest
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_terraform_latest
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_swift
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_pages_jekyll
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_pages_harp
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_pages_octopress
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_pages_brunch
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_pages_doxygen
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_pages_hyde
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_pages_lektor
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_pages_jbake
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_pages_hexo
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_pages_middleman
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_pages_hugo
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_pages_pelican
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_pages_nanoc
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_pages_swaggerui
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_pages_jigsaw
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_pages_metalsmith
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_pages_gatsby
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_pages_html
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_dart
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_docker
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_julia
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_npm
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_dotnet_core
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_5_minute_production_app
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_ruby
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_implicit_auto_devops
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_implicit_jobs_browser_performance_testing
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_implicit_jobs_build
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_implicit_jobs_code_intelligence
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_implicit_jobs_code_quality
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_implicit_jobs_container_scanning
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_implicit_jobs_dast_default_branch_deploy
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_implicit_jobs_dependency_scanning
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_implicit_jobs_deploy
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_implicit_jobs_deploy_ec2
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_implicit_jobs_deploy_ecs
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_implicit_jobs_helm_2to3
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_implicit_jobs_license_scanning
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_implicit_jobs_sast
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_implicit_jobs_secret_detection
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_implicit_jobs_test
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_implicit_security_container_scanning
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_implicit_security_dast
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_implicit_security_dependency_scanning
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_implicit_security_license_scanning
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_implicit_security_sast
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_implicit_security_secret_detection
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_terraform_module_base
+ redis_slot: ci_templates
aggregation: weekly
- name: p_ci_templates_terraform_module
+ redis_slot: ci_templates
aggregation: weekly
diff --git a/lib/gitlab/usage_data_counters/known_events/ci_users.yml b/lib/gitlab/usage_data_counters/known_events/ci_users.yml
index 49757c6e672..6db10366b83 100644
--- a/lib/gitlab/usage_data_counters/known_events/ci_users.yml
+++ b/lib/gitlab/usage_data_counters/known_events/ci_users.yml
@@ -1,4 +1,6 @@
- name: ci_users_executing_deployment_job
+ redis_slot: ci_users
aggregation: weekly
- name: ci_users_executing_verify_environment_job
+ redis_slot: ci_users
aggregation: weekly
diff --git a/lib/gitlab/usage_data_counters/known_events/code_review_events.yml b/lib/gitlab/usage_data_counters/known_events/code_review_events.yml
index db0c0653f63..f64da801c39 100644
--- a/lib/gitlab/usage_data_counters/known_events/code_review_events.yml
+++ b/lib/gitlab/usage_data_counters/known_events/code_review_events.yml
@@ -1,233 +1,345 @@
---
- name: i_code_review_create_note_in_ipynb_diff
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_create_note_in_ipynb_diff_mr
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_create_note_in_ipynb_diff_commit
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_user_create_note_in_ipynb_diff
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_user_create_note_in_ipynb_diff_mr
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_user_create_note_in_ipynb_diff_commit
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_mr_diffs
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_user_single_file_diffs
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_mr_single_file_diffs
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_user_toggled_task_item_status
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_create_mr
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_user_create_mr
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_user_close_mr
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_user_reopen_mr
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_user_approve_mr
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_user_unapprove_mr
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_user_resolve_thread
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_user_unresolve_thread
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_edit_mr_title
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_edit_mr_desc
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_user_merge_mr
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_user_create_mr_comment
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_user_edit_mr_comment
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_user_remove_mr_comment
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_user_create_review_note
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_user_publish_review
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_user_create_multiline_mr_comment
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_user_edit_multiline_mr_comment
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_user_remove_multiline_mr_comment
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_user_add_suggestion
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_user_apply_suggestion
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_user_assigned
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_user_marked_as_draft
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_user_unmarked_as_draft
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_user_review_requested
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_user_approval_rule_added
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_user_approval_rule_deleted
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_user_approval_rule_edited
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_user_vs_code_api_request
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_user_jetbrains_api_request
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_user_gitlab_cli_api_request
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_user_create_mr_from_issue
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_user_mr_discussion_locked
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_user_mr_discussion_unlocked
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_user_time_estimate_changed
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_user_time_spent_changed
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_user_assignees_changed
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_user_reviewers_changed
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_user_milestone_changed
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_user_labels_changed
+ redis_slot: code_review
aggregation: weekly
# Diff settings events
- name: i_code_review_click_diff_view_setting
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_click_single_file_mode_setting
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_click_file_browser_setting
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_click_whitespace_setting
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_diff_view_inline
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_diff_view_parallel
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_file_browser_tree_view
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_file_browser_list_view
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_diff_show_whitespace
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_diff_hide_whitespace
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_diff_single_file
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_diff_multiple_files
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_user_load_conflict_ui
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_user_resolve_conflict
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_user_searches_diff
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_total_suggestions_applied
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_total_suggestions_added
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_user_resolve_thread_in_issue
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_widget_nothing_merge_click_new_file
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_post_merge_delete_branch
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_post_merge_click_revert
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_post_merge_click_cherry_pick
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_post_merge_submit_revert_modal
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_post_merge_submit_cherry_pick_modal
+ redis_slot: code_review
aggregation: weekly
# MR Widget Extensions
## Test Summary
- name: i_code_review_merge_request_widget_test_summary_view
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_test_summary_full_report_clicked
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_test_summary_expand
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_test_summary_expand_success
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_test_summary_expand_warning
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_test_summary_expand_failed
+ redis_slot: code_review
aggregation: weekly
## Accessibility
- name: i_code_review_merge_request_widget_accessibility_view
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_accessibility_full_report_clicked
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_accessibility_expand
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_accessibility_expand_success
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_accessibility_expand_warning
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_accessibility_expand_failed
+ redis_slot: code_review
aggregation: weekly
## Code Quality
- name: i_code_review_merge_request_widget_code_quality_view
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_code_quality_full_report_clicked
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_code_quality_expand
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_code_quality_expand_success
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_code_quality_expand_warning
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_code_quality_expand_failed
+ redis_slot: code_review
aggregation: weekly
## Terraform
- name: i_code_review_merge_request_widget_terraform_view
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_terraform_full_report_clicked
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_terraform_expand
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_terraform_expand_success
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_terraform_expand_warning
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_terraform_expand_failed
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_submit_review_approve
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_submit_review_comment
+ redis_slot: code_review
aggregation: weekly
## License Compliance
- name: i_code_review_merge_request_widget_license_compliance_view
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_license_compliance_full_report_clicked
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_license_compliance_expand
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_license_compliance_expand_success
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_license_compliance_expand_warning
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_license_compliance_expand_failed
+ redis_slot: code_review
aggregation: weekly
## Security Reports
- name: i_code_review_merge_request_widget_security_reports_view
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_security_reports_full_report_clicked
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_security_reports_expand
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_security_reports_expand_success
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_security_reports_expand_warning
+ redis_slot: code_review
aggregation: weekly
- name: i_code_review_merge_request_widget_security_reports_expand_failed
+ redis_slot: code_review
aggregation: weekly
diff --git a/lib/gitlab/usage_data_counters/known_events/common.yml b/lib/gitlab/usage_data_counters/known_events/common.yml
index d3520961665..3314997f873 100644
--- a/lib/gitlab/usage_data_counters/known_events/common.yml
+++ b/lib/gitlab/usage_data_counters/known_events/common.yml
@@ -1,14 +1,19 @@
---
# Compliance category
- name: g_edit_by_web_ide
+ redis_slot: edit
aggregation: daily
- name: g_edit_by_sfe
+ redis_slot: edit
aggregation: daily
- name: g_edit_by_snippet_ide
+ redis_slot: edit
aggregation: daily
- name: g_edit_by_live_preview
+ redis_slot: edit
aggregation: daily
- name: i_search_total
+ redis_slot: search
aggregation: weekly
- name: wiki_action
aggregation: daily
@@ -21,145 +26,209 @@
- name: merge_request_action
aggregation: daily
- name: i_source_code_code_intelligence
+ redis_slot: source_code
aggregation: daily
# Incident management
- name: incident_management_alert_status_changed
+ redis_slot: incident_management
aggregation: weekly
- name: incident_management_alert_assigned
+ redis_slot: incident_management
aggregation: weekly
- name: incident_management_alert_todo
+ redis_slot: incident_management
aggregation: weekly
- name: incident_management_incident_created
+ redis_slot: incident_management
aggregation: weekly
- name: incident_management_incident_reopened
+ redis_slot: incident_management
aggregation: weekly
- name: incident_management_incident_closed
+ redis_slot: incident_management
aggregation: weekly
- name: incident_management_incident_assigned
+ redis_slot: incident_management
aggregation: weekly
- name: incident_management_incident_todo
+ redis_slot: incident_management
aggregation: weekly
- name: incident_management_incident_comment
+ redis_slot: incident_management
aggregation: weekly
- name: incident_management_incident_zoom_meeting
+ redis_slot: incident_management
aggregation: weekly
- name: incident_management_incident_relate
+ redis_slot: incident_management
aggregation: weekly
- name: incident_management_incident_unrelate
+ redis_slot: incident_management
aggregation: weekly
- name: incident_management_incident_change_confidential
+ redis_slot: incident_management
aggregation: weekly
# Incident management timeline events
- name: incident_management_timeline_event_created
+ redis_slot: incident_management
aggregation: weekly
- name: incident_management_timeline_event_edited
+ redis_slot: incident_management
aggregation: weekly
- name: incident_management_timeline_event_deleted
+ redis_slot: incident_management
aggregation: weekly
# Incident management alerts
- name: incident_management_alert_create_incident
+ redis_slot: incident_management
aggregation: weekly
# Testing category
- name: i_testing_test_case_parsed
+ redis_slot: testing
aggregation: weekly
- name: i_testing_test_report_uploaded
+ redis_slot: testing
aggregation: weekly
- name: i_testing_coverage_report_uploaded
+ redis_slot: testing
aggregation: weekly
# Project Management group
- name: g_project_management_issue_title_changed
+ redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_description_changed
+ redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_assignee_changed
+ redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_made_confidential
+ redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_made_visible
+ redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_created
+ redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_closed
+ redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_reopened
+ redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_label_changed
+ redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_milestone_changed
+ redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_cross_referenced
+ redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_moved
+ redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_related
+ redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_unrelated
+ redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_marked_as_duplicate
+ redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_locked
+ redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_unlocked
+ redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_designs_added
+ redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_designs_modified
+ redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_designs_removed
+ redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_due_date_changed
+ redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_design_comments_removed
+ redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_time_estimate_changed
+ redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_time_spent_changed
+ redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_comment_added
+ redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_comment_edited
+ redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_comment_removed
+ redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_cloned
+ redis_slot: project_management
aggregation: daily
# Runner group
- name: g_runner_fleet_read_jobs_statistics
+ redis_slot: runner
aggregation: weekly
# Secrets Management
- name: i_snippets_show
+ redis_slot: snippets
aggregation: weekly
# Terraform
- name: p_terraform_state_api_unique_users
+ redis_slot: terraform
aggregation: weekly
# Pipeline Authoring group
- name: o_pipeline_authoring_unique_users_committing_ciconfigfile
+ redis_slot: pipeline_authoring
aggregation: weekly
- name: o_pipeline_authoring_unique_users_pushing_mr_ciconfigfile
+ redis_slot: pipeline_authoring
aggregation: weekly
- name: i_ci_secrets_management_id_tokens_build_created
+ redis_slot: ci_secrets_management
aggregation: weekly
# Merge request widgets
- name: users_expanding_secure_security_report
+ redis_slot: secure
aggregation: weekly
- name: users_expanding_testing_code_quality_report
+ redis_slot: testing
aggregation: weekly
- name: users_expanding_testing_accessibility_report
+ redis_slot: testing
aggregation: weekly
- name: users_expanding_testing_license_compliance_report
+ redis_slot: testing
aggregation: weekly
- name: users_visiting_testing_license_compliance_full_report
+ redis_slot: testing
aggregation: weekly
- name: users_visiting_testing_manage_license_compliance
+ redis_slot: testing
aggregation: weekly
- name: users_clicking_license_testing_visiting_external_website
+ redis_slot: testing
aggregation: weekly
# Geo group
- name: g_geo_proxied_requests
+ redis_slot: geo
aggregation: daily
# Manage
- name: unique_active_user
aggregation: weekly
# Environments page
- name: users_visiting_environments_pages
+ redis_slot: users
aggregation: weekly
diff --git a/lib/gitlab/usage_data_counters/known_events/container_registry_events.yml b/lib/gitlab/usage_data_counters/known_events/container_registry_events.yml
index aa0f9965fa7..ac40079a6dc 100644
--- a/lib/gitlab/usage_data_counters/known_events/container_registry_events.yml
+++ b/lib/gitlab/usage_data_counters/known_events/container_registry_events.yml
@@ -1,11 +1,16 @@
---
- name: i_container_registry_push_tag_user
aggregation: weekly
+ redis_slot: container_registry
- name: i_container_registry_delete_tag_user
aggregation: weekly
+ redis_slot: container_registry
- name: i_container_registry_push_repository_user
aggregation: weekly
+ redis_slot: container_registry
- name: i_container_registry_delete_repository_user
aggregation: weekly
+ redis_slot: container_registry
- name: i_container_registry_create_repository_user
aggregation: weekly
+ redis_slot: container_registry
diff --git a/lib/gitlab/usage_data_counters/known_events/ecosystem.yml b/lib/gitlab/usage_data_counters/known_events/ecosystem.yml
index 6e4a893d19a..03bbba663c5 100644
--- a/lib/gitlab/usage_data_counters/known_events/ecosystem.yml
+++ b/lib/gitlab/usage_data_counters/known_events/ecosystem.yml
@@ -1,24 +1,35 @@
---
# Ecosystem category
- name: i_ecosystem_jira_service_close_issue
+ redis_slot: ecosystem
aggregation: weekly
- name: i_ecosystem_jira_service_cross_reference
+ redis_slot: ecosystem
aggregation: weekly
- name: i_ecosystem_slack_service_issue_notification
+ redis_slot: ecosystem
aggregation: weekly
- name: i_ecosystem_slack_service_push_notification
+ redis_slot: ecosystem
aggregation: weekly
- name: i_ecosystem_slack_service_deployment_notification
+ redis_slot: ecosystem
aggregation: weekly
- name: i_ecosystem_slack_service_wiki_page_notification
+ redis_slot: ecosystem
aggregation: weekly
- name: i_ecosystem_slack_service_merge_request_notification
+ redis_slot: ecosystem
aggregation: weekly
- name: i_ecosystem_slack_service_note_notification
+ redis_slot: ecosystem
aggregation: weekly
- name: i_ecosystem_slack_service_tag_push_notification
+ redis_slot: ecosystem
aggregation: weekly
- name: i_ecosystem_slack_service_confidential_note_notification
+ redis_slot: ecosystem
aggregation: weekly
- name: i_ecosystem_slack_service_confidential_issue_notification
+ redis_slot: ecosystem
aggregation: weekly
diff --git a/lib/gitlab/usage_data_counters/known_events/error_tracking.yml b/lib/gitlab/usage_data_counters/known_events/error_tracking.yml
index ebfd1b274f9..efed16c11f8 100644
--- a/lib/gitlab/usage_data_counters/known_events/error_tracking.yml
+++ b/lib/gitlab/usage_data_counters/known_events/error_tracking.yml
@@ -1,5 +1,7 @@
---
- name: error_tracking_view_details
+ redis_slot: error_tracking
aggregation: weekly
- name: error_tracking_view_list
+ redis_slot: error_tracking
aggregation: weekly
diff --git a/lib/gitlab/usage_data_counters/known_events/importer_events.yml b/lib/gitlab/usage_data_counters/known_events/importer_events.yml
index 3346c0556d6..a6c90a6c762 100644
--- a/lib/gitlab/usage_data_counters/known_events/importer_events.yml
+++ b/lib/gitlab/usage_data_counters/known_events/importer_events.yml
@@ -1,10 +1,13 @@
---
# Importer events
- name: github_import_project_start
+ redis_slot: import
aggregation: weekly
- name: github_import_project_success
+ redis_slot: import
aggregation: weekly
- name: github_import_project_failure
+ redis_slot: import
aggregation: weekly
- name: github_import_project_cancelled
redis_slot: import
@@ -12,3 +15,4 @@
- name: github_import_project_partially_completed
redis_slot: import
aggregation: weekly
+
diff --git a/lib/gitlab/usage_data_counters/known_events/kubernetes_agent.yml b/lib/gitlab/usage_data_counters/known_events/kubernetes_agent.yml
index b3d1c51c0e7..9703c022ef5 100644
--- a/lib/gitlab/usage_data_counters/known_events/kubernetes_agent.yml
+++ b/lib/gitlab/usage_data_counters/known_events/kubernetes_agent.yml
@@ -1,2 +1,3 @@
- name: agent_users_using_ci_tunnel
+ redis_slot: agent
aggregation: weekly
diff --git a/lib/gitlab/usage_data_counters/known_events/package_events.yml b/lib/gitlab/usage_data_counters/known_events/package_events.yml
index 47cc7f98838..d9797635240 100644
--- a/lib/gitlab/usage_data_counters/known_events/package_events.yml
+++ b/lib/gitlab/usage_data_counters/known_events/package_events.yml
@@ -1,45 +1,67 @@
---
- name: i_package_composer_deploy_token
aggregation: weekly
+ redis_slot: package
- name: i_package_composer_user
aggregation: weekly
+ redis_slot: package
- name: i_package_conan_deploy_token
aggregation: weekly
+ redis_slot: package
- name: i_package_conan_user
aggregation: weekly
+ redis_slot: package
- name: i_package_generic_deploy_token
aggregation: weekly
+ redis_slot: package
- name: i_package_generic_user
aggregation: weekly
+ redis_slot: package
- name: i_package_helm_deploy_token
aggregation: weekly
+ redis_slot: package
- name: i_package_helm_user
aggregation: weekly
+ redis_slot: package
- name: i_package_maven_deploy_token
aggregation: weekly
+ redis_slot: package
- name: i_package_maven_user
aggregation: weekly
+ redis_slot: package
- name: i_package_npm_deploy_token
aggregation: weekly
+ redis_slot: package
- name: i_package_npm_user
aggregation: weekly
+ redis_slot: package
- name: i_package_nuget_deploy_token
aggregation: weekly
+ redis_slot: package
- name: i_package_nuget_user
aggregation: weekly
+ redis_slot: package
- name: i_package_pypi_deploy_token
aggregation: weekly
+ redis_slot: package
- name: i_package_pypi_user
aggregation: weekly
+ redis_slot: package
- name: i_package_rubygems_deploy_token
aggregation: weekly
+ redis_slot: package
- name: i_package_rubygems_user
aggregation: weekly
+ redis_slot: package
- name: i_package_terraform_module_deploy_token
aggregation: weekly
+ redis_slot: package
- name: i_package_terraform_module_user
aggregation: weekly
+ redis_slot: package
- name: i_package_rpm_user
aggregation: weekly
+ redis_slot: package
- name: i_package_rpm_deploy_token
aggregation: weekly
+ redis_slot: package
diff --git a/lib/gitlab/usage_data_counters/known_events/quickactions.yml b/lib/gitlab/usage_data_counters/known_events/quickactions.yml
index 7006173cc59..306ed79ea23 100644
--- a/lib/gitlab/usage_data_counters/known_events/quickactions.yml
+++ b/lib/gitlab/usage_data_counters/known_events/quickactions.yml
@@ -1,127 +1,190 @@
---
- name: i_quickactions_assign_multiple
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_approve
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_unapprove
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_assign_single
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_assign_self
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_assign_reviewer
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_award
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_board_move
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_clone
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_close
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_confidential
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_copy_metadata_merge_request
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_copy_metadata_issue
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_create_merge_request
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_done
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_draft
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_due
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_duplicate
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_estimate
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_label
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_lock
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_merge
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_milestone
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_move
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_promote_to_incident
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_timeline
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_ready
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_reassign
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_reassign_reviewer
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_rebase
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_relabel
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_relate
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_remove_due_date
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_remove_estimate
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_remove_milestone
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_remove_time_spent
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_remove_zoom
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_reopen
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_severity
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_shrug
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_spend_subtract
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_spend_add
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_submit_review
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_subscribe
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_tableflip
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_tag
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_target_branch
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_title
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_todo
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_unassign_specific
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_unassign_all
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_unassign_reviewer
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_unlabel_specific
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_unlabel_all
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_unlock
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_unsubscribe
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_wip
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_zoom
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_link
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_invite_email_single
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_invite_email_multiple
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_add_contacts
+ redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_remove_contacts
+ redis_slot: quickactions
aggregation: weekly
diff --git a/lib/gitlab/usage_data_counters/known_events/work_items.yml b/lib/gitlab/usage_data_counters/known_events/work_items.yml
index a6e5b9e1af5..1f0cc0c8a2e 100644
--- a/lib/gitlab/usage_data_counters/known_events/work_items.yml
+++ b/lib/gitlab/usage_data_counters/known_events/work_items.yml
@@ -1,21 +1,28 @@
---
- name: users_updating_work_item_title
+ redis_slot: users
aggregation: weekly
- name: users_creating_work_items
+ redis_slot: users
aggregation: weekly
- name: users_updating_work_item_dates
+ redis_slot: users
aggregation: weekly
- name: users_updating_work_item_labels
+ redis_slot: users
aggregation: weekly
- name: users_updating_work_item_milestone
+ redis_slot: users
aggregation: weekly
- name: users_updating_work_item_iteration
# The event tracks an EE feature.
# It's added here so it can be aggregated into the CE/EE 'OR' aggregate metrics.
# It will report 0 for CE instances and should not be used with 'AND' aggregators.
+ redis_slot: users
aggregation: weekly
- name: users_updating_weight_estimate
# The event tracks an EE feature.
# It's added here so it can be aggregated into the CE/EE 'OR' aggregate metrics.
# It will report 0 for CE instances and should not be used with 'AND' aggregators.
+ redis_slot: users
aggregation: weekly
diff --git a/lib/tasks/gitlab/assets.rake b/lib/tasks/gitlab/assets.rake
index 0936430a0f2..5d6d395037c 100644
--- a/lib/tasks/gitlab/assets.rake
+++ b/lib/tasks/gitlab/assets.rake
@@ -55,6 +55,9 @@ module Tasks
Digest::SHA256.hexdigest(assets_sha256).tap { |sha256| puts "=> SHA256 generated in #{Time.now - start_time}: #{sha256}" if verbose }
end
+ # Files listed here should match the list in:
+ # .assets-compilation-patterns in .gitlab/ci/rules.gitlab-ci.yml
+ # So we make sure that any impacting changes we do rebuild cache
def self.assets_impacting_compilation
assets_folders = FOSS_ASSET_FOLDERS
assets_folders += EE_ASSET_FOLDERS if ::Gitlab.ee?
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 4360f3a5644..c81ae43e09f 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -4834,6 +4834,9 @@ msgstr ""
msgid "Analytics|No dashboard matches the specified URL path."
msgstr ""
+msgid "Analytics|No results match your query or filter"
+msgstr ""
+
msgid "Analytics|OS"
msgstr ""
@@ -18162,6 +18165,18 @@ msgstr ""
msgid "FindFile|Switch branch/tag"
msgstr ""
+msgid "FindingsDrawer|Category:"
+msgstr ""
+
+msgid "FindingsDrawer|Engine:"
+msgstr ""
+
+msgid "FindingsDrawer|Other locations:"
+msgstr ""
+
+msgid "FindingsDrawer|Severity:"
+msgstr ""
+
msgid "Fingerprint (MD5)"
msgstr ""
diff --git a/qa/qa/page/project/show.rb b/qa/qa/page/project/show.rb
index b89e17910c9..b5fce559496 100644
--- a/qa/qa/page/project/show.rb
+++ b/qa/qa/page/project/show.rb
@@ -9,6 +9,7 @@ module QA
include Page::Component::Breadcrumbs
include Page::Project::SubMenus::Settings
include Page::File::Shared::CommitMessage
+ include ::QA::Page::Component::Dropdown
prepend Mobile::Page::Project::Show if Runtime::Env.mobile_layout?
view 'app/assets/javascripts/repository/components/preview/index.vue' do
@@ -68,11 +69,6 @@ module QA
element :web_ide_button
end
- view 'app/views/shared/_ref_switcher.html.haml' do
- element :branches_dropdown
- element :branches_dropdown_content
- end
-
view 'app/views/projects/blob/viewers/_loading.html.haml' do
element :spinner_placeholder
end
@@ -184,11 +180,8 @@ module QA
end
def switch_to_branch(branch_name)
- find_element(:branches_dropdown).click
-
- within_element(:branches_dropdown_content) do
- click_on branch_name
- end
+ expand_select_list
+ select_item(branch_name)
end
def wait_for_import
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/branch_with_unusual_name_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/branch_with_unusual_name_spec.rb
index b98bb8592d3..679f273d0f4 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/branch_with_unusual_name_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/branch_with_unusual_name_spec.rb
@@ -2,10 +2,7 @@
module QA
RSpec.describe 'Create' do
- describe 'Branch with unusual name', product_group: :source_code, quarantine: {
- issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/364565',
- type: :bug
- } do
+ describe 'Branch with unusual name', product_group: :source_code do
let(:branch_name) { 'unUsually/named#br--anch' }
let(:project) do
Resource::Project.fabricate_via_api! do |resource|
diff --git a/spec/controllers/projects/pipelines_controller_spec.rb b/spec/controllers/projects/pipelines_controller_spec.rb
index 09b703a48d6..fe528719f26 100644
--- a/spec/controllers/projects/pipelines_controller_spec.rb
+++ b/spec/controllers/projects/pipelines_controller_spec.rb
@@ -1311,148 +1311,6 @@ RSpec.describe Projects::PipelinesController, feature_category: :continuous_inte
end
end
- describe 'GET config_variables.json', :use_clean_rails_memory_store_caching do
- include ReactiveCachingHelpers
-
- let(:ci_config) { '' }
- let(:files) { { '.gitlab-ci.yml' => YAML.dump(ci_config) } }
- let(:project) { create(:project, :auto_devops_disabled, :custom_repo, files: files) }
- let(:service) { Ci::ListConfigVariablesService.new(project, user) }
-
- before do
- allow(Ci::ListConfigVariablesService)
- .to receive(:new)
- .and_return(service)
- end
-
- context 'when sending a valid ref' do
- let(:ref) { 'master' }
- let(:ci_config) do
- {
- variables: {
- KEY1: { value: 'val 1', description: 'description 1' }
- },
- test: {
- stage: 'test',
- script: 'echo'
- }
- }
- end
-
- before do
- synchronous_reactive_cache(service)
- end
-
- it 'returns variable list' do
- get_config_variables
-
- expect(response).to have_gitlab_http_status(:ok)
- expect(json_response['KEY1']).to eq({ 'value' => 'val 1', 'description' => 'description 1' })
- end
- end
-
- context 'when sending an invalid ref' do
- let(:ref) { 'invalid-ref' }
-
- before do
- synchronous_reactive_cache(service)
- end
-
- it 'returns empty json' do
- get_config_variables
-
- expect(response).to have_gitlab_http_status(:ok)
- expect(json_response).to eq({})
- end
- end
-
- context 'when sending an invalid config' do
- let(:ref) { 'master' }
- let(:ci_config) do
- {
- variables: {
- KEY1: { value: 'val 1', description: 'description 1' }
- },
- test: {
- stage: 'invalid',
- script: 'echo'
- }
- }
- end
-
- before do
- synchronous_reactive_cache(service)
- end
-
- it 'returns empty result' do
- get_config_variables
-
- expect(response).to have_gitlab_http_status(:ok)
- expect(json_response).to eq({})
- end
- end
-
- context 'when the cache is empty' do
- let(:ref) { 'master' }
- let(:ci_config) do
- {
- variables: {
- KEY1: { value: 'val 1', description: 'description 1' }
- },
- test: {
- stage: 'test',
- script: 'echo'
- }
- }
- end
-
- it 'returns no content' do
- get_config_variables
-
- expect(response).to have_gitlab_http_status(:no_content)
- end
- end
-
- context 'when project uses external project ci config' do
- let(:other_project) { create(:project, :custom_repo, files: other_project_files) }
- let(:other_project_files) { { '.gitlab-ci.yml' => YAML.dump(other_project_ci_config) } }
- let(:ref) { 'master' }
-
- let(:other_project_ci_config) do
- {
- variables: {
- KEY1: { value: 'val 1', description: 'description 1' }
- },
- test: {
- stage: 'test',
- script: 'echo'
- }
- }
- end
-
- before do
- other_project.add_developer(user)
- project.update!(ci_config_path: ".gitlab-ci.yml@#{other_project.full_path}:master")
- synchronous_reactive_cache(service)
- end
-
- it 'returns other project config variables' do
- get_config_variables
-
- expect(response).to have_gitlab_http_status(:ok)
- expect(json_response['KEY1']).to eq({ 'value' => 'val 1', 'description' => 'description 1' })
- end
- end
-
- private
-
- def get_config_variables
- get :config_variables, params: {
- namespace_id: project.namespace, project_id: project, sha: ref
- }, format: :json
- end
- end
-
describe 'GET downloadable_artifacts.json' do
context 'when pipeline is empty' do
let(:pipeline) { create(:ci_empty_pipeline) }
diff --git a/spec/frontend/design_management/pages/index_spec.js b/spec/frontend/design_management/pages/index_spec.js
index 1ddf757eb19..9b6ed37f92d 100644
--- a/spec/frontend/design_management/pages/index_spec.js
+++ b/spec/frontend/design_management/pages/index_spec.js
@@ -100,6 +100,7 @@ describe('Design management index page', () => {
let wrapper;
let fakeApollo;
let moveDesignHandler;
+ let permissionsQueryHandler;
const findDesignCheckboxes = () => wrapper.findAll('.design-checkbox');
const findSelectAllButton = () => wrapper.findByTestId('select-all-designs-button');
@@ -174,14 +175,16 @@ describe('Design management index page', () => {
}
function createComponentWithApollo({
+ permissionsHandler = jest.fn().mockResolvedValue(getPermissionsQueryResponse()),
moveHandler = jest.fn().mockResolvedValue(moveDesignMutationResponse),
}) {
Vue.use(VueApollo);
+ permissionsQueryHandler = permissionsHandler;
moveDesignHandler = moveHandler;
const requestHandlers = [
[getDesignListQuery, jest.fn().mockResolvedValue(designListQueryResponse)],
- [permissionsQuery, jest.fn().mockResolvedValue(getPermissionsQueryResponse())],
+ [permissionsQuery, permissionsQueryHandler],
[moveDesignMutation, moveDesignHandler],
];
@@ -230,13 +233,6 @@ describe('Design management index page', () => {
expect(findDesignUploadButton().exists()).toBe(true);
});
- it('does not render toolbar when there is no permission', () => {
- createComponent({ designs: mockDesigns, allVersions: [mockVersion], createDesign: false });
-
- expect(findDesignToolbarWrapper().exists()).toBe(false);
- expect(findDesignUploadButton().exists()).toBe(false);
- });
-
it('has correct classes applied to design dropzone', () => {
createComponent({ designs: mockDesigns, allVersions: [mockVersion] });
expect(dropzoneClasses()).toContain('design-list-item');
@@ -744,6 +740,17 @@ describe('Design management index page', () => {
});
});
+ describe('when there is no permission to create a design', () => {
+ beforeEach(() => {
+ createComponent({ designs: mockDesigns, allVersions: [mockVersion], createDesign: false });
+ });
+
+ it("doesn't render the design toolbar and dropzone", () => {
+ expect(findToolbar().exists()).toBe(false);
+ expect(findDropzoneWrapper().exists()).toBe(false);
+ });
+ });
+
describe('with mocked Apollo client', () => {
it('has a design with id 1 as a first one', async () => {
createComponentWithApollo({});
@@ -819,5 +826,17 @@ describe('Design management index page', () => {
'Something went wrong when reordering designs. Please try again',
);
});
+
+ it("doesn't render the design toolbar and dropzone if the user can't edit", async () => {
+ createComponentWithApollo({
+ permissionsHandler: jest.fn().mockResolvedValue(getPermissionsQueryResponse(false)),
+ });
+
+ await waitForPromises();
+
+ expect(permissionsQueryHandler).toHaveBeenCalled();
+ expect(findToolbar().exists()).toBe(false);
+ expect(findDropzoneWrapper().exists()).toBe(false);
+ });
});
});
diff --git a/spec/frontend/diffs/components/app_spec.js b/spec/frontend/diffs/components/app_spec.js
index 06995706a2b..545ba4a0e04 100644
--- a/spec/frontend/diffs/components/app_spec.js
+++ b/spec/frontend/diffs/components/app_spec.js
@@ -11,6 +11,7 @@ import CommitWidget from '~/diffs/components/commit_widget.vue';
import CompareVersions from '~/diffs/components/compare_versions.vue';
import DiffFile from '~/diffs/components/diff_file.vue';
import NoChanges from '~/diffs/components/no_changes.vue';
+import findingsDrawer from '~/diffs/components/shared/findings_drawer.vue';
import TreeList from '~/diffs/components/tree_list.vue';
import CollapsedFilesWarning from '~/diffs/components/collapsed_files_warning.vue';
@@ -741,4 +742,20 @@ describe('diffs/components/app', () => {
);
});
});
+
+ describe('findings-drawer', () => {
+ it('does not render findings-drawer when codeQualityInlineDrawer flag is off', () => {
+ createComponent();
+ expect(wrapper.findComponent(findingsDrawer).exists()).toBe(false);
+ });
+
+ it('does render findings-drawer when codeQualityInlineDrawer flag is on', () => {
+ createComponent({}, () => {}, {
+ glFeatures: {
+ codeQualityInlineDrawer: true,
+ },
+ });
+ expect(wrapper.findComponent(findingsDrawer).exists()).toBe(true);
+ });
+ });
});
diff --git a/spec/frontend/diffs/components/diff_code_quality_item_spec.js b/spec/frontend/diffs/components/diff_code_quality_item_spec.js
new file mode 100644
index 00000000000..be9fb61a77d
--- /dev/null
+++ b/spec/frontend/diffs/components/diff_code_quality_item_spec.js
@@ -0,0 +1,66 @@
+import { GlIcon, GlLink } from '@gitlab/ui';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import DiffCodeQualityItem from '~/diffs/components/diff_code_quality_item.vue';
+import { SEVERITY_CLASSES, SEVERITY_ICONS } from '~/ci/reports/codequality_report/constants';
+import { multipleFindingsArr } from '../mock_data/diff_code_quality';
+
+let wrapper;
+
+const findIcon = () => wrapper.findComponent(GlIcon);
+const findButton = () => wrapper.findComponent(GlLink);
+const findDescriptionPlainText = () => wrapper.findByTestId('description-plain-text');
+const findDescriptionLinkSection = () => wrapper.findByTestId('description-button-section');
+
+describe('DiffCodeQuality', () => {
+ const createWrapper = ({ glFeatures = {} } = {}) => {
+ return shallowMountExtended(DiffCodeQualityItem, {
+ propsData: {
+ finding: multipleFindingsArr[0],
+ },
+ provide: {
+ glFeatures,
+ },
+ });
+ };
+
+ it('shows icon for given degradation', () => {
+ wrapper = createWrapper();
+ expect(findIcon().exists()).toBe(true);
+
+ expect(findIcon().attributes()).toMatchObject({
+ class: `codequality-severity-icon ${SEVERITY_CLASSES[multipleFindingsArr[0].severity]}`,
+ name: SEVERITY_ICONS[multipleFindingsArr[0].severity],
+ size: '12',
+ });
+ });
+
+ describe('with codeQualityInlineDrawer flag false', () => {
+ it('should render severity + description in plain text', () => {
+ wrapper = createWrapper({
+ glFeatures: {
+ codeQualityInlineDrawer: false,
+ },
+ });
+ expect(findDescriptionPlainText().text()).toContain(multipleFindingsArr[0].severity);
+ expect(findDescriptionPlainText().text()).toContain(multipleFindingsArr[0].description);
+ });
+ });
+
+ describe('with codeQualityInlineDrawer flag true', () => {
+ beforeEach(() => {
+ wrapper = createWrapper({
+ glFeatures: {
+ codeQualityInlineDrawer: true,
+ },
+ });
+ });
+
+ it('should render severity as plain text', () => {
+ expect(findDescriptionLinkSection().text()).toContain(multipleFindingsArr[0].severity);
+ });
+
+ it('should render button with description text', () => {
+ expect(findButton().text()).toContain(multipleFindingsArr[0].description);
+ });
+ });
+});
diff --git a/spec/frontend/diffs/components/diff_code_quality_spec.js b/spec/frontend/diffs/components/diff_code_quality_spec.js
index e5ca90eb7c8..9ecfb62e1c5 100644
--- a/spec/frontend/diffs/components/diff_code_quality_spec.js
+++ b/spec/frontend/diffs/components/diff_code_quality_spec.js
@@ -1,13 +1,12 @@
-import { GlIcon } from '@gitlab/ui';
import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper';
import DiffCodeQuality from '~/diffs/components/diff_code_quality.vue';
-import { SEVERITY_CLASSES, SEVERITY_ICONS } from '~/ci/reports/codequality_report/constants';
+import DiffCodeQualityItem from '~/diffs/components/diff_code_quality_item.vue';
import { NEW_CODE_QUALITY_FINDINGS } from '~/diffs/i18n';
import { multipleFindingsArr } from '../mock_data/diff_code_quality';
let wrapper;
-const findIcon = () => wrapper.findComponent(GlIcon);
+const diffItems = () => wrapper.findAllComponents(DiffCodeQualityItem);
const findHeading = () => wrapper.findByTestId(`diff-codequality-findings-heading`);
describe('DiffCodeQuality', () => {
@@ -28,37 +27,12 @@ describe('DiffCodeQuality', () => {
expect(wrapper.emitted('hideCodeQualityFindings').length).toBe(1);
});
- it('renders heading and correct amount of list items for codequality array and their description', async () => {
- wrapper = createWrapper(multipleFindingsArr);
- expect(findHeading().text()).toEqual(NEW_CODE_QUALITY_FINDINGS);
-
- const listItems = wrapper.findAll('li');
- expect(wrapper.findAll('li').length).toBe(5);
+ it('renders heading and correct amount of list items for codequality array and their description', () => {
+ wrapper = createWrapper(multipleFindingsArr, shallowMountExtended);
- listItems.wrappers.map((e, i) => {
- return expect(e.text()).toContain(
- `${multipleFindingsArr[i].severity} - ${multipleFindingsArr[i].description}`,
- );
- });
- });
-
- it.each`
- severity
- ${'info'}
- ${'minor'}
- ${'major'}
- ${'critical'}
- ${'blocker'}
- ${'unknown'}
- `('shows icon for $severity degradation', ({ severity }) => {
- wrapper = createWrapper([{ severity }], shallowMountExtended);
-
- expect(findIcon().exists()).toBe(true);
+ expect(findHeading().text()).toEqual(NEW_CODE_QUALITY_FINDINGS);
- expect(findIcon().attributes()).toMatchObject({
- class: `codequality-severity-icon ${SEVERITY_CLASSES[severity]}`,
- name: SEVERITY_ICONS[severity],
- size: '12',
- });
+ expect(diffItems()).toHaveLength(multipleFindingsArr.length);
+ expect(diffItems().at(0).props().finding).toEqual(multipleFindingsArr[0]);
});
});
diff --git a/spec/frontend/diffs/components/shared/__snapshots__/findings_drawer_spec.js.snap b/spec/frontend/diffs/components/shared/__snapshots__/findings_drawer_spec.js.snap
new file mode 100644
index 00000000000..ab330ffbb38
--- /dev/null
+++ b/spec/frontend/diffs/components/shared/__snapshots__/findings_drawer_spec.js.snap
@@ -0,0 +1,126 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`FindingsDrawer matches the snapshot 1`] = `
+<gl-drawer-stub
+ class="findings-drawer"
+ headerheight=""
+ open="true"
+ variant="default"
+ zindex="252"
+>
+ <h2
+ class="gl-font-size-h2 gl-mt-0 gl-mb-0"
+ data-testid="findings-drawer-heading"
+ >
+
+ Unused method argument - \`c\`. If it's necessary, use \`_\` or \`_c\` as an argument name to indicate that it won't be used.
+
+ </h2>
+ <ul
+ class="gl-list-style-none gl-border-b-initial gl-mb-0 gl-pb-0!"
+ >
+ <li
+ class="gl-mb-4"
+ data-testid="findings-drawer-severity"
+ >
+ <span
+ class="gl-font-weight-bold"
+ >
+ Severity:
+ </span>
+
+ <gl-icon-stub
+ class="codequality-severity-icon gl-text-orange-200"
+ data-testid="findings-drawer-severity-icon"
+ name="severity-low"
+ size="12"
+ />
+
+
+ minor
+
+ </li>
+
+ <li
+ class="gl-mb-4"
+ data-testid="findings-drawer-engine"
+ >
+ <span
+ class="gl-font-weight-bold"
+ >
+ Engine:
+ </span>
+
+ testengine name
+
+ </li>
+
+ <li
+ class="gl-mb-4"
+ data-testid="findings-drawer-category"
+ >
+ <span
+ class="gl-font-weight-bold"
+ >
+ Category:
+ </span>
+
+ testcategory 1
+
+ </li>
+
+ <li
+ class="gl-mb-4"
+ data-testid="findings-drawer-other-locations"
+ >
+ <span
+ class="gl-font-weight-bold gl-mb-3 gl-display-block"
+ >
+ Other locations:
+ </span>
+
+ <ul
+ class="gl-pl-6"
+ >
+ <li
+ class="gl-mb-1"
+ >
+ <gl-link-stub
+ data-testid="findings-drawer-other-locations-link"
+ href="http://testlink.com"
+ >
+ testpath
+ </gl-link-stub>
+ </li>
+ <li
+ class="gl-mb-1"
+ >
+ <gl-link-stub
+ data-testid="findings-drawer-other-locations-link"
+ href="http://testlink.com"
+ >
+ testpath 1
+ </gl-link-stub>
+ </li>
+ <li
+ class="gl-mb-1"
+ >
+ <gl-link-stub
+ data-testid="findings-drawer-other-locations-link"
+ href="http://testlink.com"
+ >
+ testpath2
+ </gl-link-stub>
+ </li>
+ </ul>
+ </li>
+ </ul>
+
+ <span
+ class="drawer-body gl-display-block gl-px-3 gl-py-0!"
+ data-testid="findings-drawer-body"
+ >
+ Duplicated Code Duplicated code
+ </span>
+</gl-drawer-stub>
+`;
diff --git a/spec/frontend/diffs/components/shared/findings_drawer_spec.js b/spec/frontend/diffs/components/shared/findings_drawer_spec.js
new file mode 100644
index 00000000000..0af6e0f0e96
--- /dev/null
+++ b/spec/frontend/diffs/components/shared/findings_drawer_spec.js
@@ -0,0 +1,19 @@
+import FindingsDrawer from '~/diffs/components/shared/findings_drawer.vue';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import mockFinding from '../../mock_data/findings_drawer';
+
+let wrapper;
+describe('FindingsDrawer', () => {
+ const createWrapper = () => {
+ return shallowMountExtended(FindingsDrawer, {
+ propsData: {
+ drawer: mockFinding,
+ },
+ });
+ };
+
+ it('matches the snapshot', () => {
+ wrapper = createWrapper();
+ expect(wrapper.element).toMatchSnapshot();
+ });
+});
diff --git a/spec/frontend/diffs/create_diffs_store.js b/spec/frontend/diffs/create_diffs_store.js
index 307ebdaa4ac..92f38858ca5 100644
--- a/spec/frontend/diffs/create_diffs_store.js
+++ b/spec/frontend/diffs/create_diffs_store.js
@@ -3,6 +3,7 @@ import Vuex from 'vuex';
import batchCommentsModule from '~/batch_comments/stores/modules/batch_comments';
import diffsModule from '~/diffs/store/modules';
import notesModule from '~/notes/stores/modules';
+import findingsDrawer from '~/mr_notes/stores/drawer';
Vue.use(Vuex);
@@ -18,6 +19,7 @@ export default function createDiffsStore() {
diffs: diffsModule(),
notes: notesModule(),
batchComments: batchCommentsModule(),
+ findingsDrawer: findingsDrawer(),
},
});
}
diff --git a/spec/frontend/diffs/mock_data/diff_code_quality.js b/spec/frontend/diffs/mock_data/diff_code_quality.js
index 7558592f6a4..29f16da8d89 100644
--- a/spec/frontend/diffs/mock_data/diff_code_quality.js
+++ b/spec/frontend/diffs/mock_data/diff_code_quality.js
@@ -24,6 +24,11 @@ export const multipleFindingsArr = [
description: 'mocked blocker Issue',
line: 3,
},
+ {
+ severity: 'unknown',
+ description: 'mocked unknown Issue',
+ line: 3,
+ },
];
export const fiveFindings = {
diff --git a/spec/frontend/diffs/mock_data/findings_drawer.js b/spec/frontend/diffs/mock_data/findings_drawer.js
new file mode 100644
index 00000000000..d7e7e957c83
--- /dev/null
+++ b/spec/frontend/diffs/mock_data/findings_drawer.js
@@ -0,0 +1,21 @@
+export default {
+ line: 7,
+ description:
+ "Unused method argument - `c`. If it's necessary, use `_` or `_c` as an argument name to indicate that it won't be used.",
+ severity: 'minor',
+ engineName: 'testengine name',
+ categories: ['testcategory 1', 'testcategory 2'],
+ content: {
+ body: 'Duplicated Code Duplicated code',
+ },
+ location: {
+ path: 'workhorse/config_test.go',
+ lines: { begin: 221, end: 284 },
+ },
+ otherLocations: [
+ { path: 'testpath', href: 'http://testlink.com' },
+ { path: 'testpath 1', href: 'http://testlink.com' },
+ { path: 'testpath2', href: 'http://testlink.com' },
+ ],
+ type: 'issue',
+};
diff --git a/spec/frontend/environments/environment_actions_spec.js b/spec/frontend/environments/environment_actions_spec.js
index 3c9b4144e45..dcfefbb2072 100644
--- a/spec/frontend/environments/environment_actions_spec.js
+++ b/spec/frontend/environments/environment_actions_spec.js
@@ -1,14 +1,8 @@
-import { GlDropdown, GlDropdownItem, GlLoadingIcon, GlIcon } from '@gitlab/ui';
-import { shallowMount, mount } from '@vue/test-utils';
-import Vue, { nextTick } from 'vue';
-import VueApollo from 'vue-apollo';
+import { GlDisclosureDropdown, GlDisclosureDropdownItem, GlIcon } from '@gitlab/ui';
+import { mount } from '@vue/test-utils';
import { TEST_HOST } from 'helpers/test_constants';
-import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import EnvironmentActions from '~/environments/components/environment_actions.vue';
-import eventHub from '~/environments/event_hub';
-import actionMutation from '~/environments/graphql/mutations/action.mutation.graphql';
import { confirmAction } from '~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal';
-import createMockApollo from 'helpers/mock_apollo_helper';
jest.mock('~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal');
@@ -29,15 +23,9 @@ const expiredJobAction = {
describe('EnvironmentActions Component', () => {
let wrapper;
- const findEnvironmentActionsButton = () =>
- wrapper.find('[data-testid="environment-actions-button"]');
-
- function createComponent(props, { mountFn = shallowMount, options = {} } = {}) {
- wrapper = mountFn(EnvironmentActions, {
+ function createComponent(props, { options = {} } = {}) {
+ wrapper = mount(EnvironmentActions, {
propsData: { actions: [], ...props },
- directives: {
- GlTooltip: createMockDirective('gl-tooltip'),
- },
...options,
});
}
@@ -46,9 +34,10 @@ describe('EnvironmentActions Component', () => {
return createComponent({ actions: [scheduledJobAction, expiredJobAction] }, opts);
}
+ const findDropdownItems = () => wrapper.findAllComponents(GlDisclosureDropdownItem);
const findDropdownItem = (action) => {
- const buttons = wrapper.findAllComponents(GlDropdownItem);
- return buttons.filter((button) => button.text().startsWith(action.name)).at(0);
+ const items = findDropdownItems();
+ return items.filter((item) => item.text().startsWith(action.name)).at(0);
};
afterEach(() => {
@@ -56,19 +45,15 @@ describe('EnvironmentActions Component', () => {
});
it('should render a dropdown button with 2 icons', () => {
- createComponent({}, { mountFn: mount });
- expect(wrapper.findComponent(GlDropdown).findAllComponents(GlIcon).length).toBe(2);
- });
-
- it('should render a dropdown button with aria-label description', () => {
createComponent();
- expect(wrapper.findComponent(GlDropdown).attributes('aria-label')).toBe('Deploy to...');
+ expect(wrapper.findComponent(GlDisclosureDropdown).findAllComponents(GlIcon).length).toBe(2);
});
- it('should render a tooltip', () => {
+ it('should render a dropdown button with aria-label description', () => {
createComponent();
- const tooltip = getBinding(findEnvironmentActionsButton().element, 'gl-tooltip');
- expect(tooltip).toBeDefined();
+ expect(wrapper.findComponent(GlDisclosureDropdown).attributes('aria-label')).toBe(
+ 'Deploy to...',
+ );
});
describe('manual actions', () => {
@@ -93,96 +78,31 @@ describe('EnvironmentActions Component', () => {
});
it('should render a dropdown with the provided list of actions', () => {
- expect(wrapper.findAllComponents(GlDropdownItem)).toHaveLength(actions.length);
+ expect(findDropdownItems()).toHaveLength(actions.length);
});
it("should render a disabled action when it's not playable", () => {
- const dropdownItems = wrapper.findAllComponents(GlDropdownItem);
+ const dropdownItems = findDropdownItems();
const lastDropdownItem = dropdownItems.at(dropdownItems.length - 1);
- expect(lastDropdownItem.attributes('disabled')).toBe('true');
+ expect(lastDropdownItem.find('button').attributes('disabled')).toBe('disabled');
});
});
describe('scheduled jobs', () => {
- let emitSpy;
-
- const clickAndConfirm = async ({ confirm = true } = {}) => {
- confirmAction.mockResolvedValueOnce(confirm);
-
- findDropdownItem(scheduledJobAction).vm.$emit('click');
- await nextTick();
- };
-
beforeEach(() => {
- emitSpy = jest.fn();
- eventHub.$on('postAction', emitSpy);
jest.spyOn(Date, 'now').mockImplementation(() => new Date('2063-04-04T00:42:00Z').getTime());
});
- describe('when postAction event is confirmed', () => {
- beforeEach(async () => {
- createComponentWithScheduledJobs({ mountFn: mount });
- clickAndConfirm();
- });
-
- it('emits postAction event', () => {
- expect(confirmAction).toHaveBeenCalled();
- expect(emitSpy).toHaveBeenCalledWith({ endpoint: scheduledJobAction.playPath });
- });
-
- it('should render a dropdown button with a loading icon', () => {
- expect(wrapper.findComponent(GlLoadingIcon).isVisible()).toBe(true);
- });
- });
-
- describe('when postAction event is denied', () => {
- beforeEach(async () => {
- createComponentWithScheduledJobs({ mountFn: mount });
- clickAndConfirm({ confirm: false });
- });
-
- it('does not emit postAction event if confirmation is cancelled', () => {
- expect(confirmAction).toHaveBeenCalled();
- expect(emitSpy).not.toHaveBeenCalled();
- });
- });
-
it('displays the remaining time in the dropdown', () => {
+ confirmAction.mockResolvedValueOnce(true);
createComponentWithScheduledJobs();
expect(findDropdownItem(scheduledJobAction).text()).toContain('24:00:00');
});
it('displays 00:00:00 for expired jobs in the dropdown', () => {
+ confirmAction.mockResolvedValueOnce(true);
createComponentWithScheduledJobs();
expect(findDropdownItem(expiredJobAction).text()).toContain('00:00:00');
});
});
-
- describe('graphql', () => {
- Vue.use(VueApollo);
-
- const action = {
- name: 'bar',
- play_path: 'https://gitlab.com/play',
- };
-
- let mockApollo;
-
- beforeEach(() => {
- mockApollo = createMockApollo();
- createComponent(
- { actions: [action], graphql: true },
- { options: { apolloProvider: mockApollo } },
- );
- });
-
- it('should trigger a graphql mutation on click', () => {
- jest.spyOn(mockApollo.defaultClient, 'mutate');
- findDropdownItem(action).vm.$emit('click');
- expect(mockApollo.defaultClient.mutate).toHaveBeenCalledWith({
- mutation: actionMutation,
- variables: { action },
- });
- });
- });
});
diff --git a/spec/frontend/environments/new_environment_item_spec.js b/spec/frontend/environments/new_environment_item_spec.js
index b2088ad410b..89a9ca725ba 100644
--- a/spec/frontend/environments/new_environment_item_spec.js
+++ b/spec/frontend/environments/new_environment_item_spec.js
@@ -7,6 +7,7 @@ import { stubTransition } from 'helpers/stub_transition';
import { formatDate, getTimeago } from '~/lib/utils/datetime_utility';
import { __, s__, sprintf } from '~/locale';
import EnvironmentItem from '~/environments/components/new_environment_item.vue';
+import EnvironmentActions from '~/environments/components/environment_actions.vue';
import Deployment from '~/environments/components/deployment.vue';
import DeployBoardWrapper from '~/environments/components/deploy_board_wrapper.vue';
import KubernetesOverview from '~/environments/components/kubernetes_overview.vue';
@@ -30,6 +31,7 @@ describe('~/environments/components/new_environment_item.vue', () => {
});
const findDeployment = () => wrapper.findComponent(Deployment);
+ const findActions = () => wrapper.findComponent(EnvironmentActions);
const findKubernetesOverview = () => wrapper.findComponent(KubernetesOverview);
const expandCollapsedSection = async () => {
@@ -124,9 +126,7 @@ describe('~/environments/components/new_environment_item.vue', () => {
it('shows a dropdown if there are actions to perform', () => {
wrapper = createWrapper({ apolloProvider: createApolloProvider() });
- const actions = wrapper.findByRole('button', { name: __('Deploy to...') });
-
- expect(actions.exists()).toBe(true);
+ expect(findActions().exists()).toBe(true);
});
it('does not show a dropdown if there are no actions to perform', () => {
@@ -140,17 +140,15 @@ describe('~/environments/components/new_environment_item.vue', () => {
},
});
- const actions = wrapper.findByRole('button', { name: __('Deploy to...') });
-
- expect(actions.exists()).toBe(false);
+ expect(findActions().exists()).toBe(false);
});
it('passes all the actions down to the action component', () => {
wrapper = createWrapper({ apolloProvider: createApolloProvider() });
- const action = wrapper.findByRole('menuitem', { name: 'deploy-staging' });
-
- expect(action.exists()).toBe(true);
+ expect(findActions().props('actions')).toMatchObject(
+ resolvedEnvironment.lastDeployment.manualActions,
+ );
});
});
diff --git a/spec/frontend/ide/stores/modules/commit/actions_spec.js b/spec/frontend/ide/stores/modules/commit/actions_spec.js
index 872aa9b6e6b..3eaff92d321 100644
--- a/spec/frontend/ide/stores/modules/commit/actions_spec.js
+++ b/spec/frontend/ide/stores/modules/commit/actions_spec.js
@@ -1,7 +1,6 @@
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import testAction from 'helpers/vuex_action_helper';
-import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
import { file } from 'jest/ide/helpers';
import { commitActionTypes, PERMISSION_CREATE_MR } from '~/ide/constants';
import eventHub from '~/ide/eventhub';
@@ -40,14 +39,12 @@ describe('IDE commit module actions', () => {
let mock;
let store;
let router;
- let trackingSpy;
beforeEach(() => {
store = createStore();
router = createRouter(store);
gon.api_version = 'v1';
mock = new MockAdapter(axios);
- trackingSpy = mockTracking(undefined, undefined, jest.spyOn);
jest.spyOn(router, 'push').mockImplementation();
mock
@@ -56,7 +53,6 @@ describe('IDE commit module actions', () => {
});
afterEach(() => {
- unmockTracking();
mock.restore();
});
@@ -426,28 +422,6 @@ describe('IDE commit module actions', () => {
});
});
});
-
- describe('learnGitlabSource', () => {
- describe('learnGitlabSource is true', () => {
- it('tracks commit', async () => {
- store.state.learnGitlabSource = true;
-
- await store.dispatch('commit/commitChanges');
-
- expect(trackingSpy).toHaveBeenCalledWith(undefined, 'commit', {
- label: 'web_ide_learn_gitlab_source',
- });
- });
- });
-
- describe('learnGitlabSource is false', () => {
- it('does not track commit', async () => {
- await store.dispatch('commit/commitChanges');
-
- expect(trackingSpy).not.toHaveBeenCalled();
- });
- });
- });
});
describe('success response with failed message', () => {
@@ -465,26 +439,6 @@ describe('IDE commit module actions', () => {
expect(alert.textContent.trim()).toBe('failed message');
});
-
- describe('learnGitlabSource', () => {
- describe('learnGitlabSource is true', () => {
- it('does not track commit', async () => {
- store.state.learnGitlabSource = true;
-
- await store.dispatch('commit/commitChanges');
-
- expect(trackingSpy).not.toHaveBeenCalled();
- });
- });
-
- describe('learnGitlabSource is false', () => {
- it('does not track commit', async () => {
- await store.dispatch('commit/commitChanges');
-
- expect(trackingSpy).not.toHaveBeenCalled();
- });
- });
- });
});
describe('failed response', () => {
@@ -504,26 +458,6 @@ describe('IDE commit module actions', () => {
['commit/SET_ERROR', createUnexpectedCommitError(), undefined],
]);
});
-
- describe('learnGitlabSource', () => {
- describe('learnGitlabSource is true', () => {
- it('does not track commit', async () => {
- store.state.learnGitlabSource = true;
-
- await store.dispatch('commit/commitChanges').catch(() => {});
-
- expect(trackingSpy).not.toHaveBeenCalled();
- });
- });
-
- describe('learnGitlabSource is false', () => {
- it('does not track commit', async () => {
- await store.dispatch('commit/commitChanges').catch(() => {});
-
- expect(trackingSpy).not.toHaveBeenCalled();
- });
- });
- });
});
describe('first commit of a branch', () => {
diff --git a/spec/frontend/notes/components/discussion_filter_spec.js b/spec/frontend/notes/components/discussion_filter_spec.js
index ed1ced1b3d1..28e5e65c177 100644
--- a/spec/frontend/notes/components/discussion_filter_spec.js
+++ b/spec/frontend/notes/components/discussion_filter_spec.js
@@ -1,4 +1,4 @@
-import { GlDropdown } from '@gitlab/ui';
+import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
import Vue, { nextTick } from 'vue';
import AxiosMockAdapter from 'axios-mock-adapter';
@@ -77,17 +77,16 @@ describe('DiscussionFilter component', () => {
// as it doesn't matter for our tests here
mock.onGet(DISCUSSION_PATH).reply(HTTP_STATUS_OK, '');
window.mrTabs = undefined;
- wrapper = mountComponent();
jest.spyOn(Tracking, 'event');
});
afterEach(() => {
- wrapper.vm.$destroy();
mock.restore();
});
describe('default', () => {
beforeEach(() => {
+ wrapper = mountComponent();
jest.spyOn(store, 'dispatch').mockImplementation();
});
@@ -104,6 +103,7 @@ describe('DiscussionFilter component', () => {
describe('when asc', () => {
beforeEach(() => {
+ wrapper = mountComponent();
jest.spyOn(store, 'dispatch').mockImplementation();
});
@@ -123,6 +123,7 @@ describe('DiscussionFilter component', () => {
describe('when desc', () => {
beforeEach(() => {
+ wrapper = mountComponent();
store.state.discussionSortOrder = DESC;
jest.spyOn(store, 'dispatch').mockImplementation();
});
@@ -145,56 +146,62 @@ describe('DiscussionFilter component', () => {
});
});
- it('renders the all filters', () => {
- expect(wrapper.findAll('.discussion-filter-container .dropdown-item').length).toBe(
- discussionFiltersMock.length,
- );
- });
+ describe('discussion filter functionality', () => {
+ beforeEach(() => {
+ wrapper = mountComponent();
+ });
- it('renders the default selected item', () => {
- expect(wrapper.find('.discussion-filter-container .dropdown-item').text().trim()).toBe(
- discussionFiltersMock[0].title,
- );
- });
+ it('renders the all filters', () => {
+ expect(wrapper.findAll('.discussion-filter-container .dropdown-item').length).toBe(
+ discussionFiltersMock.length,
+ );
+ });
- it('disables the dropdown when discussions are loading', () => {
- store.state.isLoading = true;
+ it('renders the default selected item', () => {
+ expect(wrapper.find('.discussion-filter-container .dropdown-item').text().trim()).toBe(
+ discussionFiltersMock[0].title,
+ );
+ });
- expect(wrapper.findComponent(GlDropdown).props('disabled')).toBe(true);
- });
+ it('disables the dropdown when discussions are loading', () => {
+ store.state.isLoading = true;
- it('updates to the selected item', () => {
- const filterItem = findFilter(DISCUSSION_FILTER_TYPES.ALL);
+ expect(wrapper.findComponent(GlDropdown).props('disabled')).toBe(true);
+ });
- filterItem.trigger('click');
+ it('updates to the selected item', () => {
+ const filterItem = findFilter(DISCUSSION_FILTER_TYPES.ALL);
- expect(wrapper.vm.currentFilter.title).toBe(filterItem.text().trim());
- });
+ filterItem.trigger('click');
- it('only updates when selected filter changes', () => {
- findFilter(DISCUSSION_FILTER_TYPES.ALL).trigger('click');
+ expect(filterItem.text().trim()).toBe('Show all activity');
+ });
- expect(filterDiscussion).not.toHaveBeenCalled();
- });
+ it('only updates when selected filter changes', () => {
+ findFilter(DISCUSSION_FILTER_TYPES.ALL).trigger('click');
+
+ expect(filterDiscussion).not.toHaveBeenCalled();
+ });
- it('disables timeline view if it was enabled', () => {
- store.state.isTimelineEnabled = true;
+ it('disables timeline view if it was enabled', () => {
+ store.state.isTimelineEnabled = true;
- findFilter(DISCUSSION_FILTER_TYPES.HISTORY).trigger('click');
+ findFilter(DISCUSSION_FILTER_TYPES.HISTORY).trigger('click');
- expect(wrapper.vm.$store.state.isTimelineEnabled).toBe(false);
- });
+ expect(store.state.isTimelineEnabled).toBe(false);
+ });
- it('disables commenting when "Show history only" filter is applied', () => {
- findFilter(DISCUSSION_FILTER_TYPES.HISTORY).trigger('click');
+ it('disables commenting when "Show history only" filter is applied', () => {
+ findFilter(DISCUSSION_FILTER_TYPES.HISTORY).trigger('click');
- expect(wrapper.vm.$store.state.commentsDisabled).toBe(true);
- });
+ expect(store.state.commentsDisabled).toBe(true);
+ });
- it('enables commenting when "Show history only" filter is not applied', () => {
- findFilter(DISCUSSION_FILTER_TYPES.ALL).trigger('click');
+ it('enables commenting when "Show history only" filter is not applied', () => {
+ findFilter(DISCUSSION_FILTER_TYPES.ALL).trigger('click');
- expect(wrapper.vm.$store.state.commentsDisabled).toBe(false);
+ expect(store.state.commentsDisabled).toBe(false);
+ });
});
describe('Merge request tabs', () => {
@@ -222,52 +229,41 @@ describe('DiscussionFilter component', () => {
});
describe('URL with Links to notes', () => {
+ const findDropdownItems = () => wrapper.findAllComponents(GlDropdownItem);
+
afterEach(() => {
window.location.hash = '';
});
- it('updates the filter when the URL links to a note', async () => {
- window.location.hash = `note_${discussionMock.notes[0].id}`;
- wrapper.vm.currentValue = discussionFiltersMock[2].value;
- wrapper.vm.handleLocationHash();
-
- await nextTick();
- expect(wrapper.vm.currentValue).toBe(DISCUSSION_FILTERS_DEFAULT_VALUE);
- });
-
it('does not update the filter when the current filter is "Show all activity"', async () => {
window.location.hash = `note_${discussionMock.notes[0].id}`;
- wrapper.vm.handleLocationHash();
+ wrapper = mountComponent();
await nextTick();
- expect(wrapper.vm.currentValue).toBe(DISCUSSION_FILTERS_DEFAULT_VALUE);
+ const filtered = findDropdownItems().filter((el) => el.classes('is-active'));
+
+ expect(filtered).toHaveLength(1);
+ expect(filtered.at(0).text()).toBe(discussionFiltersMock[0].title);
});
it('only updates filter when the URL links to a note', async () => {
window.location.hash = `testing123`;
- wrapper.vm.handleLocationHash();
+ wrapper = mountComponent();
await nextTick();
- expect(wrapper.vm.currentValue).toBe(DISCUSSION_FILTERS_DEFAULT_VALUE);
- });
+ const filtered = findDropdownItems().filter((el) => el.classes('is-active'));
- it('fetches discussions when there is a hash', async () => {
- window.location.hash = `note_${discussionMock.notes[0].id}`;
- wrapper.vm.currentValue = discussionFiltersMock[2].value;
- jest.spyOn(wrapper.vm, 'selectFilter').mockImplementation(() => {});
- wrapper.vm.handleLocationHash();
-
- await nextTick();
- expect(wrapper.vm.selectFilter).toHaveBeenCalled();
+ expect(filtered).toHaveLength(1);
+ expect(filtered.at(0).text()).toBe(discussionFiltersMock[0].title);
});
it('does not fetch discussions when there is no hash', async () => {
window.location.hash = '';
- jest.spyOn(wrapper.vm, 'selectFilter').mockImplementation(() => {});
- wrapper.vm.handleLocationHash();
+ const selectFilterSpy = jest.spyOn(wrapper.vm, 'selectFilter').mockImplementation(() => {});
+ wrapper = mountComponent();
await nextTick();
- expect(wrapper.vm.selectFilter).not.toHaveBeenCalled();
+ expect(selectFilterSpy).not.toHaveBeenCalled();
});
});
});
diff --git a/spec/graphql/types/work_items/widget_interface_spec.rb b/spec/graphql/types/work_items/widget_interface_spec.rb
index d1dcfb961cb..045c1620815 100644
--- a/spec/graphql/types/work_items/widget_interface_spec.rb
+++ b/spec/graphql/types/work_items/widget_interface_spec.rb
@@ -21,6 +21,7 @@ RSpec.describe Types::WorkItems::WidgetInterface do
WorkItems::Widgets::Labels | Types::WorkItems::Widgets::LabelsType
WorkItems::Widgets::Notes | Types::WorkItems::Widgets::NotesType
WorkItems::Widgets::Notifications | Types::WorkItems::Widgets::NotificationsType
+ WorkItems::Widgets::CurrentUserTodos | Types::WorkItems::Widgets::CurrentUserTodosType
end
with_them do
diff --git a/spec/graphql/types/work_items/widgets/current_user_todos_type_spec.rb b/spec/graphql/types/work_items/widgets/current_user_todos_type_spec.rb
new file mode 100644
index 00000000000..b39adefbd87
--- /dev/null
+++ b/spec/graphql/types/work_items/widgets/current_user_todos_type_spec.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Types::WorkItems::Widgets::CurrentUserTodosType, feature_category: :team_planning do
+ it 'exposes the expected fields' do
+ expected_fields = %i[current_user_todos type]
+
+ expect(described_class).to have_graphql_fields(*expected_fields)
+ end
+end
diff --git a/spec/helpers/sidebars_helper_spec.rb b/spec/helpers/sidebars_helper_spec.rb
index bdfc45811df..c7d9c36f1a4 100644
--- a/spec/helpers/sidebars_helper_spec.rb
+++ b/spec/helpers/sidebars_helper_spec.rb
@@ -112,10 +112,10 @@ RSpec.describe SidebarsHelper, feature_category: :navigation do
},
can_sign_out: helper.current_user_menu?(:sign_out),
sign_out_link: destroy_user_session_path,
- assigned_open_issues_count: 1,
- todos_pending_count: 3,
+ assigned_open_issues_count: "1",
+ todos_pending_count: "3",
issues_dashboard_path: issues_dashboard_path(assignee_username: user.username),
- total_merge_requests_count: 4,
+ total_merge_requests_count: "4",
projects_path: projects_path,
groups_path: groups_path,
support_path: helper.support_url,
@@ -195,6 +195,23 @@ RSpec.describe SidebarsHelper, feature_category: :navigation do
)
end
+ context 'when counts are high' do
+ before do
+ allow(user).to receive(:assigned_open_issues_count).and_return(1000)
+ allow(user).to receive(:todos_pending_count).and_return(3000)
+ allow(user).to receive(:assigned_open_merge_requests_count).and_return(50)
+ allow(user).to receive(:review_requested_open_merge_requests_count).and_return(50)
+ end
+
+ it 'caps counts to USER_BAR_COUNT_LIMIT and appends a "+" to them' do
+ expect(subject).to include(
+ assigned_open_issues_count: "99+",
+ todos_pending_count: "99+",
+ total_merge_requests_count: "99+"
+ )
+ end
+ end
+
describe 'current context' do
context 'when current context is a project' do
let_it_be(:project) { build(:project) }
diff --git a/spec/lib/gitlab/ci/status/composite_spec.rb b/spec/lib/gitlab/ci/status/composite_spec.rb
index 9f133d2c16f..cbf0976c976 100644
--- a/spec/lib/gitlab/ci/status/composite_spec.rb
+++ b/spec/lib/gitlab/ci/status/composite_spec.rb
@@ -63,8 +63,8 @@ RSpec.describe Gitlab::Ci::Status::Composite, feature_category: :continuous_inte
%i(created success pending) | false | 'running' | false
%i(skipped success failed) | false | 'failed' | false
%i(skipped success failed) | true | 'skipped' | false
- %i(success manual) | true | 'pending' | false
- %i(success failed created) | true | 'pending' | false
+ %i(success manual) | true | 'manual' | false
+ %i(success failed created) | true | 'running' | false
end
with_them do
diff --git a/spec/migrations/20230302811133_re_migrate_redis_slot_keys_spec.rb b/spec/migrations/20230302811133_re_migrate_redis_slot_keys_spec.rb
new file mode 100644
index 00000000000..4c6d4907c29
--- /dev/null
+++ b/spec/migrations/20230302811133_re_migrate_redis_slot_keys_spec.rb
@@ -0,0 +1,77 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe ReMigrateRedisSlotKeys, :migration, feature_category: :service_ping do
+ let(:date) { Date.yesterday.strftime('%G-%j') }
+ let(:week) { Date.yesterday.strftime('%G-%V') }
+ let(:known_events) do
+ [
+ {
+ redis_slot: 'analytics',
+ aggregation: 'daily',
+ name: 'users_viewing_analytics_group_devops_adoption'
+ }, {
+ aggregation: 'weekly',
+ name: 'wiki_action'
+ }, {
+ aggregation: 'weekly',
+ name: 'non_existing_event'
+ }, {
+ aggregation: 'weekly',
+ name: 'event_without_expiry'
+ }
+ ]
+ end
+
+ describe "#up" do
+ it 'rename keys', :aggregate_failures do
+ allow(Gitlab::UsageDataCounters::HLLRedisCounter).to receive(:known_events)
+ .and_return(known_events)
+
+ expiry_daily = Gitlab::UsageDataCounters::HLLRedisCounter::DEFAULT_DAILY_KEY_EXPIRY_LENGTH
+ expiry_weekly = Gitlab::UsageDataCounters::HLLRedisCounter::DEFAULT_WEEKLY_KEY_EXPIRY_LENGTH
+
+ default_slot = Gitlab::UsageDataCounters::HLLRedisCounter::REDIS_SLOT
+
+ old_slot_a = "#{date}-users_viewing_{analytics}_group_devops_adoption"
+ old_slot_b = "{wiki_action}-#{week}"
+ old_slot_without_expiry = "{event_without_expiry}-#{week}"
+
+ new_slot_a = "#{date}-{#{default_slot}}_users_viewing_analytics_group_devops_adoption"
+ new_slot_b = "{#{default_slot}}_wiki_action-#{week}"
+ new_slot_without_expiry = "{#{default_slot}}_event_without_expiry-#{week}"
+
+ Gitlab::Redis::HLL.add(key: old_slot_a, value: 1, expiry: expiry_daily)
+ Gitlab::Redis::HLL.add(key: old_slot_b, value: 1, expiry: expiry_weekly)
+ Gitlab::Redis::HLL.add(key: old_slot_a, value: 2, expiry: expiry_daily)
+ Gitlab::Redis::HLL.add(key: old_slot_b, value: 2, expiry: expiry_weekly)
+ Gitlab::Redis::HLL.add(key: old_slot_b, value: 2, expiry: expiry_weekly)
+ Gitlab::Redis::SharedState.with { |redis| redis.pfadd(old_slot_without_expiry, 1) }
+
+ # check that we merge values during migration
+ # i.e. we dont drop keys created after code deploy but before the migration
+ Gitlab::Redis::HLL.add(key: new_slot_a, value: 3, expiry: expiry_daily)
+ Gitlab::Redis::HLL.add(key: new_slot_b, value: 3, expiry: expiry_weekly)
+ Gitlab::Redis::HLL.add(key: new_slot_without_expiry, value: 2, expiry: expiry_weekly)
+
+ migrate!
+
+ expect(Gitlab::Redis::HLL.count(keys: new_slot_a)).to eq(3)
+ expect(Gitlab::Redis::HLL.count(keys: new_slot_b)).to eq(3)
+ expect(Gitlab::Redis::HLL.count(keys: new_slot_without_expiry)).to eq(2)
+ expect(with_redis { |r| r.ttl(new_slot_a) }).to be_within(600).of(expiry_daily)
+ expect(with_redis { |r| r.ttl(new_slot_b) }).to be_within(600).of(expiry_weekly)
+ expect(with_redis { |r| r.ttl(new_slot_without_expiry) }).to be_within(600).of(expiry_weekly)
+ end
+
+ it 'runs without errors' do
+ expect { migrate! }.not_to raise_error
+ end
+ end
+
+ def with_redis(&block)
+ Gitlab::Redis::SharedState.with(&block)
+ end
+end
diff --git a/spec/migrations/20230317162059_add_current_user_todos_work_item_widget_spec.rb b/spec/migrations/20230317162059_add_current_user_todos_work_item_widget_spec.rb
new file mode 100644
index 00000000000..f044b15fa6b
--- /dev/null
+++ b/spec/migrations/20230317162059_add_current_user_todos_work_item_widget_spec.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe AddCurrentUserTodosWorkItemWidget, :migration, feature_category: :team_planning do
+ let(:migration) { described_class.new }
+ let(:work_item_definitions) { table(:work_item_widget_definitions) }
+
+ describe '#up' do
+ it 'creates notifications widget definition in all types' do
+ work_item_definitions.where(name: 'Current user todos').delete_all
+
+ expect { migrate! }.to change { work_item_definitions.count }.by(7)
+ expect(work_item_definitions.all.pluck(:name)).to include('Current user todos')
+ end
+ end
+
+ describe '#down' do
+ it 'removes definitions for notifications widget' do
+ migrate!
+
+ expect { migration.down }.to change { work_item_definitions.count }.by(-7)
+ expect(work_item_definitions.all.pluck(:name)).not_to include('Current user todos')
+ end
+ end
+end
diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb
index 3134f2ba248..ac774c84335 100644
--- a/spec/models/group_spec.rb
+++ b/spec/models/group_spec.rb
@@ -981,6 +981,22 @@ RSpec.describe Group, feature_category: :subgroups do
expect(result).to include(group_2, group_3, group_4)
expect(result).not_to include(group_1)
end
+
+ context 'when the application_setting is set to `NO_ONE_PROJECT_ACCESS`' do
+ before do
+ stub_application_setting(default_project_creation: Gitlab::Access::NO_ONE_PROJECT_ACCESS)
+ end
+
+ it 'only includes groups where project creation is allowed' do
+ result = described_class.project_creation_allowed
+
+ expect(result).to include(group_2, group_3)
+
+ # group_4 won't be included because it has `project_creation_level: nil`,
+ # and that means it behaves like the value of the application_setting will inherited.
+ expect(result).not_to include(group_1, group_4)
+ end
+ end
end
describe 'by_ids_or_paths' do
diff --git a/spec/models/work_items/widget_definition_spec.rb b/spec/models/work_items/widget_definition_spec.rb
index 3a4670c996f..f4d132bec52 100644
--- a/spec/models/work_items/widget_definition_spec.rb
+++ b/spec/models/work_items/widget_definition_spec.rb
@@ -12,7 +12,8 @@ RSpec.describe WorkItems::WidgetDefinition, feature_category: :team_planning do
::WorkItems::Widgets::StartAndDueDate,
::WorkItems::Widgets::Milestone,
::WorkItems::Widgets::Notes,
- ::WorkItems::Widgets::Notifications
+ ::WorkItems::Widgets::Notifications,
+ ::WorkItems::Widgets::CurrentUserTodos
]
if Gitlab.ee?
diff --git a/spec/requests/api/graphql/work_item_spec.rb b/spec/requests/api/graphql/work_item_spec.rb
index 24c72a8bb00..fe6f75548a5 100644
--- a/spec/requests/api/graphql/work_item_spec.rb
+++ b/spec/requests/api/graphql/work_item_spec.rb
@@ -399,6 +399,93 @@ RSpec.describe 'Query.work_item(id)', feature_category: :team_planning do
)
end
end
+
+ describe 'currentUserTodos widget' do
+ let_it_be(:current_user) { developer }
+ let_it_be(:other_todo) { create(:todo, state: :pending, user: current_user) }
+
+ let_it_be(:done_todo) do
+ create(:todo, state: :done, target: work_item, target_type: work_item.class.name, user: current_user)
+ end
+
+ let_it_be(:pending_todo) do
+ create(:todo, state: :pending, target: work_item, target_type: work_item.class.name, user: current_user)
+ end
+
+ let_it_be(:other_user_todo) do
+ create(:todo, state: :pending, target: work_item, target_type: work_item.class.name, user: create(:user))
+ end
+
+ let(:work_item_fields) do
+ <<~GRAPHQL
+ id
+ widgets {
+ type
+ ... on WorkItemWidgetCurrentUserTodos {
+ currentUserTodos {
+ nodes {
+ id
+ state
+ }
+ }
+ }
+ }
+ GRAPHQL
+ end
+
+ context 'with access' do
+ it 'returns widget information' do
+ expect(work_item_data).to include(
+ 'id' => work_item.to_gid.to_s,
+ 'widgets' => include(
+ hash_including(
+ 'type' => 'CURRENT_USER_TODOS',
+ 'currentUserTodos' => {
+ 'nodes' => match_array(
+ [done_todo, pending_todo].map { |t| { 'id' => t.to_gid.to_s, 'state' => t.state } }
+ )
+ }
+ )
+ )
+ )
+ end
+ end
+
+ context 'with filter' do
+ let(:work_item_fields) do
+ <<~GRAPHQL
+ id
+ widgets {
+ type
+ ... on WorkItemWidgetCurrentUserTodos {
+ currentUserTodos(state: done) {
+ nodes {
+ id
+ state
+ }
+ }
+ }
+ }
+ GRAPHQL
+ end
+
+ it 'returns widget information' do
+ expect(work_item_data).to include(
+ 'id' => work_item.to_gid.to_s,
+ 'widgets' => include(
+ hash_including(
+ 'type' => 'CURRENT_USER_TODOS',
+ 'currentUserTodos' => {
+ 'nodes' => match_array(
+ [done_todo].map { |t| { 'id' => t.to_gid.to_s, 'state' => t.state } }
+ )
+ }
+ )
+ )
+ )
+ end
+ end
+ end
end
context 'when an Issue Global ID is provided' do
diff --git a/spec/services/bulk_imports/create_service_spec.rb b/spec/services/bulk_imports/create_service_spec.rb
index 35398e4cae0..6fe93437694 100644
--- a/spec/services/bulk_imports/create_service_spec.rb
+++ b/spec/services/bulk_imports/create_service_spec.rb
@@ -150,7 +150,8 @@ RSpec.describe BulkImports::CreateService, feature_category: :importers do
expect_snowplow_event(
category: 'BulkImports::CreateService',
action: 'create',
- label: 'bulk_import_group'
+ label: 'bulk_import_group',
+ extra: { source_equals_destination: false }
)
expect_snowplow_event(
@@ -162,6 +163,23 @@ RSpec.describe BulkImports::CreateService, feature_category: :importers do
)
end
+ context 'on the same instance' do
+ before do
+ allow(Settings.gitlab).to receive(:base_url).and_return('http://gitlab.example')
+ end
+
+ it 'tracks the same instance migration' do
+ expect { subject.execute }.to change { BulkImport.count }.by(1)
+
+ expect_snowplow_event(
+ category: 'BulkImports::CreateService',
+ action: 'create',
+ label: 'bulk_import_group',
+ extra: { source_equals_destination: true }
+ )
+ end
+ end
+
describe 'projects migration flag' do
let(:import) { BulkImport.last }
@@ -229,7 +247,8 @@ RSpec.describe BulkImports::CreateService, feature_category: :importers do
expect_snowplow_event(
category: 'BulkImports::CreateService',
action: 'create',
- label: 'bulk_import_group'
+ label: 'bulk_import_group',
+ extra: { source_equals_destination: false }
)
expect_snowplow_event(
@@ -241,6 +260,23 @@ RSpec.describe BulkImports::CreateService, feature_category: :importers do
)
end
+ context 'on the same instance' do
+ before do
+ allow(Settings.gitlab).to receive(:base_url).and_return('http://gitlab.example')
+ end
+
+ it 'tracks the same instance migration' do
+ expect { subject.execute }.to change { BulkImport.count }.by(1)
+
+ expect_snowplow_event(
+ category: 'BulkImports::CreateService',
+ action: 'create',
+ label: 'bulk_import_group',
+ extra: { source_equals_destination: true }
+ )
+ end
+ end
+
it 'creates bulk import entities' do
expect { subject.execute }.to change { BulkImports::Entity.count }.by(3)
end
diff --git a/spec/services/ci/pipeline_processing/atomic_processing_service/status_collection_spec.rb b/spec/services/ci/pipeline_processing/atomic_processing_service/status_collection_spec.rb
index ceef369f868..89b3c45485b 100644
--- a/spec/services/ci/pipeline_processing/atomic_processing_service/status_collection_spec.rb
+++ b/spec/services/ci/pipeline_processing/atomic_processing_service/status_collection_spec.rb
@@ -36,7 +36,7 @@ RSpec.describe Ci::PipelineProcessing::AtomicProcessingService::StatusCollection
it 'does update existing status of job' do
collection.set_job_status(test_a.id, 'success', 100)
- expect(collection.status_of_jobs(['test-a'], dag: false)).to eq('success')
+ expect(collection.status_of_jobs(['test-a'])).to eq('success')
end
it 'ignores a missing job' do
@@ -51,18 +51,15 @@ RSpec.describe Ci::PipelineProcessing::AtomicProcessingService::StatusCollection
end
describe '#status_of_jobs' do
- where(:names, :status, :dag) do
- %w[build-a] | 'success' | false
- %w[build-a build-b] | 'failed' | false
- %w[build-a test-a] | 'running' | false
- %w[build-a] | 'success' | true
- %w[build-a build-b] | 'failed' | true
- %w[build-a test-a] | 'pending' | true
+ where(:names, :status) do
+ %w[build-a] | 'success'
+ %w[build-a build-b] | 'failed'
+ %w[build-a test-a] | 'running'
end
with_them do
it 'returns composite status of given names' do
- expect(collection.status_of_jobs(names, dag: dag)).to eq(status)
+ expect(collection.status_of_jobs(names)).to eq(status)
end
end
end
diff --git a/spec/services/ci/pipeline_processing/atomic_processing_service_spec.rb b/spec/services/ci/pipeline_processing/atomic_processing_service_spec.rb
index d0496acc6fe..d59d8e24af6 100644
--- a/spec/services/ci/pipeline_processing/atomic_processing_service_spec.rb
+++ b/spec/services/ci/pipeline_processing/atomic_processing_service_spec.rb
@@ -33,6 +33,25 @@ RSpec.describe Ci::PipelineProcessing::AtomicProcessingService, feature_category
end
end
+ context 'when the FF ci_simplify_dag_status_calculation_for_processing is disabled' do
+ before do
+ stub_feature_flags(ci_simplify_dag_status_calculation_for_processing: false)
+ end
+
+ # This is duplicate of the one above but it is temporary
+ it 'follows transitions' do
+ expect(pipeline).to be_persisted
+ Sidekiq::Worker.drain_all # ensure that all async jobs are executed
+ check_expectation(test_file.dig('init', 'expect'), "init")
+
+ test_file['transitions'].each_with_index do |transition, idx|
+ process_events(transition)
+ Sidekiq::Worker.drain_all # ensure that all async jobs are executed
+ check_expectation(transition['expect'], "transition:#{idx}")
+ end
+ end
+ end
+
private
def check_expectation(expectation, message)
diff --git a/spec/support/helpers/test_env.rb b/spec/support/helpers/test_env.rb
index 727b8a6b880..a53e1e1002c 100644
--- a/spec/support/helpers/test_env.rb
+++ b/spec/support/helpers/test_env.rb
@@ -234,7 +234,7 @@ module TestEnv
end
def workhorse_dir
- @workhorse_path ||= File.join('tmp', 'tests', 'gitlab-workhorse')
+ @workhorse_path ||= Rails.root.join('tmp', 'tests', 'gitlab-workhorse')
end
def with_workhorse(host, port, upstream, &blk)
diff --git a/workhorse/.tool-versions b/workhorse/.tool-versions
index 18a7cdea814..0c4422a9db4 100644
--- a/workhorse/.tool-versions
+++ b/workhorse/.tool-versions
@@ -1 +1 @@
-golang 1.18.9
+golang 1.19.7
diff --git a/workhorse/internal/httprs/httprs.go b/workhorse/internal/httprs/httprs.go
index f7767d2ee28..811a50035f3 100644
--- a/workhorse/internal/httprs/httprs.go
+++ b/workhorse/internal/httprs/httprs.go
@@ -11,6 +11,7 @@ Usage :
io.ReadFull(rs, buf) // does a range request and reads from the response body
If you want use a specific http.Client for additional range requests :
+
rs := httprs.NewHttpReadSeeker(resp, client)
*/
package httprs
diff --git a/workhorse/internal/queueing/queue.go b/workhorse/internal/queueing/queue.go
index c8d32280355..266f8897450 100644
--- a/workhorse/internal/queueing/queue.go
+++ b/workhorse/internal/queueing/queue.go
@@ -27,8 +27,9 @@ type queueMetrics struct {
// newQueueMetrics prepares Prometheus metrics for queueing mechanism
// name specifies name of the queue, used to label metrics with ConstLabel `queue_name`
// timeout specifies the timeout of storing a request in queue - queueMetrics
-// uses it to calculate histogram buckets for gitlab_workhorse_queueing_waiting_time
-// metric
+//
+// uses it to calculate histogram buckets for gitlab_workhorse_queueing_waiting_time
+// metric
func newQueueMetrics(name string, timeout time.Duration, reg prometheus.Registerer) *queueMetrics {
waitingTimeBuckets := []float64{
timeout.Seconds() * 0.01,
diff --git a/workhorse/internal/queueing/requests.go b/workhorse/internal/queueing/requests.go
index c3df614de41..a6ca98a674a 100644
--- a/workhorse/internal/queueing/requests.go
+++ b/workhorse/internal/queueing/requests.go
@@ -16,7 +16,9 @@ const (
// QueueRequests creates a new request queue
// name specifies the name of queue, used to label Prometheus metrics
-// Don't call QueueRequests twice with the same name argument!
+//
+// Don't call QueueRequests twice with the same name argument!
+//
// h specifies a http.Handler which will handle the queue requests
// limit specifies number of requests run concurrently
// queueLimit specifies maximum number of requests that can be queued