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>2024-01-23 00:08:53 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2024-01-23 00:08:53 +0300
commit386dcdbe9d3cef9d5fa79c4582a722db27fe2c57 (patch)
treea0719a1794b21fedf33ab51a4052b8b9c0f7b573
parenta9a2f9257eae40935e03ca4185d5263bcb7ba45f (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.gitlab/ci/rails/shared.gitlab-ci.yml8
-rw-r--r--.ruby-version2
-rw-r--r--Gemfile2
-rw-r--r--Gemfile.checksum6
-rw-r--r--Gemfile.lock9
-rw-r--r--app/assets/javascripts/diffs/components/app.vue17
-rw-r--r--app/assets/javascripts/lib/utils/datetime/date_calculation_utility.js13
-rw-r--r--app/assets/javascripts/notes/components/comment_form.vue7
-rw-r--r--app/assets/javascripts/notes/components/note_form.vue2
-rw-r--r--app/assets/javascripts/notes/components/notes_app.vue18
-rw-r--r--app/assets/javascripts/usage_quotas/storage/components/namespace_storage_app.vue64
-rw-r--r--app/assets/javascripts/usage_quotas/storage/components/project_list.vue208
-rw-r--r--app/assets/javascripts/usage_quotas/storage/components/storage_type_help_link.vue36
-rw-r--r--app/services/service_ping/submit_service.rb2
-rw-r--r--config/events/merge_request_click_add_to_review_on_changes_tab.yml20
-rw-r--r--config/events/merge_request_click_add_to_review_on_overview_tab.yml20
-rw-r--r--config/events/merge_request_click_start_review_on_changes_tab.yml20
-rw-r--r--config/events/merge_request_click_start_review_on_overview_tab.yml20
-rw-r--r--config/feature_flags/gitlab_com_derisk/github_importer_attachments.yml9
-rw-r--r--config/metrics/counts_28d/count_total_merge_request_click_add_to_review_on_changes_tab_monthly.yml26
-rw-r--r--config/metrics/counts_28d/count_total_merge_request_click_add_to_review_on_overview_tab_monthly.yml26
-rw-r--r--config/metrics/counts_28d/count_total_merge_request_click_start_review_on_changes_tab_monthly.yml26
-rw-r--r--config/metrics/counts_28d/count_total_merge_request_click_start_review_on_overview_tab_monthly.yml26
-rw-r--r--config/metrics/counts_7d/count_total_merge_request_click_add_to_review_on_changes_tab_weekly.yml26
-rw-r--r--config/metrics/counts_7d/count_total_merge_request_click_add_to_review_on_overview_tab_weekly.yml26
-rw-r--r--config/metrics/counts_7d/count_total_merge_request_click_start_review_on_changes_tab_weekly.yml26
-rw-r--r--config/metrics/counts_7d/count_total_merge_request_click_start_review_on_overview_tab_weekly.yml26
-rw-r--r--config/metrics/counts_all/count_total_merge_request_click_add_to_review_on_changes_tab.yml26
-rw-r--r--config/metrics/counts_all/count_total_merge_request_click_add_to_review_on_overview_tab.yml26
-rw-r--r--config/metrics/counts_all/count_total_merge_request_click_start_review_on_changes_tab.yml26
-rw-r--r--config/metrics/counts_all/count_total_merge_request_click_start_review_on_overview_tab.yml26
-rw-r--r--doc/api/resource_state_events.md3
-rw-r--r--doc/development/documentation/restful_api_styleguide.md17
-rw-r--r--doc/development/documentation/styleguide/index.md13
-rw-r--r--doc/user/ai_features.md32
-rw-r--r--lib/bulk_imports/common/pipelines/wiki_pipeline.rb7
-rw-r--r--lib/bulk_imports/projects/pipelines/repository_pipeline.rb7
-rw-r--r--lib/bulk_imports/projects/pipelines/snippets_repository_pipeline.rb3
-rw-r--r--lib/gitlab/database.rb2
-rw-r--r--lib/gitlab/error_tracking/error_repository/open_api_strategy.rb6
-rw-r--r--lib/gitlab/github_gists_import/importer/gist_importer.rb12
-rw-r--r--lib/gitlab/github_import/importer/attachments/base_importer.rb2
-rw-r--r--lib/gitlab/kubernetes/kube_client.rb6
-rw-r--r--lib/gitlab/octokit/middleware.rb5
-rw-r--r--lib/service_ping/service_ping_settings.rb2
-rw-r--r--spec/frontend/diffs/components/app_spec.js36
-rw-r--r--spec/frontend/lib/utils/datetime_utility_spec.js9
-rw-r--r--spec/frontend/notes/components/comment_form_spec.js19
-rw-r--r--spec/frontend/notes/components/note_form_spec.js51
-rw-r--r--spec/frontend/notes/components/notes_app_spec.js37
-rw-r--r--spec/frontend/usage_quotas/storage/components/storage_type_help_link_spec.js49
-rw-r--r--spec/frontend/usage_quotas/storage/mock_data.js3
-rw-r--r--spec/lib/gitlab/github_gists_import/importer/gist_importer_spec.rb14
-rw-r--r--spec/lib/gitlab/github_import/importer/attachments/issues_importer_spec.rb14
-rw-r--r--spec/lib/gitlab/github_import/importer/attachments/merge_requests_importer_spec.rb14
-rw-r--r--spec/lib/gitlab/github_import/importer/attachments/notes_importer_spec.rb14
-rw-r--r--spec/lib/gitlab/github_import/importer/attachments/releases_importer_spec.rb14
-rw-r--r--spec/lib/service_ping/service_ping_settings_spec.rb8
-rw-r--r--spec/services/service_ping/submit_service_ping_service_spec.rb8
59 files changed, 1053 insertions, 149 deletions
diff --git a/.gitlab/ci/rails/shared.gitlab-ci.yml b/.gitlab/ci/rails/shared.gitlab-ci.yml
index 1f420b9b8ec..04811baf932 100644
--- a/.gitlab/ci/rails/shared.gitlab-ci.yml
+++ b/.gitlab/ci/rails/shared.gitlab-ci.yml
@@ -115,6 +115,14 @@ include:
--input-files "rspec/rspec-*.json" \
--merge_request_iid "$CI_MERGE_REQUEST_IID";
fi
+ if [ "$ALLOW_KNAPSACK_REPORT_CREATE_ISSUES" == "true" ]; then
+ bundle exec knapsack-report-issues \
+ --token "${KNAPSACK_REPORT_ISSUES_PROJECT_TOKEN}" \
+ --project "gitlab-org/gitlab" \
+ --input-file knapsack/rspec_*_report.json \
+ --expected-report node_specs_expected_duration.json \
+ --merge_request_iid "$CI_MERGE_REQUEST_IID";
+ fi
- echo -e "\e[0Ksection_end:`date +%s`:report_results_section\r\e[0K"
- tooling/bin/push_job_metrics || true
diff --git a/.ruby-version b/.ruby-version
index be94e6f53db..b347b11eac8 100644
--- a/.ruby-version
+++ b/.ruby-version
@@ -1 +1 @@
-3.2.2
+3.2.3
diff --git a/Gemfile b/Gemfile
index 01b0b9b7c86..312c8313ccf 100644
--- a/Gemfile
+++ b/Gemfile
@@ -518,7 +518,7 @@ group :test do
# Moved in `test` because https://gitlab.com/gitlab-org/gitlab/-/issues/217527
gem 'derailed_benchmarks', require: false # rubocop:todo Gemfile/MissingFeatureCategory
- gem 'gitlab_quality-test_tooling', '~> 1.12.0', require: false, feature_category: :tooling
+ gem 'gitlab_quality-test_tooling', '~> 1.13.0', require: false, feature_category: :tooling
end
gem 'octokit', '~> 6.0' # rubocop:todo Gemfile/MissingFeatureCategory
diff --git a/Gemfile.checksum b/Gemfile.checksum
index 7ad4c2dc349..dcd0f1e82fe 100644
--- a/Gemfile.checksum
+++ b/Gemfile.checksum
@@ -226,7 +226,7 @@
{"name":"gitlab-styles","version":"11.0.0","platform":"ruby","checksum":"0dd8ec066ce9955ac51d3616c6bfded30f75bb526f39ff392ece6f43d5b9406b"},
{"name":"gitlab_chronic_duration","version":"0.12.0","platform":"ruby","checksum":"0d766944d415b5c831f176871ee8625783fc0c5bfbef2d79a3a616f207ffc16d"},
{"name":"gitlab_omniauth-ldap","version":"2.2.0","platform":"ruby","checksum":"bb4d20acb3b123ed654a8f6a47d3fac673ece7ed0b6992edb92dca14bad2838c"},
-{"name":"gitlab_quality-test_tooling","version":"1.12.0","platform":"ruby","checksum":"6d687db96777bd8c87264253a7cc9ce1d71851d2b20a64d594770c35555630b1"},
+{"name":"gitlab_quality-test_tooling","version":"1.13.0","platform":"ruby","checksum":"04c51c0b372a38e030572ab85b997234e139d0d639d617ce1924269021b51328"},
{"name":"globalid","version":"1.1.0","platform":"ruby","checksum":"b337e1746f0c8cb0a6c918234b03a1ddeb4966206ce288fbb57779f59b2d154f"},
{"name":"gon","version":"6.4.0","platform":"ruby","checksum":"e3a618d659392890f1aa7db420f17c75fd7d35aeb5f8fe003697d02c4b88d2f0"},
{"name":"google-apis-androidpublisher_v3","version":"0.34.0","platform":"ruby","checksum":"d7e1d7dd92f79c498fe2082222a1740d788e022e660c135564b3fd299cab5425"},
@@ -572,7 +572,7 @@
{"name":"ruby-saml","version":"1.15.0","platform":"ruby","checksum":"3a9dda2b448310f4f90d5cf0967d4b668530fa7994d2a4d9cbfdfa62e35f76a3"},
{"name":"ruby-statistics","version":"3.0.0","platform":"ruby","checksum":"610301370346931cb701e3a8d3d3e28eb65681162cae6066c0c11abf20efdc81"},
{"name":"ruby2_keywords","version":"0.0.5","platform":"ruby","checksum":"ffd13740c573b7301cf7a2e61fc857b2a8e3d3aff32545d6f8300d8bae10e3ef"},
-{"name":"ruby_parser","version":"3.20.3","platform":"ruby","checksum":"8d2289a695dc81ffddcdd5a56e80c9a109806bc0d0b1239a1c852b0c71251c49"},
+{"name":"ruby_parser","version":"3.21.0","platform":"ruby","checksum":"3842893d2f4602dcd93c0a79d77f9ce8e1ce197d41ac533d8e25c684f8f1c56b"},
{"name":"rubyntlm","version":"0.6.3","platform":"ruby","checksum":"5b321456dba3130351f7451f8669f1afa83a0d26fd63cdec285b7b88e667102d"},
{"name":"rubypants","version":"0.2.0","platform":"ruby","checksum":"f07e38eac793655a0323fe91946081052341b9e69807026fcf102346589eedee"},
{"name":"rubyzip","version":"2.3.2","platform":"ruby","checksum":"3f57e3935dc2255c414484fbf8d673b4909d8a6a57007ed754dde39342d2373f"},
@@ -593,7 +593,7 @@
{"name":"sentry-ruby","version":"5.10.0","platform":"ruby","checksum":"115c24c0aee1309210f3a2988fb118e2bec1f11609feeda90e694388b1183619"},
{"name":"sentry-sidekiq","version":"5.10.0","platform":"ruby","checksum":"cc81018d0733fb1be3fb5641c9e0b61030bbeaa1d0b23ca64797d70def7aea1a"},
{"name":"set","version":"1.0.2","platform":"ruby","checksum":"02ffa4de1f2621495e05b72326040dd014d7abbcb02fea698bc600a389992c02"},
-{"name":"sexp_processor","version":"4.17.0","platform":"ruby","checksum":"4daa4874ce1838cd801c65e66ed5d4f140024404a3de7482c36d4ef2604dff6f"},
+{"name":"sexp_processor","version":"4.17.1","platform":"ruby","checksum":"91110946720307f30bf1d549e90d9a529fef40d1fc471c069c8cca7667015da0"},
{"name":"shellany","version":"0.0.1","platform":"ruby","checksum":"0e127a9132698766d7e752e82cdac8250b6adbd09e6c0a7fbbb6f61964fedee7"},
{"name":"shoulda-matchers","version":"5.1.0","platform":"ruby","checksum":"a01d20589989e9653ab4a28c67d9db2b82bcf0a2496cf01d5e1a95a4aaaf5b07"},
{"name":"sidekiq","version":"7.1.6","platform":"ruby","checksum":"7859da66d5bcef3c22bea2c3091d08c866890168e003f5bf4dea197dc37843a2"},
diff --git a/Gemfile.lock b/Gemfile.lock
index b24601eed37..2f7c295dde6 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -732,7 +732,7 @@ GEM
omniauth (>= 1.3, < 3)
pyu-ruby-sasl (>= 0.0.3.3, < 0.1)
rubyntlm (~> 0.5)
- gitlab_quality-test_tooling (1.12.0)
+ gitlab_quality-test_tooling (1.13.0)
activesupport (>= 6.1, < 7.2)
amatch (~> 0.4.1)
gitlab (~> 4.19)
@@ -1500,7 +1500,8 @@ GEM
rexml
ruby-statistics (3.0.0)
ruby2_keywords (0.0.5)
- ruby_parser (3.20.3)
+ ruby_parser (3.21.0)
+ racc (~> 1.5)
sexp_processor (~> 4.16)
rubyntlm (0.6.3)
rubypants (0.2.0)
@@ -1547,7 +1548,7 @@ GEM
sentry-ruby (~> 5.10.0)
sidekiq (>= 3.0)
set (1.0.2)
- sexp_processor (4.17.0)
+ sexp_processor (4.17.1)
shellany (0.0.1)
shoulda-matchers (5.1.0)
activesupport (>= 5.2.0)
@@ -1914,7 +1915,7 @@ DEPENDENCIES
gitlab-utils!
gitlab_chronic_duration (~> 0.12)
gitlab_omniauth-ldap (~> 2.2.0)
- gitlab_quality-test_tooling (~> 1.12.0)
+ gitlab_quality-test_tooling (~> 1.13.0)
gon (~> 6.4.0)
google-apis-androidpublisher_v3 (~> 0.34.0)
google-apis-cloudbilling_v1 (~> 0.21.0)
diff --git a/app/assets/javascripts/diffs/components/app.vue b/app/assets/javascripts/diffs/components/app.vue
index 50266e2c434..b5e446d13e4 100644
--- a/app/assets/javascripts/diffs/components/app.vue
+++ b/app/assets/javascripts/diffs/components/app.vue
@@ -15,6 +15,7 @@ import {
MR_COMMITS_PREVIOUS_COMMIT,
} from '~/behaviors/shortcuts/keybindings';
import { createAlert } from '~/alert';
+import { InternalEvents } from '~/tracking';
import { isSingleViewStyle } from '~/helpers/diffs_helper';
import { helpPagePath } from '~/helpers/help_page_helper';
import { parseBoolean, handleLocationHash } from '~/lib/utils/common_utils';
@@ -86,7 +87,7 @@ export default {
GlSprintf,
GlAlert,
},
- mixins: [glFeatureFlagsMixin()],
+ mixins: [glFeatureFlagsMixin(), InternalEvents.mixin()],
alerts: {
ALERT_OVERFLOW_HIDDEN,
ALERT_MERGE_CONFLICT,
@@ -443,6 +444,8 @@ export default {
notesEventHub.$once('fetchDiffData', this.fetchData);
notesEventHub.$on('refetchDiffData', this.refetchDiffData);
notesEventHub.$on('fetchedNotesData', this.rereadNoteHash);
+ notesEventHub.$on('noteFormAddToReview', this.handleReviewTracking);
+ notesEventHub.$on('noteFormStartReview', this.handleReviewTracking);
diffsEventHub.$on('diffFilesModified', this.setDiscussions);
diffsEventHub.$on('doneLoadingBatches', this.autoScroll);
diffsEventHub.$on(EVT_MR_PREPARED, this.fetchData);
@@ -453,6 +456,8 @@ export default {
diffsEventHub.$off(EVT_MR_PREPARED, this.fetchData);
diffsEventHub.$off('doneLoadingBatches', this.autoScroll);
diffsEventHub.$off('diffFilesModified', this.setDiscussions);
+ notesEventHub.$off('noteFormStartReview', this.handleReviewTracking);
+ notesEventHub.$off('noteFormAddToReview', this.handleReviewTracking);
notesEventHub.$off('fetchedNotesData', this.rereadNoteHash);
notesEventHub.$off('refetchDiffData', this.refetchDiffData);
notesEventHub.$off('fetchDiffData', this.fetchData);
@@ -679,6 +684,16 @@ export default {
reloadPage() {
window.location.reload();
},
+ handleReviewTracking(event) {
+ const types = {
+ noteFormStartReview: 'merge_request_click_start_review_on_changes_tab',
+ noteFormAddToReview: 'merge_request_click_add_to_review_on_changes_tab',
+ };
+
+ if (this.shouldShow && types[event.name]) {
+ this.trackEvent(types[event.name]);
+ }
+ },
},
howToMergeDocsPath: helpPagePath('user/project/merge_requests/reviews/index.md', {
anchor: 'checkout-merge-requests-locally-through-the-head-ref',
diff --git a/app/assets/javascripts/lib/utils/datetime/date_calculation_utility.js b/app/assets/javascripts/lib/utils/datetime/date_calculation_utility.js
index 6484fcff769..9bb2884e065 100644
--- a/app/assets/javascripts/lib/utils/datetime/date_calculation_utility.js
+++ b/app/assets/javascripts/lib/utils/datetime/date_calculation_utility.js
@@ -401,6 +401,8 @@ export const nWeeksBefore = (date, numberOfWeeks, options) =>
/**
* Returns the date `n` years after the date provided.
+ * When Feb 29 is the specified date, the default behaviour is to return March 1.
+ * But to align with the equivalent rails code, moment JS and datefns we should return Feb 28 instead.
*
* @param {Date} date the initial date
* @param {Number} numberOfYears number of years after
@@ -408,7 +410,16 @@ export const nWeeksBefore = (date, numberOfWeeks, options) =>
*/
export const nYearsAfter = (date, numberOfYears) => {
const clone = newDate(date);
- clone.setFullYear(clone.getFullYear() + numberOfYears);
+ clone.setUTCMonth(clone.getUTCMonth());
+
+ // If the date we are calculating from is Feb 29, return the equivalent result for Feb 28
+ if (clone.getUTCMonth() === 1 && clone.getUTCDate() === 29) {
+ clone.setUTCDate(28);
+ } else {
+ clone.setUTCDate(clone.getUTCDate());
+ }
+
+ clone.setUTCFullYear(clone.getUTCFullYear() + numberOfYears);
return clone;
};
diff --git a/app/assets/javascripts/notes/components/comment_form.vue b/app/assets/javascripts/notes/components/comment_form.vue
index 87b55b19c08..17eded3bec0 100644
--- a/app/assets/javascripts/notes/components/comment_form.vue
+++ b/app/assets/javascripts/notes/components/comment_form.vue
@@ -12,6 +12,7 @@ import {
slugifyWithUnderscore,
} from '~/lib/utils/text_utility';
import { sprintf } from '~/locale';
+import { InternalEvents } from '~/tracking';
import { badgeState } from '~/merge_requests/components/merge_request_header.vue';
import MarkdownEditor from '~/vue_shared/components/markdown/markdown_editor.vue';
import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue';
@@ -48,7 +49,7 @@ export default {
directives: {
GlTooltip: GlTooltipDirective,
},
- mixins: [issuableStateMixin],
+ mixins: [issuableStateMixin, InternalEvents.mixin()],
props: {
noteableType: {
type: String,
@@ -253,6 +254,10 @@ export default {
this.isSubmitting = true;
+ if (isDraft) {
+ eventHub.$emit('noteFormAddToReview', { name: 'noteFormAddToReview' });
+ }
+
trackSavedUsingEditor(
this.$refs.markdownEditor.isContentEditorActive,
`${this.noteableType}_${this.noteType}`,
diff --git a/app/assets/javascripts/notes/components/note_form.vue b/app/assets/javascripts/notes/components/note_form.vue
index 77ce5ea5910..135d595aae5 100644
--- a/app/assets/javascripts/notes/components/note_form.vue
+++ b/app/assets/javascripts/notes/components/note_form.vue
@@ -320,12 +320,14 @@ export default {
);
},
handleAddToReview() {
+ const clickType = this.hasDrafts ? 'noteFormAddToReview' : 'noteFormStartReview';
// check if draft should resolve thread
const shouldResolve =
(this.discussionResolved && !this.isUnresolving) ||
(!this.discussionResolved && this.isResolving);
this.isSubmitting = true;
+ eventHub.$emit(clickType, { name: clickType });
this.$emit(
'handleFormUpdateAddToReview',
this.updatedNoteBody,
diff --git a/app/assets/javascripts/notes/components/notes_app.vue b/app/assets/javascripts/notes/components/notes_app.vue
index 86f93ee425e..eb6764a7937 100644
--- a/app/assets/javascripts/notes/components/notes_app.vue
+++ b/app/assets/javascripts/notes/components/notes_app.vue
@@ -2,6 +2,7 @@
// eslint-disable-next-line no-restricted-imports
import { mapGetters, mapActions } from 'vuex';
import { v4 as uuidv4 } from 'uuid';
+import { InternalEvents } from '~/tracking';
import highlightCurrentUser from '~/behaviors/markdown/highlight_current_user';
import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue';
import OrderedLayout from '~/vue_shared/components/ordered_layout.vue';
@@ -39,7 +40,7 @@ export default {
TimelineEntryItem,
AiSummary: () => import('ee_component/notes/components/ai_summary.vue'),
},
- mixins: [glFeatureFlagsMixin()],
+ mixins: [glFeatureFlagsMixin(), InternalEvents.mixin()],
provide() {
return {
summarizeClientSubscriptionId: uuidv4(),
@@ -165,6 +166,9 @@ export default {
});
}
+ eventHub.$on('noteFormAddToReview', this.handleReviewTracking);
+ eventHub.$on('noteFormStartReview', this.handleReviewTracking);
+
window.addEventListener('hashchange', this.handleHashChanged);
eventHub.$on('notesApp.updateIssuableConfidentiality', this.setConfidentiality);
@@ -177,6 +181,8 @@ export default {
beforeDestroy() {
window.removeEventListener('hashchange', this.handleHashChanged);
eventHub.$off('notesApp.updateIssuableConfidentiality', this.setConfidentiality);
+ eventHub.$off('noteFormStartReview', this.handleReviewTracking);
+ eventHub.$off('noteFormAddToReview', this.handleReviewTracking);
},
methods: {
...mapActions([
@@ -222,6 +228,16 @@ export default {
setAiLoading(loading) {
this.aiLoading = loading;
},
+ handleReviewTracking(event) {
+ const types = {
+ noteFormStartReview: 'merge_request_click_start_review_on_overview_tab',
+ noteFormAddToReview: 'merge_request_click_add_to_review_on_overview_tab',
+ };
+
+ if (this.shouldShow && window.mrTabs && types[event.name]) {
+ this.trackEvent(types[event.name]);
+ }
+ },
},
systemNote: constants.SYSTEM_NOTE,
};
diff --git a/app/assets/javascripts/usage_quotas/storage/components/namespace_storage_app.vue b/app/assets/javascripts/usage_quotas/storage/components/namespace_storage_app.vue
index a812b90e378..1594e125da3 100644
--- a/app/assets/javascripts/usage_quotas/storage/components/namespace_storage_app.vue
+++ b/app/assets/javascripts/usage_quotas/storage/components/namespace_storage_app.vue
@@ -1,20 +1,23 @@
<script>
-import { GlAlert } from '@gitlab/ui';
+import { GlAlert, GlKeysetPagination } from '@gitlab/ui';
import StorageUsageStatistics from 'ee_else_ce/usage_quotas/storage/components/storage_usage_statistics.vue';
import SearchAndSortBar from '~/usage_quotas/components/search_and_sort_bar/search_and_sort_bar.vue';
import DependencyProxyUsage from './dependency_proxy_usage.vue';
import ContainerRegistryUsage from './container_registry_usage.vue';
+import ProjectList from './project_list.vue';
export default {
name: 'NamespaceStorageApp',
components: {
GlAlert,
+ GlKeysetPagination,
StorageUsageStatistics,
DependencyProxyUsage,
ContainerRegistryUsage,
SearchAndSortBar,
+ ProjectList,
},
- inject: ['userNamespace', 'namespaceId'],
+ inject: ['userNamespace', 'namespaceId', 'helpLinks', 'defaultPerPage'],
props: {
namespaceLoadingError: {
type: Boolean,
@@ -31,11 +34,26 @@ export default {
required: false,
default: false,
},
+ isNamespaceProjectsLoading: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
namespace: {
type: Object,
required: false,
default: () => ({}),
},
+ projects: {
+ type: Object,
+ required: false,
+ default: () => ({}),
+ },
+ initialSortBy: {
+ type: String,
+ required: false,
+ default: 'storage',
+ },
},
computed: {
usedStorage() {
@@ -55,6 +73,27 @@ export default {
containerRegistrySizeIsEstimated() {
return this.namespace.rootStorageStatistics?.containerRegistrySizeIsEstimated ?? false;
},
+ projectList() {
+ return this.projects?.nodes ?? [];
+ },
+ pageInfo() {
+ return this.projects?.pageInfo;
+ },
+ showPagination() {
+ return Boolean(this.pageInfo?.hasPreviousPage || this.pageInfo?.hasNextPage);
+ },
+ },
+ methods: {
+ onPrev(before) {
+ if (this.pageInfo?.hasPreviousPage) {
+ this.$emit('fetch-more-projects', { before, last: this.defaultPerPage, first: undefined });
+ }
+ },
+ onNext(after) {
+ if (this.pageInfo?.hasNextPage) {
+ this.$emit('fetch-more-projects', { after, first: this.defaultPerPage });
+ }
+ },
},
};
</script>
@@ -103,7 +142,26 @@ export default {
"
/>
</div>
- <slot name="ee-storage-app"></slot>
+ <project-list
+ :projects="projectList"
+ :is-loading="isNamespaceProjectsLoading"
+ :help-links="helpLinks"
+ :sort-by="initialSortBy"
+ :sort-desc="true"
+ @sortChanged="
+ ($event) => {
+ $emit('sort-changed', $event);
+ }
+ "
+ />
+ <div class="gl-display-flex gl-justify-content-center gl-mt-5">
+ <gl-keyset-pagination
+ v-if="showPagination"
+ v-bind="pageInfo"
+ @prev="onPrev"
+ @next="onNext"
+ />
+ </div>
</section>
</div>
</template>
diff --git a/app/assets/javascripts/usage_quotas/storage/components/project_list.vue b/app/assets/javascripts/usage_quotas/storage/components/project_list.vue
new file mode 100644
index 00000000000..c6f9b1fff03
--- /dev/null
+++ b/app/assets/javascripts/usage_quotas/storage/components/project_list.vue
@@ -0,0 +1,208 @@
+<script>
+import { GlTable, GlLink, GlSprintf, GlIcon } from '@gitlab/ui';
+import { __ } from '~/locale';
+import ProjectAvatar from '~/vue_shared/components/project_avatar.vue';
+import { containerRegistryPopover } from '~/usage_quotas/storage/constants';
+import NumberToHumanSize from '~/vue_shared/components/number_to_human_size/number_to_human_size.vue';
+import HelpPageLink from '~/vue_shared/components/help_page_link/help_page_link.vue';
+import StorageTypeHelpLink from './storage_type_help_link.vue';
+import StorageTypeWarning from './storage_type_warning.vue';
+
+export default {
+ name: 'ProjectList',
+ components: {
+ GlTable,
+ GlLink,
+ GlSprintf,
+ GlIcon,
+ ProjectAvatar,
+ NumberToHumanSize,
+ HelpPageLink,
+ StorageTypeHelpLink,
+ StorageTypeWarning,
+ },
+ inject: ['isUsingProjectEnforcementWithLimits'],
+ props: {
+ projects: {
+ type: Array,
+ required: true,
+ },
+ isLoading: {
+ type: Boolean,
+ required: true,
+ },
+ helpLinks: {
+ type: Object,
+ required: true,
+ },
+ sortBy: {
+ type: String,
+ required: false,
+ default: undefined,
+ },
+ sortDesc: {
+ type: Boolean,
+ required: false,
+ default: undefined,
+ },
+ },
+ created() {
+ this.fields = [
+ { key: 'name', label: __('Project') },
+ { key: 'storage', label: __('Total'), sortable: !this.isUsingProjectEnforcementWithLimits },
+ { key: 'repository', label: __('Repository') },
+ { key: 'snippets', label: __('Snippets') },
+ { key: 'buildArtifacts', label: __('Jobs') },
+ { key: 'lfsObjects', label: __('LFS') },
+ { key: 'packages', label: __('Packages') },
+ { key: 'wiki', label: __('Wiki') },
+ {
+ key: 'containerRegistry',
+ label: __('Containers'),
+ thClass: 'gl-border-l!',
+ tdClass: 'gl-border-l!',
+ },
+ ].map((f) => ({
+ ...f,
+ // eslint-disable-next-line @gitlab/require-i18n-strings
+ thClass: `${f.thClass ?? ''} gl-px-3!`,
+ // eslint-disable-next-line @gitlab/require-i18n-strings
+ tdClass: `${f.tdClass ?? ''} gl-px-3!`,
+ }));
+ },
+ methods: {
+ /**
+ * Builds a gl-table td cell slot name for particular field
+ * @param {string} key
+ * @returns {string} */
+ getHeaderSlotName(key) {
+ return `head(${key})`;
+ },
+ getUsageQuotasUrl(projectUrl) {
+ return `${projectUrl}/-/usage_quotas`;
+ },
+ /**
+ * Creates a relative path from a full project path.
+ * E.g. input `namespace / subgroup / project`
+ * results in `subgroup / project`
+ */
+ getProjectRelativePath(fullPath) {
+ return fullPath.replace(/.*?\s?\/\s?/, '');
+ },
+ isCostFactored(project) {
+ return project.statistics.storageSize !== project.statistics.costFactoredStorageSize;
+ },
+ },
+ containerRegistryPopover,
+};
+</script>
+
+<template>
+ <gl-table
+ :fields="fields"
+ :items="projects"
+ :busy="isLoading"
+ show-empty
+ :empty-text="s__('UsageQuota|No projects to display.')"
+ small
+ stacked="lg"
+ :sort-by="sortBy"
+ :sort-desc="sortDesc"
+ no-local-sorting
+ no-sort-reset
+ @sort-changed="$emit('sortChanged', $event)"
+ >
+ <template v-for="field in fields" #[getHeaderSlotName(field.key)]>
+ <div :key="field.key" :data-testid="'th-' + field.key">
+ {{ field.label }}
+
+ <storage-type-help-link
+ v-if="field.key in helpLinks"
+ :storage-type="field.key"
+ :help-links="helpLinks"
+ /><storage-type-warning v-if="field.key == 'containerRegistry'">
+ {{ $options.containerRegistryPopover.content }}
+ <gl-link :href="$options.containerRegistryPopover.docsLink" target="_blank">
+ {{ __('Learn more.') }}
+ </gl-link>
+ </storage-type-warning>
+ </div>
+ </template>
+
+ <template #cell(name)="{ item: project }">
+ <project-avatar
+ :project-id="project.id"
+ :project-name="project.name"
+ :project-avatar-url="project.avatarUrl"
+ :size="16"
+ :alt="project.name"
+ class="gl-display-inline-block gl-mr-2 gl-text-center!"
+ />
+
+ <gl-link
+ :href="getUsageQuotasUrl(project.webUrl)"
+ class="gl-text-gray-900! js-project-link gl-word-break-word"
+ data-testid="project-link"
+ >
+ {{ getProjectRelativePath(project.nameWithNamespace) }}
+ </gl-link>
+ </template>
+
+ <template #cell(storage)="{ item: project }">
+ <template v-if="isCostFactored(project)">
+ <number-to-human-size :value="project.statistics.costFactoredStorageSize" />
+
+ <div class="gl-text-gray-600 gl-mt-2 gl-font-sm">
+ <gl-sprintf :message="s__('UsageQuotas|(of %{totalStorageSize})')">
+ <template #totalStorageSize>
+ <number-to-human-size :value="project.statistics.storageSize" />
+ </template>
+ </gl-sprintf>
+ <help-page-link href="user/usage_quotas#view-project-fork-storage-usage" target="_blank">
+ <gl-icon name="question-o" :size="12" />
+ </help-page-link>
+ </div>
+ </template>
+ <template v-else>
+ <number-to-human-size :value="project.statistics.storageSize" />
+ </template>
+ </template>
+
+ <template #cell(repository)="{ item: project }">
+ <number-to-human-size
+ :value="project.statistics.repositorySize"
+ data-testid="project-repository-size"
+ />
+ </template>
+
+ <template #cell(lfsObjects)="{ item: project }">
+ <number-to-human-size :value="project.statistics.lfsObjectsSize" />
+ </template>
+
+ <template #cell(buildArtifacts)="{ item: project }">
+ <number-to-human-size :value="project.statistics.buildArtifactsSize" />
+ </template>
+
+ <template #cell(packages)="{ item: project }">
+ <number-to-human-size :value="project.statistics.packagesSize" />
+ </template>
+
+ <template #cell(wiki)="{ item: project }">
+ <number-to-human-size :value="project.statistics.wikiSize" data-testid="project-wiki-size" />
+ </template>
+
+ <template #cell(snippets)="{ item: project }">
+ <number-to-human-size
+ :value="project.statistics.snippetsSize"
+ data-testid="project-snippets-size"
+ />
+ </template>
+
+ <template #cell(containerRegistry)="{ item: project }">
+ <number-to-human-size
+ :value="project.statistics.containerRegistrySize"
+ data-testid="project-containers-registry-size"
+ />
+ </template>
+ </gl-table>
+</template>
diff --git a/app/assets/javascripts/usage_quotas/storage/components/storage_type_help_link.vue b/app/assets/javascripts/usage_quotas/storage/components/storage_type_help_link.vue
new file mode 100644
index 00000000000..c25b1848124
--- /dev/null
+++ b/app/assets/javascripts/usage_quotas/storage/components/storage_type_help_link.vue
@@ -0,0 +1,36 @@
+<script>
+import { GlLink, GlIcon } from '@gitlab/ui';
+import { sprintf } from '~/locale';
+import { HELP_LINK_ARIA_LABEL } from '~/usage_quotas/storage/constants';
+
+export default {
+ name: 'StorageTypeHelpLink',
+ components: {
+ GlLink,
+ GlIcon,
+ },
+ props: {
+ storageType: {
+ type: String,
+ required: true,
+ },
+ helpLinks: {
+ type: Object,
+ required: true,
+ },
+ },
+ computed: {
+ ariaLabel() {
+ return sprintf(HELP_LINK_ARIA_LABEL, {
+ linkTitle: this.storageType,
+ });
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-link :href="helpLinks[storageType]" target="_blank" :aria-label="ariaLabel">
+ <gl-icon name="question-o" :size="12" />
+ </gl-link>
+</template>
diff --git a/app/services/service_ping/submit_service.rb b/app/services/service_ping/submit_service.rb
index 72d0c022609..7243bc411f7 100644
--- a/app/services/service_ping/submit_service.rb
+++ b/app/services/service_ping/submit_service.rb
@@ -16,7 +16,7 @@ module ServicePing
end
def execute
- return unless ServicePing::ServicePingSettings.product_intelligence_enabled?
+ return unless ServicePing::ServicePingSettings.enabled_and_consented?
start_time = Time.current
diff --git a/config/events/merge_request_click_add_to_review_on_changes_tab.yml b/config/events/merge_request_click_add_to_review_on_changes_tab.yml
new file mode 100644
index 00000000000..5d504b617a0
--- /dev/null
+++ b/config/events/merge_request_click_add_to_review_on_changes_tab.yml
@@ -0,0 +1,20 @@
+---
+description: User clicks the "Add to review" button on the Merge Request Changes tab
+category: InternalEventTracking
+action: merge_request_click_add_to_review_on_changes_tab
+identifiers:
+- project
+- namespace
+- user
+product_section: dev
+product_stage: create
+product_group: code_review
+milestone: '16.9'
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/141911
+distributions:
+- ce
+- ee
+tiers:
+- free
+- premium
+- ultimate
diff --git a/config/events/merge_request_click_add_to_review_on_overview_tab.yml b/config/events/merge_request_click_add_to_review_on_overview_tab.yml
new file mode 100644
index 00000000000..0001aada7b4
--- /dev/null
+++ b/config/events/merge_request_click_add_to_review_on_overview_tab.yml
@@ -0,0 +1,20 @@
+---
+description: User clicks the "Add to review" button on the Merge Request Overview tab
+category: InternalEventTracking
+action: merge_request_click_add_to_review_on_overview_tab
+identifiers:
+- project
+- namespace
+- user
+product_section: dev
+product_stage: create
+product_group: code_review
+milestone: '16.9'
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/141911
+distributions:
+- ce
+- ee
+tiers:
+- free
+- premium
+- ultimate
diff --git a/config/events/merge_request_click_start_review_on_changes_tab.yml b/config/events/merge_request_click_start_review_on_changes_tab.yml
new file mode 100644
index 00000000000..a1cd6c0bda3
--- /dev/null
+++ b/config/events/merge_request_click_start_review_on_changes_tab.yml
@@ -0,0 +1,20 @@
+---
+description: User clicks the "Start a review" button on the Merge Request Changes tab
+category: InternalEventTracking
+action: merge_request_click_start_review_on_changes_tab
+identifiers:
+- project
+- namespace
+- user
+product_section: dev
+product_stage: create
+product_group: code_review
+milestone: '16.9'
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/141911
+distributions:
+- ce
+- ee
+tiers:
+- free
+- premium
+- ultimate
diff --git a/config/events/merge_request_click_start_review_on_overview_tab.yml b/config/events/merge_request_click_start_review_on_overview_tab.yml
new file mode 100644
index 00000000000..ec7be2a6c1e
--- /dev/null
+++ b/config/events/merge_request_click_start_review_on_overview_tab.yml
@@ -0,0 +1,20 @@
+---
+description: User clicks the "Start a review" button on the Merge Request Overview tab
+category: InternalEventTracking
+action: merge_request_click_start_review_on_overview_tab
+identifiers:
+- project
+- namespace
+- user
+product_section: dev
+product_stage: create
+product_group: code_review
+milestone: '16.9'
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/141911
+distributions:
+- ce
+- ee
+tiers:
+- free
+- premium
+- ultimate
diff --git a/config/feature_flags/gitlab_com_derisk/github_importer_attachments.yml b/config/feature_flags/gitlab_com_derisk/github_importer_attachments.yml
deleted file mode 100644
index ab068225d2c..00000000000
--- a/config/feature_flags/gitlab_com_derisk/github_importer_attachments.yml
+++ /dev/null
@@ -1,9 +0,0 @@
----
-name: github_importer_attachments
-feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/436400
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/140524
-rollout_issue_url: https://gitlab.com/gitlab-com/gl-infra/production/-/issues/17318
-milestone: '16.8'
-group: group::import and integrate
-type: gitlab_com_derisk
-default_enabled: false
diff --git a/config/metrics/counts_28d/count_total_merge_request_click_add_to_review_on_changes_tab_monthly.yml b/config/metrics/counts_28d/count_total_merge_request_click_add_to_review_on_changes_tab_monthly.yml
new file mode 100644
index 00000000000..160258d006e
--- /dev/null
+++ b/config/metrics/counts_28d/count_total_merge_request_click_add_to_review_on_changes_tab_monthly.yml
@@ -0,0 +1,26 @@
+---
+key_path: counts.count_total_merge_request_click_add_to_review_on_changes_tab_monthly
+description: Monthly count of clicks on the Add to review button on the MR Changes tab
+product_section: dev
+product_stage: create
+product_group: code_review
+performance_indicator_type: []
+value_type: number
+status: active
+milestone: '16.9'
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/141911
+time_frame: 28d
+data_source: internal_events
+data_category: optional
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
+options:
+ events:
+ - merge_request_click_add_to_review_on_changes_tab
+events:
+- name: merge_request_click_add_to_review_on_changes_tab
diff --git a/config/metrics/counts_28d/count_total_merge_request_click_add_to_review_on_overview_tab_monthly.yml b/config/metrics/counts_28d/count_total_merge_request_click_add_to_review_on_overview_tab_monthly.yml
new file mode 100644
index 00000000000..8f6942d62e7
--- /dev/null
+++ b/config/metrics/counts_28d/count_total_merge_request_click_add_to_review_on_overview_tab_monthly.yml
@@ -0,0 +1,26 @@
+---
+key_path: counts.count_total_merge_request_click_add_to_review_on_overview_tab_monthly
+description: Monthly count of clicks on the Add to review button on the MR Overview tab
+product_section: dev
+product_stage: create
+product_group: code_review
+performance_indicator_type: []
+value_type: number
+status: active
+milestone: '16.9'
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/141911
+time_frame: 28d
+data_source: internal_events
+data_category: optional
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
+options:
+ events:
+ - merge_request_click_add_to_review_on_overview_tab
+events:
+- name: merge_request_click_add_to_review_on_overview_tab
diff --git a/config/metrics/counts_28d/count_total_merge_request_click_start_review_on_changes_tab_monthly.yml b/config/metrics/counts_28d/count_total_merge_request_click_start_review_on_changes_tab_monthly.yml
new file mode 100644
index 00000000000..8b769405979
--- /dev/null
+++ b/config/metrics/counts_28d/count_total_merge_request_click_start_review_on_changes_tab_monthly.yml
@@ -0,0 +1,26 @@
+---
+key_path: counts.count_total_merge_request_click_start_review_on_changes_tab_monthly
+description: Monthly count of clicks on the Start a Review button on the MR Changes tab
+product_section: dev
+product_stage: create
+product_group: code_review
+performance_indicator_type: []
+value_type: number
+status: active
+milestone: '16.9'
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/141911
+time_frame: 28d
+data_source: internal_events
+data_category: optional
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
+options:
+ events:
+ - merge_request_click_start_review_on_changes_tab
+events:
+- name: merge_request_click_start_review_on_changes_tab
diff --git a/config/metrics/counts_28d/count_total_merge_request_click_start_review_on_overview_tab_monthly.yml b/config/metrics/counts_28d/count_total_merge_request_click_start_review_on_overview_tab_monthly.yml
new file mode 100644
index 00000000000..203cd468f3d
--- /dev/null
+++ b/config/metrics/counts_28d/count_total_merge_request_click_start_review_on_overview_tab_monthly.yml
@@ -0,0 +1,26 @@
+---
+key_path: counts.count_total_merge_request_click_start_review_on_overview_tab_monthly
+description: Monthly count of clicks on the Start a Review button on the MR Overview tab
+product_section: dev
+product_stage: create
+product_group: code_review
+performance_indicator_type: []
+value_type: number
+status: active
+milestone: '16.9'
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/141911
+time_frame: 28d
+data_source: internal_events
+data_category: optional
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
+options:
+ events:
+ - merge_request_click_start_review_on_overview_tab
+events:
+- name: merge_request_click_start_review_on_overview_tab
diff --git a/config/metrics/counts_7d/count_total_merge_request_click_add_to_review_on_changes_tab_weekly.yml b/config/metrics/counts_7d/count_total_merge_request_click_add_to_review_on_changes_tab_weekly.yml
new file mode 100644
index 00000000000..d764a377dc5
--- /dev/null
+++ b/config/metrics/counts_7d/count_total_merge_request_click_add_to_review_on_changes_tab_weekly.yml
@@ -0,0 +1,26 @@
+---
+key_path: counts.count_total_merge_request_click_add_to_review_on_changes_tab_weekly
+description: Weekly count of clicks on the Add to review button on the MR Changes tab
+product_section: dev
+product_stage: create
+product_group: code_review
+performance_indicator_type: []
+value_type: number
+status: active
+milestone: '16.9'
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/141911
+time_frame: 7d
+data_source: internal_events
+data_category: optional
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
+options:
+ events:
+ - merge_request_click_add_to_review_on_changes_tab
+events:
+- name: merge_request_click_add_to_review_on_changes_tab
diff --git a/config/metrics/counts_7d/count_total_merge_request_click_add_to_review_on_overview_tab_weekly.yml b/config/metrics/counts_7d/count_total_merge_request_click_add_to_review_on_overview_tab_weekly.yml
new file mode 100644
index 00000000000..c11ac48986e
--- /dev/null
+++ b/config/metrics/counts_7d/count_total_merge_request_click_add_to_review_on_overview_tab_weekly.yml
@@ -0,0 +1,26 @@
+---
+key_path: counts.count_total_merge_request_click_add_to_review_on_overview_tab_weekly
+description: Weekly count of clicks on the Add to review button on the MR Overview tab
+product_section: dev
+product_stage: create
+product_group: code_review
+performance_indicator_type: []
+value_type: number
+status: active
+milestone: '16.9'
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/141911
+time_frame: 7d
+data_source: internal_events
+data_category: optional
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
+options:
+ events:
+ - merge_request_click_add_to_review_on_overview_tab
+events:
+- name: merge_request_click_add_to_review_on_overview_tab
diff --git a/config/metrics/counts_7d/count_total_merge_request_click_start_review_on_changes_tab_weekly.yml b/config/metrics/counts_7d/count_total_merge_request_click_start_review_on_changes_tab_weekly.yml
new file mode 100644
index 00000000000..0fdf6762da1
--- /dev/null
+++ b/config/metrics/counts_7d/count_total_merge_request_click_start_review_on_changes_tab_weekly.yml
@@ -0,0 +1,26 @@
+---
+key_path: counts.count_total_merge_request_click_start_review_on_changes_tab_weekly
+description: Weekly count of clicks on the Start a Review button on the MR Changes tab
+product_section: dev
+product_stage: create
+product_group: code_review
+performance_indicator_type: []
+value_type: number
+status: active
+milestone: '16.9'
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/141911
+time_frame: 7d
+data_source: internal_events
+data_category: optional
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
+options:
+ events:
+ - merge_request_click_start_review_on_changes_tab
+events:
+- name: merge_request_click_start_review_on_changes_tab
diff --git a/config/metrics/counts_7d/count_total_merge_request_click_start_review_on_overview_tab_weekly.yml b/config/metrics/counts_7d/count_total_merge_request_click_start_review_on_overview_tab_weekly.yml
new file mode 100644
index 00000000000..4ff3f9b090c
--- /dev/null
+++ b/config/metrics/counts_7d/count_total_merge_request_click_start_review_on_overview_tab_weekly.yml
@@ -0,0 +1,26 @@
+---
+key_path: counts.count_total_merge_request_click_start_review_on_overview_tab_weekly
+description: Weekly count of clicks on the Start a Review button on the MR Overview tab
+product_section: dev
+product_stage: create
+product_group: code_review
+performance_indicator_type: []
+value_type: number
+status: active
+milestone: '16.9'
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/141911
+time_frame: 7d
+data_source: internal_events
+data_category: optional
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
+options:
+ events:
+ - merge_request_click_start_review_on_overview_tab
+events:
+- name: merge_request_click_start_review_on_overview_tab
diff --git a/config/metrics/counts_all/count_total_merge_request_click_add_to_review_on_changes_tab.yml b/config/metrics/counts_all/count_total_merge_request_click_add_to_review_on_changes_tab.yml
new file mode 100644
index 00000000000..0383f854a4e
--- /dev/null
+++ b/config/metrics/counts_all/count_total_merge_request_click_add_to_review_on_changes_tab.yml
@@ -0,0 +1,26 @@
+---
+key_path: counts.count_total_merge_request_click_add_to_review_on_changes_tab
+description: Total count of clicks on the Add to review button on the MR Changes tab
+product_section: dev
+product_stage: create
+product_group: code_review
+performance_indicator_type: []
+value_type: number
+status: active
+milestone: '16.9'
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/141911
+time_frame: all
+data_source: internal_events
+data_category: optional
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
+options:
+ events:
+ - merge_request_click_add_to_review_on_changes_tab
+events:
+- name: merge_request_click_add_to_review_on_changes_tab
diff --git a/config/metrics/counts_all/count_total_merge_request_click_add_to_review_on_overview_tab.yml b/config/metrics/counts_all/count_total_merge_request_click_add_to_review_on_overview_tab.yml
new file mode 100644
index 00000000000..e9ed2d5c155
--- /dev/null
+++ b/config/metrics/counts_all/count_total_merge_request_click_add_to_review_on_overview_tab.yml
@@ -0,0 +1,26 @@
+---
+key_path: counts.count_total_merge_request_click_add_to_review_on_overview_tab
+description: Total count of clicks on the Add to review button on the MR Overview tab
+product_section: dev
+product_stage: create
+product_group: code_review
+performance_indicator_type: []
+value_type: number
+status: active
+milestone: '16.9'
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/141911
+time_frame: all
+data_source: internal_events
+data_category: optional
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
+options:
+ events:
+ - merge_request_click_add_to_review_on_overview_tab
+events:
+- name: merge_request_click_add_to_review_on_overview_tab
diff --git a/config/metrics/counts_all/count_total_merge_request_click_start_review_on_changes_tab.yml b/config/metrics/counts_all/count_total_merge_request_click_start_review_on_changes_tab.yml
new file mode 100644
index 00000000000..bac1dbbc1cb
--- /dev/null
+++ b/config/metrics/counts_all/count_total_merge_request_click_start_review_on_changes_tab.yml
@@ -0,0 +1,26 @@
+---
+key_path: counts.count_total_merge_request_click_start_review_on_changes_tab
+description: Total count of clicks on the Start a Review button on the MR Changes tab
+product_section: dev
+product_stage: create
+product_group: code_review
+performance_indicator_type: []
+value_type: number
+status: active
+milestone: '16.9'
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/141911
+time_frame: all
+data_source: internal_events
+data_category: optional
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
+options:
+ events:
+ - merge_request_click_start_review_on_changes_tab
+events:
+- name: merge_request_click_start_review_on_changes_tab
diff --git a/config/metrics/counts_all/count_total_merge_request_click_start_review_on_overview_tab.yml b/config/metrics/counts_all/count_total_merge_request_click_start_review_on_overview_tab.yml
new file mode 100644
index 00000000000..7ee5058c7ca
--- /dev/null
+++ b/config/metrics/counts_all/count_total_merge_request_click_start_review_on_overview_tab.yml
@@ -0,0 +1,26 @@
+---
+key_path: counts.count_total_merge_request_click_start_review_on_overview_tab
+description: Total count of clicks on the Start a Review button on the MR Overview tab
+product_section: dev
+product_stage: create
+product_group: code_review
+performance_indicator_type: []
+value_type: number
+status: active
+milestone: '16.9'
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/141911
+time_frame: all
+data_source: internal_events
+data_category: optional
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
+options:
+ events:
+ - merge_request_click_start_review_on_overview_tab
+events:
+- name: merge_request_click_start_review_on_overview_tab
diff --git a/doc/api/resource_state_events.md b/doc/api/resource_state_events.md
index 1c8f743ca72..c2b2c80883a 100644
--- a/doc/api/resource_state_events.md
+++ b/doc/api/resource_state_events.md
@@ -13,6 +13,9 @@ Resource state events keep track of what happens to GitLab [issues](../user/proj
Use them to track which state was set, who did it, and when it happened.
+Resource state events API does not track the initial state ("create" or "open") of resources.
+For a resource that was not closed or re-opened, an empty list is returned.
+
## Issues
### List project issue state events
diff --git a/doc/development/documentation/restful_api_styleguide.md b/doc/development/documentation/restful_api_styleguide.md
index 66bb662e1c7..ddddeca8168 100644
--- a/doc/development/documentation/restful_api_styleguide.md
+++ b/doc/development/documentation/restful_api_styleguide.md
@@ -32,9 +32,8 @@ In the Markdown doc for a resource (AKA endpoint):
- Every method must have a detailed [description of the response body](#response-body-description).
- Every method must have a response body example (in JSON format).
- If an attribute is available only to higher level tiers than the other
- attributes, add the appropriate inline [tier badge](styleguide/index.md#product-tier-badges).
- Put the badge in the **Attribute** column, like the
- `**(<tier>)**` code in the following template.
+ attributes, add the appropriate tier to the description. If an attribute is
+ for Premium, include that it's also available for Ultimate.
After a new API documentation page is added, [add an entry in the global navigation](site_architecture/global_nav.md#add-a-navigation-entry). [Example](https://gitlab.com/gitlab-org/gitlab-docs/-/merge_requests/3497).
@@ -65,7 +64,7 @@ Supported attributes:
| Attribute | Type | Required | Description |
|--------------------------|----------|----------|-----------------------|
| `attribute` | datatype | Yes | Detailed description. |
-| `attribute` **(<tier>)** | datatype | No | Detailed description. |
+| `attribute` | datatype | No | Detailed description. |
| `attribute` | datatype | No | Detailed description. |
| `attribute` | datatype | No | Detailed description. |
@@ -75,7 +74,7 @@ response attributes:
| Attribute | Type | Description |
|--------------------------|----------|-----------------------|
| `attribute` | datatype | Detailed description. |
-| `attribute` **(<tier>)** | datatype | Detailed description. |
+| `attribute` | datatype | Detailed description. |
Example request:
@@ -146,7 +145,7 @@ Sort the table by required attributes first, then alphabetically.
| Attribute | Type | Required | Description |
|------------------------------|---------------|----------|-----------------------------------------------------|
| `title` | string | Yes | Title of the issue. |
-| `assignee_ids` **(PREMIUM ALL)** | integer array | No | IDs of the users to assign the issue to. |
+| `assignee_ids` | integer array | No | IDs of the users to assign the issue to. Ultimate only. |
| `confidential` | boolean | No | Sets the issue to confidential. Default is `false`. |
```
@@ -155,7 +154,7 @@ Rendered example:
| Attribute | Type | Required | Description |
|------------------------------|---------------|----------|-----------------------------------------------------|
| `title` | string | Yes | Title of the issue. |
-| `assignee_ids` **(PREMIUM ALL)** | integer array | No | IDs of the users to assign the issue to. |
+| `assignee_ids` | integer array | No | IDs of the users to assign the issue to. Premium and Ultimate only. |
| `confidential` | boolean | No | Sets the issue to confidential. Default is `false`. |
For information about writing attribute descriptions, see the [GraphQL API description style guide](../api_graphql_styleguide.md#description-style-guide).
@@ -181,7 +180,7 @@ Sort the table alphabetically.
```markdown
| Attribute | Type | Description |
|------------------------------|---------------|-------------------------------------------|
-| `assignee_ids` **(PREMIUM ALL)** | integer array | IDs of the users to assign the issue to. |
+| `assignee_ids` | integer array | IDs of the users to assign the issue to. Premium and Ultimate only. |
| `confidential` | boolean | Whether the issue is confidential or not. |
| `title` | string | Title of the issue. |
```
@@ -190,7 +189,7 @@ Rendered example:
| Attribute | Type | Description |
|------------------------------|---------------|-------------------------------------------|
-| `assignee_ids` **(PREMIUM ALL)** | integer array | IDs of the users to assign the issue to. |
+| `assignee_ids` | integer array | IDs of the users to assign the issue to. Premium and Ultimate only. |
| `confidential` | boolean | Whether the issue is confidential or not. |
| `title` | string | Title of the issue. |
diff --git a/doc/development/documentation/styleguide/index.md b/doc/development/documentation/styleguide/index.md
index a41390558ad..4f812712651 100644
--- a/doc/development/documentation/styleguide/index.md
+++ b/doc/development/documentation/styleguide/index.md
@@ -1648,7 +1648,7 @@ Tier badges provide information about a feature and are displayed next to the to
Assign tier badges to:
-- All H1 topic titles, except the pages under `doc/development/*` and `doc/solutions/*`.
+- Most H1 topic titles, except the pages under `doc/development/*` and `doc/solutions/*`.
- Topic titles that don't apply to the same tier as the H1.
The H1 tier badge should be the badge that applies to the lowest tier for the features on the page.
@@ -1731,10 +1731,19 @@ Or add the status by itself:
##### Inline tier badges
-Do not add tier badges inline with other text, except for [API attributes](../restful_api_styleguide.md).
+Do not add tier badges inline with other text.
The single source of truth for a feature should be the topic where the
functionality is described.
+If you need to mention a tier inline, write it in plain text. For example,
+for an API topic:
+
+```markdown
+IDs of the users to assign the issue to. Ultimate only.
+```
+
+For more examples, see the [REST API style guide](../restful_api_styleguide.md).
+
##### Administrator documentation tier badges
Topics that are only for instance administrators should be badged `<TIER> SELF`. Instance
diff --git a/doc/user/ai_features.md b/doc/user/ai_features.md
index 3e55661d00f..0891ae20918 100644
--- a/doc/user/ai_features.md
+++ b/doc/user/ai_features.md
@@ -14,22 +14,22 @@ GitLab is creating AI-assisted features across our DevSecOps platform. These fea
| Goal | Feature | Tier/Offering/Status |
|---|---|---|
-| Helps you discover or recall Git commands when and where you need them. | [Git suggestions](https://gitlab.com/gitlab-org/gitlab/-/issues/409636) | **(ULTIMATE SAAS EXPERIMENT)** |
-| Assists with quickly getting everyone up to speed on lengthy conversations to help ensure you are all on the same page. | [Discussion summary](#summarize-issue-discussions-with-discussion-summary) | **(ULTIMATE SAAS EXPERIMENT)** |
-| Generates issue descriptions. | [Issue description generation](#summarize-an-issue-with-issue-description-generation) | **(ULTIMATE SAAS EXPERIMENT)** |
-| Helps you write code more efficiently by viewing code suggestions as you type. <br><br><i class="fa fa-youtube-play youtube" aria-hidden="true"></i> [Watch overview](https://www.youtube.com/watch?v=hCAyCTacdAQ) | [Code Suggestions](project/repository/code_suggestions/index.md) | For SaaS: **(FREE)**<br><br> For self-managed: **(PREMIUM)** |
-| Automates repetitive tasks and helps catch bugs early. | [Test generation](gitlab_duo_chat.md#write-tests-in-the-ide) | **(ULTIMATE BETA)** |
-| Generates a description for the merge request based on the contents of the template. | [Merge request template population](project/merge_requests/ai_in_merge_requests.md#fill-in-merge-request-templates) | **(ULTIMATE SAAS EXPERIMENT)** |
-| Assists in creating faster and higher-quality reviews by automatically suggesting reviewers for your merge request. <br><br><i class="fa fa-youtube-play youtube" aria-hidden="true"></i> [Watch overview](https://www.youtube.com/watch?v=ivwZQgh4Rxw) | [Suggested Reviewers](project/merge_requests/reviews/index.md#gitlab-duo-suggested-reviewers) | **(ULTIMATE SAAS)** |
-| Efficiently communicates the impact of your merge request changes. | [Merge request summary](project/merge_requests/ai_in_merge_requests.md#summarize-merge-request-changes) | **(ULTIMATE SAAS EXPERIMENT)** |
-| Helps ease merge request handoff between authors and reviewers and help reviewers efficiently understand suggestions. | [Code review summary](project/merge_requests/ai_in_merge_requests.md#summarize-my-merge-request-review) | **(ULTIMATE SAAS EXPERIMENT)** |
-| Helps you remediate vulnerabilities more efficiently, boost your skills, and write more secure code. <br><br><i class="fa fa-youtube-play youtube" aria-hidden="true"></i> [Watch overview](https://www.youtube.com/watch?v=6sDf73QOav8) | [Vulnerability summary](application_security/vulnerabilities/index.md#explaining-a-vulnerability) | **(ULTIMATE SAAS BETA)** |
-| Generates a merge request containing the changes required to mitigate a vulnerability. | [Vulnerability resolution](application_security/vulnerabilities/index.md#explaining-a-vulnerability) | **(ULTIMATE SAAS EXPERIMENT)** |
-| Helps you understand code by explaining it in English language. <br><br><i class="fa fa-youtube-play youtube" aria-hidden="true"></i> [Watch overview](https://www.youtube.com/watch?v=1izKaLmmaCA) | [Code explanation](#explain-code-in-the-web-ui-with-code-explanation) | **(ULTIMATE SAAS EXPERIMENT)** |
-| Processes and generates text and code in a conversational manner. Helps you quickly identify useful information in large volumes of text in issues, epics, code, and GitLab documentation. | [GitLab Duo Chat](gitlab_duo_chat.md) | **(ULTIMATE ALL BETA)** |
-| Assists you in determining the root cause for a pipeline failure and failed CI/CD build. | [Root cause analysis](#root-cause-analysis) | **(ULTIMATE SAAS EXPERIMENT)** |
-| Assists you with predicting productivity metrics and identifying anomalies across your software development lifecycle. | [Value stream forecasting](#forecast-deployment-frequency-with-value-stream-forecasting) | **(ULTIMATE ALL EXPERIMENT)** |
-| Processes and responds to your questions about your application's usage data. | [Product Analytics](product_analytics/index.md) | **(ULTIMATE SAAS EXPERIMENT)** |
+| Helps you discover or recall Git commands when and where you need them. | [Git suggestions](https://gitlab.com/gitlab-org/gitlab/-/issues/409636) | **Tier:** Ultimate <br>**Offering:** SaaS <br>**Status:** Experiment |
+| Assists with quickly getting everyone up to speed on lengthy conversations to help ensure you are all on the same page. | [Discussion summary](#summarize-issue-discussions-with-discussion-summary) | **Tier:** Ultimate <br>**Offering:** SaaS <br>**Status:** Experiment |
+| Generates issue descriptions. | [Issue description generation](#summarize-an-issue-with-issue-description-generation) | **Tier:** Ultimate <br>**Offering:** SaaS <br>**Status:** Experiment |
+| Helps you write code more efficiently by viewing code suggestions as you type. <br><br><i class="fa fa-youtube-play youtube" aria-hidden="true"></i> [Watch overview](https://www.youtube.com/watch?v=hCAyCTacdAQ) | [Code Suggestions](project/repository/code_suggestions/index.md) | **Offering:** SaaS **Tier:** Free <br><br>**Offering:** Self-managed **Tier:** Premium and Ultimate |
+| Automates repetitive tasks and helps catch bugs early. | [Test generation](gitlab_duo_chat.md#write-tests-in-the-ide) | **Tier:** Ultimate <br>**Offering:** SaaS, self-managed <br>**Status:** Beta |
+| Generates a description for the merge request based on the contents of the template. | [Merge request template population](project/merge_requests/ai_in_merge_requests.md#fill-in-merge-request-templates) | **Tier:** Ultimate <br>**Offering:** SaaS <br>**Status:** Experiment |
+| Assists in creating faster and higher-quality reviews by automatically suggesting reviewers for your merge request. <br><br><i class="fa fa-youtube-play youtube" aria-hidden="true"></i> [Watch overview](https://www.youtube.com/watch?v=ivwZQgh4Rxw) | [Suggested Reviewers](project/merge_requests/reviews/index.md#gitlab-duo-suggested-reviewers) | **Tier:** Ultimate <br>**Offering:** SaaS |
+| Efficiently communicates the impact of your merge request changes. | [Merge request summary](project/merge_requests/ai_in_merge_requests.md#summarize-merge-request-changes) | **Tier:** Ultimate <br>**Offering:** SaaS <br>**Status:** Experiment |
+| Helps ease merge request handoff between authors and reviewers and help reviewers efficiently understand suggestions. | [Code review summary](project/merge_requests/ai_in_merge_requests.md#summarize-my-merge-request-review) | **Tier:** Ultimate <br>**Offering:** SaaS <br>**Status:** Experiment |
+| Helps you remediate vulnerabilities more efficiently, boost your skills, and write more secure code. <br><br><i class="fa fa-youtube-play youtube" aria-hidden="true"></i> [Watch overview](https://www.youtube.com/watch?v=6sDf73QOav8) | [Vulnerability summary](application_security/vulnerabilities/index.md#explaining-a-vulnerability) | **Tier:** Ultimate <br>**Offering:** SaaS <br>**Status:** Beta |
+| Generates a merge request containing the changes required to mitigate a vulnerability. | [Vulnerability resolution](application_security/vulnerabilities/index.md#explaining-a-vulnerability) | **Tier:** Ultimate <br>**Offering:** SaaS <br>**Status:** Experiment |
+| Helps you understand code by explaining it in English language. <br><br><i class="fa fa-youtube-play youtube" aria-hidden="true"></i> [Watch overview](https://www.youtube.com/watch?v=1izKaLmmaCA) | [Code explanation](#explain-code-in-the-web-ui-with-code-explanation) | **Tier:** Ultimate <br>**Offering:** SaaS <br>**Status:** Experiment |
+| Processes and generates text and code in a conversational manner. Helps you quickly identify useful information in large volumes of text in issues, epics, code, and GitLab documentation. | [GitLab Duo Chat](gitlab_duo_chat.md) | **Tier:** Ultimate <br>**Offering:** SaaS, self-managed<br>**Status:** Beta |
+| Assists you in determining the root cause for a pipeline failure and failed CI/CD build. | [Root cause analysis](#root-cause-analysis) | **Tier:** Ultimate <br>**Offering:** SaaS <br>**Status:** Experiment |
+| Assists you with predicting productivity metrics and identifying anomalies across your software development lifecycle. | [Value stream forecasting](#forecast-deployment-frequency-with-value-stream-forecasting) | **Tier:** Ultimate <br>**Offering:** SaaS, self-managed <br>**Status:** Experiment |
+| Processes and responds to your questions about your application's usage data. | [Product Analytics](product_analytics/index.md) | **Tier:** Ultimate <br>**Offering:** SaaS <br>**Status:** Experiment |
## Enable AI/ML features
diff --git a/lib/bulk_imports/common/pipelines/wiki_pipeline.rb b/lib/bulk_imports/common/pipelines/wiki_pipeline.rb
index 68d511b065f..429a28dcb4c 100644
--- a/lib/bulk_imports/common/pipelines/wiki_pipeline.rb
+++ b/lib/bulk_imports/common/pipelines/wiki_pipeline.rb
@@ -22,7 +22,12 @@ module BulkImports
wiki = context.portable.wiki
url = data[:url].sub("://", "://oauth2:#{context.configuration.access_token}@")
- Gitlab::UrlBlocker.validate!(url, schemes: %w[http https], allow_local_network: allow_local_requests?, allow_localhost: allow_local_requests?)
+ Gitlab::HTTP_V2::UrlBlocker.validate!(
+ url,
+ schemes: %w[http https],
+ allow_local_network: allow_local_requests?,
+ allow_localhost: allow_local_requests?,
+ deny_all_requests_except_allowed: Gitlab::CurrentSettings.deny_all_requests_except_allowed?)
wiki.create_wiki_repository
wiki.repository.fetch_as_mirror(url)
diff --git a/lib/bulk_imports/projects/pipelines/repository_pipeline.rb b/lib/bulk_imports/projects/pipelines/repository_pipeline.rb
index a2b1f8c5176..04c887441f4 100644
--- a/lib/bulk_imports/projects/pipelines/repository_pipeline.rb
+++ b/lib/bulk_imports/projects/pipelines/repository_pipeline.rb
@@ -21,7 +21,12 @@ module BulkImports
url = url.sub("://", "://oauth2:#{context.configuration.access_token}@")
project = context.portable
- Gitlab::UrlBlocker.validate!(url, schemes: %w[http https], allow_local_network: allow_local_requests?, allow_localhost: allow_local_requests?)
+ Gitlab::HTTP_V2::UrlBlocker.validate!(
+ url,
+ schemes: %w[http https],
+ allow_local_network: allow_local_requests?,
+ allow_localhost: allow_local_requests?,
+ deny_all_requests_except_allowed: Gitlab::CurrentSettings.deny_all_requests_except_allowed?)
project.ensure_repository
project.repository.fetch_as_mirror(url)
diff --git a/lib/bulk_imports/projects/pipelines/snippets_repository_pipeline.rb b/lib/bulk_imports/projects/pipelines/snippets_repository_pipeline.rb
index 39c9c121797..a371c33d9ea 100644
--- a/lib/bulk_imports/projects/pipelines/snippets_repository_pipeline.rb
+++ b/lib/bulk_imports/projects/pipelines/snippets_repository_pipeline.rb
@@ -53,10 +53,11 @@ module BulkImports
end
def validate_url(url)
- Gitlab::UrlBlocker.validate!(
+ Gitlab::HTTP_V2::UrlBlocker.validate!(
url,
allow_local_network: allow_local_requests?,
allow_localhost: allow_local_requests?,
+ deny_all_requests_except_allowed: Gitlab::CurrentSettings.deny_all_requests_except_allowed?,
schemes: %w[http https]
)
end
diff --git a/lib/gitlab/database.rb b/lib/gitlab/database.rb
index 6222155d812..a771cf24db9 100644
--- a/lib/gitlab/database.rb
+++ b/lib/gitlab/database.rb
@@ -33,7 +33,7 @@ module Gitlab
MAX_TEXT_SIZE_LIMIT = 1_000_000
# Migrations before this version may have been removed
- MIN_SCHEMA_GITLAB_VERSION = '15.11'
+ MIN_SCHEMA_GITLAB_VERSION = '16.7'
# Schema we store dynamically managed partitions in (e.g. for time partitioning)
DYNAMIC_PARTITIONS_SCHEMA = :gitlab_partitions_dynamic
diff --git a/lib/gitlab/error_tracking/error_repository/open_api_strategy.rb b/lib/gitlab/error_tracking/error_repository/open_api_strategy.rb
index 3b0b4c6e935..9b9b0f65633 100644
--- a/lib/gitlab/error_tracking/error_repository/open_api_strategy.rb
+++ b/lib/gitlab/error_tracking/error_repository/open_api_strategy.rb
@@ -232,7 +232,11 @@ module Gitlab
url = Gitlab::CurrentSettings.current_application_settings.error_tracking_api_url ||
'http://localhost:8080'
- Gitlab::UrlBlocker.validate!(url, schemes: %w[http https], allow_localhost: true)
+ Gitlab::HTTP_V2::UrlBlocker.validate!(
+ url,
+ schemes: %w[http https],
+ allow_localhost: true,
+ deny_all_requests_except_allowed: Gitlab::CurrentSettings.deny_all_requests_except_allowed?)
URI(url)
end
diff --git a/lib/gitlab/github_gists_import/importer/gist_importer.rb b/lib/gitlab/github_gists_import/importer/gist_importer.rb
index 71dfe5e2aa5..c2456f83711 100644
--- a/lib/gitlab/github_gists_import/importer/gist_importer.rb
+++ b/lib/gitlab/github_gists_import/importer/gist_importer.rb
@@ -58,11 +58,13 @@ module Gitlab
end
def get_resolved_address
- validated_pull_url, host = Gitlab::UrlBlocker.validate!(gist.git_pull_url,
- schemes: Project::VALID_IMPORT_PROTOCOLS,
- ports: Project::VALID_IMPORT_PORTS,
- allow_localhost: allow_local_requests?,
- allow_local_network: allow_local_requests?)
+ validated_pull_url, host = Gitlab::HTTP_V2::UrlBlocker.validate!(
+ gist.git_pull_url,
+ schemes: Project::VALID_IMPORT_PROTOCOLS,
+ ports: Project::VALID_IMPORT_PORTS,
+ allow_localhost: allow_local_requests?,
+ allow_local_network: allow_local_requests?,
+ deny_all_requests_except_allowed: Gitlab::CurrentSettings.deny_all_requests_except_allowed?)
host.present? ? validated_pull_url.host.to_s : ''
end
diff --git a/lib/gitlab/github_import/importer/attachments/base_importer.rb b/lib/gitlab/github_import/importer/attachments/base_importer.rb
index 844008f8087..9dfa6bb2ff6 100644
--- a/lib/gitlab/github_import/importer/attachments/base_importer.rb
+++ b/lib/gitlab/github_import/importer/attachments/base_importer.rb
@@ -52,8 +52,6 @@ module Gitlab
end
def has_attachments?(object)
- return true if Feature.disabled?(:github_importer_attachments, project, type: :gitlab_com_derisk)
-
object_representation(object).has_attachments?
end
end
diff --git a/lib/gitlab/kubernetes/kube_client.rb b/lib/gitlab/kubernetes/kube_client.rb
index 44e53e9ec70..593090902e7 100644
--- a/lib/gitlab/kubernetes/kube_client.rb
+++ b/lib/gitlab/kubernetes/kube_client.rb
@@ -161,7 +161,11 @@ module Gitlab
def validate_url!
return if Gitlab::CurrentSettings.allow_local_requests_from_web_hooks_and_services?
- Gitlab::UrlBlocker.validate!(api_prefix, allow_local_network: false, schemes: %w[http https])
+ Gitlab::HTTP_V2::UrlBlocker.validate!(
+ api_prefix,
+ allow_local_network: false,
+ schemes: %w[http https],
+ deny_all_requests_except_allowed: Gitlab::CurrentSettings.deny_all_requests_except_allowed?)
end
def service_account_exists?(resource)
diff --git a/lib/gitlab/octokit/middleware.rb b/lib/gitlab/octokit/middleware.rb
index f944f9827a3..a93526da5ca 100644
--- a/lib/gitlab/octokit/middleware.rb
+++ b/lib/gitlab/octokit/middleware.rb
@@ -8,11 +8,12 @@ module Gitlab
end
def call(env)
- Gitlab::UrlBlocker.validate!(env[:url],
+ Gitlab::HTTP_V2::UrlBlocker.validate!(env[:url],
schemes: %w[http https],
allow_localhost: allow_local_requests?,
allow_local_network: allow_local_requests?,
- dns_rebind_protection: dns_rebind_protection?
+ dns_rebind_protection: dns_rebind_protection?,
+ deny_all_requests_except_allowed: Gitlab::CurrentSettings.deny_all_requests_except_allowed?
)
@app.call(env)
diff --git a/lib/service_ping/service_ping_settings.rb b/lib/service_ping/service_ping_settings.rb
index 6964210b1db..8c99f1138c5 100644
--- a/lib/service_ping/service_ping_settings.rb
+++ b/lib/service_ping/service_ping_settings.rb
@@ -4,7 +4,7 @@ module ServicePing
module ServicePingSettings
extend self
- def product_intelligence_enabled?
+ def enabled_and_consented?
enabled? && !User.single_user&.requires_usage_stats_consent?
end
diff --git a/spec/frontend/diffs/components/app_spec.js b/spec/frontend/diffs/components/app_spec.js
index 5e0dfd8bd09..0d25057993a 100644
--- a/spec/frontend/diffs/components/app_spec.js
+++ b/spec/frontend/diffs/components/app_spec.js
@@ -8,6 +8,7 @@ import Vuex from 'vuex';
import getMRCodequalityAndSecurityReports from '~/diffs/components/graphql/get_mr_codequality_and_security_reports.query.graphql';
import createMockApollo from 'helpers/mock_apollo_helper';
import setWindowLocation from 'helpers/set_window_location_helper';
+import { mockTracking } from 'helpers/tracking_helper';
import { TEST_HOST } from 'spec/test_constants';
import App from '~/diffs/components/app.vue';
@@ -22,6 +23,7 @@ import CollapsedFilesWarning from '~/diffs/components/collapsed_files_warning.vu
import HiddenFilesWarning from '~/diffs/components/hidden_files_warning.vue';
import eventHub from '~/diffs/event_hub';
+import notesEventHub from '~/notes/event_hub';
import { EVT_DISCUSSIONS_ASSIGNED } from '~/diffs/constants';
import axios from '~/lib/utils/axios_utils';
@@ -888,4 +890,38 @@ describe('diffs/components/app', () => {
expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true);
});
});
+
+ describe('draft comments', () => {
+ let trackingSpy;
+
+ beforeEach(() => {
+ trackingSpy = mockTracking(undefined, window.document, jest.spyOn);
+ });
+
+ describe('when adding a new comment to an existing review', () => {
+ it('sends the correct tracking event', () => {
+ createComponent({ shouldShow: true });
+ notesEventHub.$emit('noteFormAddToReview', { name: 'noteFormAddToReview' });
+
+ expect(trackingSpy).toHaveBeenCalledWith(
+ undefined,
+ 'merge_request_click_add_to_review_on_changes_tab',
+ expect.any(Object),
+ );
+ });
+ });
+
+ describe('when adding a comment to a new review', () => {
+ it('sends the correct tracking event', () => {
+ createComponent({ shouldShow: true });
+ notesEventHub.$emit('noteFormStartReview', { name: 'noteFormStartReview' });
+
+ expect(trackingSpy).toHaveBeenCalledWith(
+ undefined,
+ 'merge_request_click_start_review_on_changes_tab',
+ expect.any(Object),
+ );
+ });
+ });
+ });
});
diff --git a/spec/frontend/lib/utils/datetime_utility_spec.js b/spec/frontend/lib/utils/datetime_utility_spec.js
index 73a4af2c85d..5027c924e63 100644
--- a/spec/frontend/lib/utils/datetime_utility_spec.js
+++ b/spec/frontend/lib/utils/datetime_utility_spec.js
@@ -785,11 +785,16 @@ describe('date addition/subtraction methods', () => {
);
});
+ // NOTE: 2024-02-29 is a leap day
describe('nYearsAfter', () => {
it.each`
date | numberOfYears | expected
${'2020-07-06'} | ${1} | ${'2021-07-06'}
${'2020-07-06'} | ${15} | ${'2035-07-06'}
+ ${'2024-03-02'} | ${1} | ${'2025-03-02'}
+ ${'2024-03-01'} | ${1} | ${'2025-03-01'}
+ ${'2024-02-29'} | ${1} | ${'2025-02-28'}
+ ${'2024-02-28'} | ${1} | ${'2025-02-28'}
`(
'returns $expected for "$numberOfYears year(s) after $date"',
({ date, numberOfYears, expected }) => {
@@ -805,6 +810,10 @@ describe('date addition/subtraction methods', () => {
date | numberOfYears | expected
${'2020-07-06'} | ${4} | ${'2016-07-06'}
${'2020-07-06'} | ${1} | ${'2019-07-06'}
+ ${'2024-03-02'} | ${1} | ${'2023-03-02'}
+ ${'2024-03-01'} | ${1} | ${'2023-03-01'}
+ ${'2024-02-29'} | ${1} | ${'2023-02-28'}
+ ${'2024-02-28'} | ${1} | ${'2023-02-28'}
`(
'returns $expected for "$numberOfYears year(s) before $date"',
({ date, numberOfYears, expected }) => {
diff --git a/spec/frontend/notes/components/comment_form_spec.js b/spec/frontend/notes/components/comment_form_spec.js
index 8f761476c7c..500032eac26 100644
--- a/spec/frontend/notes/components/comment_form_spec.js
+++ b/spec/frontend/notes/components/comment_form_spec.js
@@ -401,11 +401,28 @@ describe('issue_comment_form component', () => {
let store;
beforeEach(() => {
- store = createStore();
+ store = createStore({
+ actions: {
+ saveNote: jest.fn().mockResolvedValue(),
+ },
+ });
store.registerModule('batchComments', batchComments());
store.state.batchComments.drafts = [{ note: 'A' }];
});
+ it('sends the event to indicate that a new draft comment has been added', () => {
+ const note = 'some note text which enables actually adding a draft note';
+
+ jest.spyOn(eventHub, '$emit');
+ mountComponent({ mountFunction: mount, initialData: { note }, store });
+
+ findAddToReviewButton().trigger('click');
+
+ expect(eventHub.$emit).toHaveBeenCalledWith('noteFormAddToReview', {
+ name: 'noteFormAddToReview',
+ });
+ });
+
it('should save note draft when cmd+enter is pressed', async () => {
mountComponent({ mountFunction: mount, store });
jest.spyOn(wrapper.vm, 'handleSaveDraft');
diff --git a/spec/frontend/notes/components/note_form_spec.js b/spec/frontend/notes/components/note_form_spec.js
index e2072ebd04d..dad36a290b1 100644
--- a/spec/frontend/notes/components/note_form_spec.js
+++ b/spec/frontend/notes/components/note_form_spec.js
@@ -7,6 +7,7 @@ import MarkdownField from '~/vue_shared/components/markdown/field.vue';
import CommentFieldLayout from '~/notes/components/comment_field_layout.vue';
import { AT_WHO_ACTIVE_CLASS } from '~/gfm_auto_complete';
import eventHub from '~/environments/event_hub';
+import notesEventHub from '~/notes/event_hub';
import { mountExtended } from 'helpers/vue_test_utils_helper';
import { mockTracking } from 'helpers/tracking_helper';
import { noteableDataMock, notesDataMock, discussionMock, note } from '../mock_data';
@@ -16,6 +17,7 @@ jest.mock('~/lib/utils/autosave');
describe('issue_note_form component', () => {
let store;
let wrapper;
+ let textarea;
let props;
let trackingSpy;
@@ -39,10 +41,13 @@ describe('issue_note_form component', () => {
},
},
});
+
+ textarea = wrapper.find('textarea');
};
const findCancelButton = () => wrapper.findByTestId('cancel');
const findCancelCommentButton = () => wrapper.findByTestId('cancelBatchCommentsEnabled');
+ const findAddToStartReviewButton = () => wrapper.findByTestId('start-review-button');
const findMarkdownField = () => wrapper.findComponent(MarkdownField);
beforeEach(() => {
@@ -112,14 +117,10 @@ describe('issue_note_form component', () => {
});
it('should render text area with placeholder', () => {
- const textarea = wrapper.find('textarea');
-
expect(textarea.attributes('placeholder')).toBe('Write a comment or drag your files hereā€¦');
});
it('should set data-supports-quick-actions to enable autocomplete', () => {
- const textarea = wrapper.find('textarea');
-
expect(textarea.attributes('data-supports-quick-actions')).toBe('true');
});
@@ -147,10 +148,7 @@ describe('issue_note_form component', () => {
});
describe('keyboard events', () => {
- let textarea;
-
beforeEach(() => {
- textarea = wrapper.find('textarea');
textarea.setValue('Foo');
});
@@ -213,7 +211,6 @@ describe('issue_note_form component', () => {
it('should be possible to update the note', () => {
createComponentWrapper();
- const textarea = wrapper.find('textarea');
textarea.setValue('Foo');
const saveButton = wrapper.find('.js-vue-issue-save');
saveButton.vm.$emit('click');
@@ -224,7 +221,6 @@ describe('issue_note_form component', () => {
it('tracks event when save button is clicked', () => {
createComponentWrapper();
- const textarea = wrapper.find('textarea');
textarea.setValue('Foo');
const saveButton = wrapper.find('.js-vue-issue-save');
saveButton.vm.$emit('click');
@@ -313,8 +309,6 @@ describe('issue_note_form component', () => {
describe('on enter', () => {
it('should start review or add to review when cmd+enter is pressed', async () => {
- const textarea = wrapper.find('textarea');
-
textarea.setValue('Foo');
textarea.trigger('keydown.enter', { metaKey: true });
@@ -325,5 +319,40 @@ describe('issue_note_form component', () => {
]);
});
});
+
+ describe('when adding a draft comment', () => {
+ beforeEach(() => {
+ jest.spyOn(notesEventHub, '$emit');
+ });
+
+ it('sends the event to indicate that a draft has been added to the review', () => {
+ store.state.batchComments.drafts = [{ note: 'A' }];
+ createComponentWrapper({
+ isDraft: true,
+ noteId: '',
+ discussion: { ...discussionMock, for_commit: false },
+ });
+
+ findAddToStartReviewButton().trigger('click');
+
+ expect(notesEventHub.$emit).toHaveBeenCalledWith('noteFormAddToReview', {
+ name: 'noteFormAddToReview',
+ });
+ });
+
+ it('sends the event to indicate that a review has been started with the new draft', () => {
+ createComponentWrapper({
+ isDraft: true,
+ noteId: '',
+ discussion: { ...discussionMock, for_commit: false },
+ });
+
+ findAddToStartReviewButton().trigger('click');
+
+ expect(notesEventHub.$emit).toHaveBeenCalledWith('noteFormStartReview', {
+ name: 'noteFormStartReview',
+ });
+ });
+ });
});
});
diff --git a/spec/frontend/notes/components/notes_app_spec.js b/spec/frontend/notes/components/notes_app_spec.js
index d49ab0d71db..e278d53b55a 100644
--- a/spec/frontend/notes/components/notes_app_spec.js
+++ b/spec/frontend/notes/components/notes_app_spec.js
@@ -3,6 +3,7 @@ import AxiosMockAdapter from 'axios-mock-adapter';
import $ from 'jquery';
import { nextTick } from 'vue';
import setWindowLocation from 'helpers/set_window_location_helper';
+import { mockTracking } from 'helpers/tracking_helper';
import waitForPromises from 'helpers/wait_for_promises';
import DraftNote from '~/batch_comments/components/draft_note.vue';
import batchComments from '~/batch_comments/stores/modules/batch_comments';
@@ -10,6 +11,7 @@ import axios from '~/lib/utils/axios_utils';
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
import { getLocationHash } from '~/lib/utils/url_utility';
import * as urlUtility from '~/lib/utils/url_utility';
+import notesEventHub from '~/notes/event_hub';
import CommentForm from '~/notes/components/comment_form.vue';
import NotesApp from '~/notes/components/notes_app.vue';
import NotesActivityHeader from '~/notes/components/notes_activity_header.vue';
@@ -453,4 +455,39 @@ describe('note_app', () => {
});
});
});
+
+ describe('draft comments', () => {
+ let trackingSpy;
+
+ beforeEach(() => {
+ window.mrTabs = { eventHub: notesEventHub };
+ axiosMock.onAny().reply(mockData.getIndividualNoteResponse);
+ trackingSpy = mockTracking(undefined, window.document, jest.spyOn);
+ wrapper = mountComponent();
+ });
+
+ describe('when adding a new comment to an existing review', () => {
+ it('sends the correct tracking event', () => {
+ notesEventHub.$emit('noteFormAddToReview', { name: 'noteFormAddToReview' });
+
+ expect(trackingSpy).toHaveBeenCalledWith(
+ undefined,
+ 'merge_request_click_add_to_review_on_overview_tab',
+ expect.any(Object),
+ );
+ });
+ });
+
+ describe('when adding a comment to a new review', () => {
+ it('sends the correct tracking event', () => {
+ notesEventHub.$emit('noteFormStartReview', { name: 'noteFormStartReview' });
+
+ expect(trackingSpy).toHaveBeenCalledWith(
+ undefined,
+ 'merge_request_click_start_review_on_overview_tab',
+ expect.any(Object),
+ );
+ });
+ });
+ });
});
diff --git a/spec/frontend/usage_quotas/storage/components/storage_type_help_link_spec.js b/spec/frontend/usage_quotas/storage/components/storage_type_help_link_spec.js
new file mode 100644
index 00000000000..9c855e4bec1
--- /dev/null
+++ b/spec/frontend/usage_quotas/storage/components/storage_type_help_link_spec.js
@@ -0,0 +1,49 @@
+import { GlLink } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import StorageTypeHelpLink from '~/usage_quotas/storage/components/storage_type_help_link.vue';
+import { storageTypeHelpPaths } from '~/usage_quotas/storage/constants';
+
+let wrapper;
+
+const createComponent = ({ props = {} } = {}) => {
+ wrapper = shallowMount(StorageTypeHelpLink, {
+ propsData: {
+ helpLinks: storageTypeHelpPaths,
+ ...props,
+ },
+ });
+};
+
+const findLink = () => wrapper.findComponent(GlLink);
+
+describe('StorageTypeHelpLink', () => {
+ describe('Storage type w/ link', () => {
+ describe.each(Object.entries(storageTypeHelpPaths))('%s', (storageType, url) => {
+ beforeEach(() => {
+ createComponent({
+ props: {
+ storageType,
+ },
+ });
+ });
+
+ it('will have proper href', () => {
+ expect(findLink().attributes('href')).toBe(url);
+ });
+ });
+ });
+
+ describe('Storage type w/o help link', () => {
+ beforeEach(() => {
+ createComponent({
+ props: {
+ storageType: 'Yellow Submarine',
+ },
+ });
+ });
+
+ it('will not have a href', () => {
+ expect(findLink().attributes('href')).toBe(undefined);
+ });
+ });
+});
diff --git a/spec/frontend/usage_quotas/storage/mock_data.js b/spec/frontend/usage_quotas/storage/mock_data.js
index e7886614575..3f615f01e17 100644
--- a/spec/frontend/usage_quotas/storage/mock_data.js
+++ b/spec/frontend/usage_quotas/storage/mock_data.js
@@ -1,6 +1,7 @@
import mockGetProjectStorageStatisticsGraphQLResponse from 'test_fixtures/graphql/usage_quotas/storage/project_storage.query.graphql.json';
import mockGetNamespaceStorageGraphQLResponse from 'test_fixtures/graphql/usage_quotas/storage/namespace_storage.query.graphql.json';
import mockGetProjectListStorageGraphQLResponse from 'test_fixtures/graphql/usage_quotas/storage/project_list_storage.query.graphql.json';
+import { storageTypeHelpPaths } from '~/usage_quotas/storage/constants';
export { mockGetProjectStorageStatisticsGraphQLResponse };
export { mockGetNamespaceStorageGraphQLResponse };
@@ -15,4 +16,6 @@ export const defaultProjectProvideValues = {
export const defaultNamespaceProvideValues = {
userNamespace: false,
namespaceId: '42',
+ defaultPerPage: 20,
+ helpLinks: storageTypeHelpPaths,
};
diff --git a/spec/lib/gitlab/github_gists_import/importer/gist_importer_spec.rb b/spec/lib/gitlab/github_gists_import/importer/gist_importer_spec.rb
index b098a151660..b64348d447b 100644
--- a/spec/lib/gitlab/github_gists_import/importer/gist_importer_spec.rb
+++ b/spec/lib/gitlab/github_gists_import/importer/gist_importer_spec.rb
@@ -167,13 +167,16 @@ RSpec.describe Gitlab::GithubGistsImport::Importer::GistImporter, feature_catego
before do
allow(::Gitlab::CurrentSettings)
.to receive(:allow_local_requests_from_web_hooks_and_services?).and_return(true)
+ allow(::Gitlab::CurrentSettings)
+ .to receive(:deny_all_requests_except_allowed?).and_return(true)
end
it 'raises error' do
- expect(Gitlab::UrlBlocker)
+ expect(Gitlab::HTTP_V2::UrlBlocker)
.to receive(:validate!)
.with(url, ports: [80, 443], schemes: %w[http https git],
- allow_localhost: true, allow_local_network: true)
+ allow_localhost: true, allow_local_network: true,
+ deny_all_requests_except_allowed: true)
.and_raise(Gitlab::HTTP_V2::UrlBlocker::BlockedUrlError)
expect { subject.execute }.to raise_error(Gitlab::HTTP_V2::UrlBlocker::BlockedUrlError)
@@ -184,13 +187,16 @@ RSpec.describe Gitlab::GithubGistsImport::Importer::GistImporter, feature_catego
before do
allow(::Gitlab::CurrentSettings)
.to receive(:allow_local_requests_from_web_hooks_and_services?).and_return(false)
+ allow(::Gitlab::CurrentSettings)
+ .to receive(:deny_all_requests_except_allowed?).and_return(true)
end
it 'raises error' do
- expect(Gitlab::UrlBlocker)
+ expect(Gitlab::HTTP_V2::UrlBlocker)
.to receive(:validate!)
.with(url, ports: [80, 443], schemes: %w[http https git],
- allow_localhost: false, allow_local_network: false)
+ allow_localhost: false, allow_local_network: false,
+ deny_all_requests_except_allowed: true)
.and_raise(Gitlab::HTTP_V2::UrlBlocker::BlockedUrlError)
expect { subject.execute }.to raise_error(Gitlab::HTTP_V2::UrlBlocker::BlockedUrlError)
diff --git a/spec/lib/gitlab/github_import/importer/attachments/issues_importer_spec.rb b/spec/lib/gitlab/github_import/importer/attachments/issues_importer_spec.rb
index 20152020897..223b7318d69 100644
--- a/spec/lib/gitlab/github_import/importer/attachments/issues_importer_spec.rb
+++ b/spec/lib/gitlab/github_import/importer/attachments/issues_importer_spec.rb
@@ -41,20 +41,6 @@ RSpec.describe Gitlab::GithubImport::Importer::Attachments::IssuesImporter, feat
importer.sequential_import
end
- context 'when flag is disabled' do
- before do
- stub_feature_flags(github_importer_attachments: false)
- end
-
- it 'executes importer for both issues' do
- expect_next_instances_of(Gitlab::GithubImport::Importer::NoteAttachmentsImporter, 2) do |importer|
- expect(importer).to receive(:execute)
- end
-
- importer.sequential_import
- end
- end
-
context 'when issue has already been processed' do
before do
importer.mark_as_imported(issue_with_attachment)
diff --git a/spec/lib/gitlab/github_import/importer/attachments/merge_requests_importer_spec.rb b/spec/lib/gitlab/github_import/importer/attachments/merge_requests_importer_spec.rb
index 5ed6dce8507..5449d4def1f 100644
--- a/spec/lib/gitlab/github_import/importer/attachments/merge_requests_importer_spec.rb
+++ b/spec/lib/gitlab/github_import/importer/attachments/merge_requests_importer_spec.rb
@@ -42,20 +42,6 @@ RSpec.describe Gitlab::GithubImport::Importer::Attachments::MergeRequestsImporte
importer.sequential_import
end
- context 'when flag is disabled' do
- before do
- stub_feature_flags(github_importer_attachments: false)
- end
-
- it 'executes importer for both merge requests' do
- expect_next_instances_of(Gitlab::GithubImport::Importer::NoteAttachmentsImporter, 2) do |importer|
- expect(importer).to receive(:execute)
- end
-
- importer.sequential_import
- end
- end
-
context 'when merge request has already been processed' do
before do
importer.mark_as_imported(mr_with_attachment)
diff --git a/spec/lib/gitlab/github_import/importer/attachments/notes_importer_spec.rb b/spec/lib/gitlab/github_import/importer/attachments/notes_importer_spec.rb
index da0ee1ed0dd..1dfe69ec12d 100644
--- a/spec/lib/gitlab/github_import/importer/attachments/notes_importer_spec.rb
+++ b/spec/lib/gitlab/github_import/importer/attachments/notes_importer_spec.rb
@@ -52,20 +52,6 @@ RSpec.describe Gitlab::GithubImport::Importer::Attachments::NotesImporter, featu
importer.sequential_import
end
- context 'when flag is disabled' do
- before do
- stub_feature_flags(github_importer_attachments: false)
- end
-
- it 'executes importer for both user notes' do
- expect_next_instances_of(Gitlab::GithubImport::Importer::NoteAttachmentsImporter, 2) do |importer|
- expect(importer).to receive(:execute)
- end
-
- importer.sequential_import
- end
- end
-
context 'when note has already been processed' do
before do
importer.mark_as_imported(note_with_attachment)
diff --git a/spec/lib/gitlab/github_import/importer/attachments/releases_importer_spec.rb b/spec/lib/gitlab/github_import/importer/attachments/releases_importer_spec.rb
index cf51760d966..4886cb923dc 100644
--- a/spec/lib/gitlab/github_import/importer/attachments/releases_importer_spec.rb
+++ b/spec/lib/gitlab/github_import/importer/attachments/releases_importer_spec.rb
@@ -41,20 +41,6 @@ RSpec.describe Gitlab::GithubImport::Importer::Attachments::ReleasesImporter, fe
importer.sequential_import
end
- context 'when flag is disabled' do
- before do
- stub_feature_flags(github_importer_attachments: false)
- end
-
- it 'executes importer for both releases' do
- expect_next_instances_of(Gitlab::GithubImport::Importer::NoteAttachmentsImporter, 2) do |importer|
- expect(importer).to receive(:execute)
- end
-
- importer.sequential_import
- end
- end
-
context 'when release has already been processed' do
before do
importer.mark_as_imported(release_with_attachment)
diff --git a/spec/lib/service_ping/service_ping_settings_spec.rb b/spec/lib/service_ping/service_ping_settings_spec.rb
index 040a5027274..2e61b35a131 100644
--- a/spec/lib/service_ping/service_ping_settings_spec.rb
+++ b/spec/lib/service_ping/service_ping_settings_spec.rb
@@ -5,8 +5,8 @@ require 'spec_helper'
RSpec.describe ServicePing::ServicePingSettings do
using RSpec::Parameterized::TableSyntax
- describe '#product_intelligence_enabled?' do
- where(:usage_ping_enabled, :requires_usage_stats_consent, :expected_product_intelligence_enabled) do
+ describe '#enabled_and_consented?' do
+ where(:usage_ping_enabled, :requires_usage_stats_consent, :expected_enabled_and_consented) do
# Usage ping enabled
true | false | true
true | true | false
@@ -23,8 +23,8 @@ RSpec.describe ServicePing::ServicePingSettings do
stub_config_setting(usage_ping_enabled: usage_ping_enabled)
end
- it 'has the correct product_intelligence_enabled?' do
- expect(described_class.product_intelligence_enabled?).to eq(expected_product_intelligence_enabled)
+ it 'has the correct enabled_and_consented?' do
+ expect(described_class.enabled_and_consented?).to eq(expected_enabled_and_consented)
end
end
end
diff --git a/spec/services/service_ping/submit_service_ping_service_spec.rb b/spec/services/service_ping/submit_service_ping_service_spec.rb
index 2248febda5c..ce0fa6248a1 100644
--- a/spec/services/service_ping/submit_service_ping_service_spec.rb
+++ b/spec/services/service_ping/submit_service_ping_service_spec.rb
@@ -104,20 +104,20 @@ RSpec.describe ServicePing::SubmitService, feature_category: :service_ping do
it_behaves_like 'does not run'
end
- context 'when product_intelligence_enabled is false' do
+ context 'when enabled_and_consented is false' do
before do
- allow(ServicePing::ServicePingSettings).to receive(:product_intelligence_enabled?).and_return(false)
+ allow(ServicePing::ServicePingSettings).to receive(:enabled_and_consented?).and_return(false)
end
it_behaves_like 'does not run'
end
- context 'when product_intelligence_enabled is true' do
+ context 'when enabled_and_consented is true' do
before do
stub_usage_data_connections
stub_database_flavor_check
- allow(ServicePing::ServicePingSettings).to receive(:product_intelligence_enabled?).and_return(true)
+ allow(ServicePing::ServicePingSettings).to receive(:enabled_and_consented?).and_return(true)
end
it 'submits a service ping payload without errors', :aggregate_failures do