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:
-rw-r--r--Gemfile2
-rw-r--r--Gemfile.checksum6
-rw-r--r--Gemfile.lock4
-rw-r--r--app/assets/javascripts/admin/abuse_reports/components/abuse_category.vue33
-rw-r--r--app/assets/javascripts/admin/abuse_reports/components/abuse_report_row.vue17
-rw-r--r--app/assets/javascripts/admin/abuse_reports/constants.js45
-rw-r--r--app/assets/javascripts/graphql_shared/issuable_client.js35
-rw-r--r--app/assets/javascripts/work_items/components/work_item_assignees.vue2
-rw-r--r--app/assets/javascripts/work_items/components/work_item_award_emoji.vue90
-rw-r--r--app/assets/javascripts/work_items/constants.js5
-rw-r--r--app/assets/javascripts/work_items/graphql/award_emoji.query.graphql27
-rw-r--r--app/assets/javascripts/work_items/graphql/work_item_metadata_widgets.fragment.graphql6
-rw-r--r--app/assets/javascripts/work_items/graphql/work_item_widgets.fragment.graphql6
-rw-r--r--app/views/admin/application_settings/_slack.html.haml6
-rw-r--r--app/views/projects/compare/index.html.haml14
-rw-r--r--app/views/projects/compare/show.html.haml6
-rw-r--r--config/feature_flags/development/global_file_size_check.yml8
-rw-r--r--config/feature_flags/development/notify_kas_on_git_push.yml2
-rw-r--r--db/docs/batched_background_migrations/backfill_uuid_conversion_column_in_vulnerability_occurrences.yml6
-rw-r--r--db/post_migrate/20230629095819_queue_backfill_uuid_conversion_column_in_vulnerability_occurrences.rb25
-rw-r--r--db/schema_migrations/202306290958191
-rw-r--r--doc/administration/admin_area.md2
-rw-r--r--doc/administration/appearance.md2
-rw-r--r--doc/administration/compliance.md6
-rw-r--r--doc/administration/configure.md2
-rw-r--r--doc/administration/docs_self_host.md4
-rw-r--r--doc/administration/get_started.md10
-rw-r--r--doc/administration/gitaly/troubleshooting.md2
-rw-r--r--doc/administration/instance_limits.md22
-rw-r--r--doc/administration/logs/index.md4
-rw-r--r--doc/administration/packages/index.md2
-rw-r--r--doc/administration/redis/replication_and_failover.md2
-rw-r--r--doc/administration/settings/deprecated_api_rate_limits.md2
-rw-r--r--doc/ci/yaml/signing_examples.md4
-rw-r--r--doc/development/fe_guide/index.md6
-rw-r--r--doc/development/fe_guide/onboarding_course/index.md64
-rw-r--r--doc/development/fe_guide/onboarding_course/lesson_1.md183
-rw-r--r--doc/user/asciidoc.md2
-rw-r--r--doc/user/product_analytics/index.md23
-rw-r--r--doc/user/project/repository/code_suggestions.md19
-rw-r--r--lib/gitlab/background_migration/backfill_uuid_conversion_column_in_vulnerability_occurrences.rb21
-rw-r--r--lib/gitlab/checks/changes_access.rb1
-rw-r--r--lib/gitlab/checks/global_file_size_check.rb29
-rw-r--r--locale/gitlab.pot50
-rw-r--r--spec/frontend/admin/abuse_reports/components/abuse_category_spec.js43
-rw-r--r--spec/frontend/admin/abuse_reports/components/abuse_report_row_spec.js16
-rw-r--r--spec/frontend/work_items/components/work_item_assignees_spec.js8
-rw-r--r--spec/frontend/work_items/components/work_item_award_emoji_spec.js231
-rw-r--r--spec/frontend/work_items/mock_data.js32
-rw-r--r--spec/frontend/work_items/router_spec.js1
-rw-r--r--spec/lib/gitlab/background_migration/backfill_uuid_conversion_column_in_vulnerability_occurrences_spec.rb133
-rw-r--r--spec/lib/gitlab/checks/changes_access_spec.rb8
-rw-r--r--spec/lib/gitlab/checks/global_file_size_check_spec.rb36
-rw-r--r--spec/migrations/20230629095819_queue_backfill_uuid_conversion_column_in_vulnerability_occurrences_spec.rb26
54 files changed, 1159 insertions, 183 deletions
diff --git a/Gemfile b/Gemfile
index 19dea298c2c..3e01bf6869b 100644
--- a/Gemfile
+++ b/Gemfile
@@ -608,7 +608,7 @@ gem 'cvss-suite', '~> 3.0.1', require: 'cvss_suite'
gem 'arr-pm', '~> 0.0.12'
# Remote Development
-gem 'devfile', '~> 0.0.19.pre.alpha1'
+gem 'devfile', '~> 0.0.20.pre.alpha1'
# Apple plist parsing
gem 'CFPropertyList', '~> 3.0.0'
diff --git a/Gemfile.checksum b/Gemfile.checksum
index 65a4045b5b9..333116430ec 100644
--- a/Gemfile.checksum
+++ b/Gemfile.checksum
@@ -109,9 +109,9 @@
{"name":"deprecation_toolkit","version":"1.5.1","platform":"ruby","checksum":"a8a1ab1a19ae40ea12560b65010e099f3459ebde390b76621ef0c21c516a04ba"},
{"name":"derailed_benchmarks","version":"2.1.2","platform":"ruby","checksum":"eaadc6206ceeb5538ff8f5e04a0023d54ebdd95d04f33e8960fb95a5f189a14f"},
{"name":"descendants_tracker","version":"0.0.4","platform":"ruby","checksum":"e9c41dd4cfbb85829a9301ea7e7c48c2a03b26f09319db230e6479ccdc780897"},
-{"name":"devfile","version":"0.0.19.pre.alpha1","platform":"arm64-darwin","checksum":"6087103d7e6c6226f2e9209d8619446afdb9bdaaf75cf7f6e06e929622465fe8"},
-{"name":"devfile","version":"0.0.19.pre.alpha1","platform":"ruby","checksum":"d928c4529162c1f2a8434d8509d9d760d15dfb3c133669199de0d12ba3ec9ed8"},
-{"name":"devfile","version":"0.0.19.pre.alpha1","platform":"x86_64-linux","checksum":"8c64e74eb470eedfd9a1754c40f82a6621a26735cdb22fc3d3dad4bc49445b37"},
+{"name":"devfile","version":"0.0.20.pre.alpha1","platform":"arm64-darwin","checksum":"1dcd4a55482f04a0ec308d13fe41358bfbfd95ffe98678a471aa5e0e0c5dba98"},
+{"name":"devfile","version":"0.0.20.pre.alpha1","platform":"ruby","checksum":"6a046be066c1b0392da1387249962d765d1f1a3a242e1ede0459b14a6d6fd760"},
+{"name":"devfile","version":"0.0.20.pre.alpha1","platform":"x86_64-linux","checksum":"d0fa2a05ae7de71a17c6251e853459504ed6a51cb1f90a25ba9d0b7c9cb82074"},
{"name":"device_detector","version":"1.0.0","platform":"ruby","checksum":"b800fb3150b00c23e87b6768011808ac1771fffaae74c3238ebaf2b782947a7d"},
{"name":"devise","version":"4.8.1","platform":"ruby","checksum":"fdd48bbe79a89e7c1152236a70479842ede48bea4fa7f4f2d8da1f872559803e"},
{"name":"devise-two-factor","version":"4.0.2","platform":"ruby","checksum":"6548d2696ed090d27046f888f4fa7380f151e0f823902d46fd9b91e7d0cac511"},
diff --git a/Gemfile.lock b/Gemfile.lock
index 75b7953edaf..3add4cdfda3 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -418,7 +418,7 @@ GEM
thor (>= 0.19, < 2)
descendants_tracker (0.0.4)
thread_safe (~> 0.3, >= 0.3.1)
- devfile (0.0.19.pre.alpha1)
+ devfile (0.0.20.pre.alpha1)
device_detector (1.0.0)
devise (4.8.1)
bcrypt (~> 3.0)
@@ -1773,7 +1773,7 @@ DEPENDENCIES
declarative_policy (~> 1.1.0)
deprecation_toolkit (~> 1.5.1)
derailed_benchmarks
- devfile (~> 0.0.19.pre.alpha1)
+ devfile (~> 0.0.20.pre.alpha1)
device_detector
devise (~> 4.8.1)
devise-pbkdf2-encryptable (~> 0.0.0)!
diff --git a/app/assets/javascripts/admin/abuse_reports/components/abuse_category.vue b/app/assets/javascripts/admin/abuse_reports/components/abuse_category.vue
new file mode 100644
index 00000000000..f05f96d6302
--- /dev/null
+++ b/app/assets/javascripts/admin/abuse_reports/components/abuse_category.vue
@@ -0,0 +1,33 @@
+<script>
+import { GlLabel } from '@gitlab/ui';
+import { ABUSE_CATEGORIES } from '../constants';
+
+export default {
+ name: 'AbuseCategory',
+ components: {
+ GlLabel,
+ },
+ props: {
+ category: {
+ type: String,
+ required: true,
+ },
+ },
+ computed: {
+ categoryObject() {
+ return ABUSE_CATEGORIES[this.category];
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-label
+ v-if="categoryObject"
+ size="sm"
+ :background-color="categoryObject.backgroundColor"
+ :title="categoryObject.title"
+ :target="null"
+ :class="`gl-text-${categoryObject.color}`"
+ />
+</template>
diff --git a/app/assets/javascripts/admin/abuse_reports/components/abuse_report_row.vue b/app/assets/javascripts/admin/abuse_reports/components/abuse_report_row.vue
index b8a4640de59..b229dd9e993 100644
--- a/app/assets/javascripts/admin/abuse_reports/components/abuse_report_row.vue
+++ b/app/assets/javascripts/admin/abuse_reports/components/abuse_report_row.vue
@@ -5,12 +5,14 @@ import { queryToObject } from '~/lib/utils/url_utility';
import { s__, __, sprintf } from '~/locale';
import ListItem from '~/vue_shared/components/registry/list_item.vue';
import { SORT_UPDATED_AT } from '../constants';
+import AbuseCategory from './abuse_category.vue';
export default {
name: 'AbuseReportRow',
components: {
GlLink,
ListItem,
+ AbuseCategory,
},
props: {
report: {
@@ -44,13 +46,24 @@ export default {
<template>
<list-item data-testid="abuse-report-row">
<template #left-primary>
- <gl-link :href="report.reportPath" class="gl-font-weight-normal gl-mb-2" data-testid="title">
+ <gl-link
+ :href="report.reportPath"
+ class="gl-font-weight-normal gl-pt-4 gl-text-gray-900"
+ data-testid="abuse-report-title"
+ >
{{ title }}
</gl-link>
</template>
+ <template #left-secondary>
+ <abuse-category
+ :category="report.category"
+ class="gl-mt-2 gl-mb-3"
+ data-testid="abuse-report-category"
+ />
+ </template>
<template #right-secondary>
- <div data-testid="abuse-report-date">{{ displayDate }}</div>
+ <div class="gl-mt-7" data-testid="abuse-report-date">{{ displayDate }}</div>
</template>
</list-item>
</template>
diff --git a/app/assets/javascripts/admin/abuse_reports/constants.js b/app/assets/javascripts/admin/abuse_reports/constants.js
index 9458aea299e..acb79293dfb 100644
--- a/app/assets/javascripts/admin/abuse_reports/constants.js
+++ b/app/assets/javascripts/admin/abuse_reports/constants.js
@@ -5,7 +5,7 @@ import {
OPERATORS_IS,
TOKEN_TITLE_STATUS,
} from '~/vue_shared/components/filtered_search_bar/constants';
-import { __ } from '~/locale';
+import { s__, __ } from '~/locale';
const STATUS_OPTIONS = [
{ value: 'closed', title: __('Closed') },
@@ -78,3 +78,46 @@ export const FILTERED_SEARCH_TOKENS = [
FILTERED_SEARCH_TOKEN_REPORTER,
FILTERED_SEARCH_TOKEN_STATUS,
];
+
+export const ABUSE_CATEGORIES = {
+ spam: {
+ backgroundColor: '#f5d9a8',
+ color: 'orange-700',
+ title: s__('AbuseReport|Spam'),
+ },
+ offensive: {
+ backgroundColor: '#e1d8f9',
+ color: 'purple-700',
+ title: s__('AbuseReport|Offensive or Abusive'),
+ },
+ phishing: {
+ backgroundColor: '#7c7ccc',
+ color: 'indigo-800',
+ title: s__('AbuseReport|Phishing'),
+ },
+ crypto: {
+ backgroundColor: '#fdd4cd',
+ color: 'red-700',
+ title: s__('AbuseReport|Crypto Mining'),
+ },
+ credentials: {
+ backgroundColor: '#cbe2f9',
+ color: 'blue-700',
+ title: s__('AbuseReport|Personal information or credentials'),
+ },
+ copyright: {
+ backgroundColor: '#c3e6cd',
+ color: 'green-700',
+ title: s__('AbuseReport|Copyright or trademark violation'),
+ },
+ malware: {
+ backgroundColor: '#fdd4cd',
+ color: 'red-700',
+ title: s__('AbuseReport|Malware'),
+ },
+ other: {
+ backgroundColor: '#dcdcde',
+ color: 'gray-700',
+ title: s__('AbuseReport|Other'),
+ },
+};
diff --git a/app/assets/javascripts/graphql_shared/issuable_client.js b/app/assets/javascripts/graphql_shared/issuable_client.js
index d0a88f2e0a6..08733bbe620 100644
--- a/app/assets/javascripts/graphql_shared/issuable_client.js
+++ b/app/assets/javascripts/graphql_shared/issuable_client.js
@@ -6,7 +6,7 @@ import errorQuery from '~/boards/graphql/client/error.query.graphql';
import getIssueStateQuery from '~/issues/show/queries/get_issue_state.query.graphql';
import createDefaultClient from '~/lib/graphql';
import typeDefs from '~/work_items/graphql/typedefs.graphql';
-import { WIDGET_TYPE_NOTES } from '~/work_items/constants';
+import { WIDGET_TYPE_NOTES, WIDGET_TYPE_AWARD_EMOJI } from '~/work_items/constants';
import activeBoardItemQuery from 'ee_else_ce/boards/graphql/client/active_board_item.query.graphql';
export const config = {
@@ -36,6 +36,15 @@ export const config = {
},
},
},
+ WorkItemWidgetAwardEmoji: {
+ fields: {
+ // If we add any key args, the awardEmoji field becomes awardEmoji({"first":10}) and
+ // kills any possibility to handle it on the widget level without hardcoding a string.
+ awardEmoji: {
+ keyArgs: false,
+ },
+ },
+ },
WorkItemWidgetProgress: {
fields: {
progress: {
@@ -68,10 +77,30 @@ export const config = {
const incomingWidget = incoming.find(
(w) => w.type && w.type === existingWidget.type,
);
- // We don't want to override existing notes with empty widget on work item updates
- if (incomingWidget?.type === WIDGET_TYPE_NOTES && !context.variables.pageSize) {
+ // We don't want to override existing notes or award emojis with empty widget on work item updates
+ if (
+ (incomingWidget?.type === WIDGET_TYPE_NOTES ||
+ incomingWidget?.type === WIDGET_TYPE_AWARD_EMOJI) &&
+ !context.variables.pageSize
+ ) {
return existingWidget;
}
+
+ // we want to concat next page of awardEmoji to the existing ones
+ if (incomingWidget?.type === WIDGET_TYPE_AWARD_EMOJI && context.variables.after) {
+ // concatPagination won't work because we were placing new widget here so we have to do this manually
+ return {
+ ...incomingWidget,
+ awardEmoji: {
+ ...incomingWidget.awardEmoji,
+ nodes: [
+ ...existingWidget.awardEmoji.nodes,
+ ...incomingWidget.awardEmoji.nodes,
+ ],
+ },
+ };
+ }
+
// we want to concat next page of discussions to the existing ones
if (incomingWidget?.type === WIDGET_TYPE_NOTES && context.variables.after) {
// concatPagination won't work because we were placing new widget here so we have to do this manually
diff --git a/app/assets/javascripts/work_items/components/work_item_assignees.vue b/app/assets/javascripts/work_items/components/work_item_assignees.vue
index ad9db1428ec..f7ac63e16c3 100644
--- a/app/assets/javascripts/work_items/components/work_item_assignees.vue
+++ b/app/assets/javascripts/work_items/components/work_item_assignees.vue
@@ -340,7 +340,7 @@ export default {
class="assign-myself"
data-testid="assign-self"
@click.stop="assignToCurrentUser"
- >{{ __('Assign myself') }}</gl-button
+ >{{ __('Assign yourself') }}</gl-button
>
</div>
</template>
diff --git a/app/assets/javascripts/work_items/components/work_item_award_emoji.vue b/app/assets/javascripts/work_items/components/work_item_award_emoji.vue
index 144c29b8ec3..3dd3a072d0f 100644
--- a/app/assets/javascripts/work_items/components/work_item_award_emoji.vue
+++ b/app/assets/javascripts/work_items/components/work_item_award_emoji.vue
@@ -7,9 +7,15 @@ import AwardsList from '~/vue_shared/components/awards_list.vue';
import { isLoggedIn } from '~/lib/utils/common_utils';
import { TYPENAME_USER } from '~/graphql_shared/constants';
+import workItemAwardEmojiQuery from '../graphql/award_emoji.query.graphql';
import updateAwardEmojiMutation from '../graphql/update_award_emoji.mutation.graphql';
-import workItemByIidQuery from '../graphql/work_item_by_iid.query.graphql';
-import { EMOJI_THUMBSDOWN, EMOJI_THUMBSUP, WIDGET_TYPE_AWARD_EMOJI } from '../constants';
+import {
+ EMOJI_THUMBSDOWN,
+ EMOJI_THUMBSUP,
+ WIDGET_TYPE_AWARD_EMOJI,
+ DEFAULT_PAGE_SIZE_EMOJIS,
+ I18N_WORK_ITEM_FETCH_AWARD_EMOJI_ERROR,
+} from '../constants';
export default {
defaultAwards: [EMOJI_THUMBSUP, EMOJI_THUMBSDOWN],
@@ -26,16 +32,17 @@ export default {
type: String,
required: true,
},
- awardEmoji: {
- type: Object,
- required: true,
- },
workItemIid: {
type: String,
required: false,
default: null,
},
},
+ data() {
+ return {
+ isLoading: false,
+ };
+ },
computed: {
currentUserId() {
return window.gon.current_user_id;
@@ -47,6 +54,10 @@ export default {
* Parse and convert award emoji list to a format that AwardsList can understand
*/
awards() {
+ if (!this.awardEmoji) {
+ return [];
+ }
+
return this.awardEmoji.nodes.map((emoji) => ({
name: emoji.name,
user: {
@@ -55,16 +66,56 @@ export default {
},
}));
},
+ pageInfo() {
+ return this.awardEmoji?.pageInfo;
+ },
+ hasNextPage() {
+ return this.pageInfo?.hasNextPage;
+ },
+ },
+ apollo: {
+ awardEmoji: {
+ query: workItemAwardEmojiQuery,
+ variables() {
+ return {
+ iid: this.workItemIid,
+ fullPath: this.workItemFullpath,
+ after: this.after,
+ pageSize: DEFAULT_PAGE_SIZE_EMOJIS,
+ };
+ },
+ update(data) {
+ const widgets = data.workspace?.workItems?.nodes[0].widgets;
+ return widgets?.find((widget) => widget.type === WIDGET_TYPE_AWARD_EMOJI).awardEmoji || {};
+ },
+ skip() {
+ return !this.workItemIid;
+ },
+ result() {
+ if (this.hasNextPage) {
+ this.fetchAwardEmojis();
+ } else {
+ this.isLoading = false;
+ }
+ },
+ error() {
+ this.$emit('error', I18N_WORK_ITEM_FETCH_AWARD_EMOJI_ERROR);
+ },
+ },
},
methods: {
- getAwards() {
- return this.awardEmoji.nodes.map((emoji) => ({
- name: emoji.name,
- user: {
- id: getIdFromGraphQLId(emoji.user.id),
- name: emoji.user.name,
- },
- }));
+ async fetchAwardEmojis() {
+ this.isLoading = true;
+ try {
+ await this.$apollo.queries.awardEmoji.fetchMore({
+ variables: {
+ pageSize: DEFAULT_PAGE_SIZE_EMOJIS,
+ after: this.pageInfo?.endCursor,
+ },
+ });
+ } catch (error) {
+ this.$emit('error', I18N_WORK_ITEM_FETCH_AWARD_EMOJI_ERROR);
+ }
},
isEmojiPresentForCurrentUser(name) {
return (
@@ -108,8 +159,12 @@ export default {
},
updateWorkItemAwardEmojiWidgetCache({ cache, name, toggledOn }) {
const query = {
- query: workItemByIidQuery,
- variables: { fullPath: this.workItemFullpath, iid: this.workItemIid },
+ query: workItemAwardEmojiQuery,
+ variables: {
+ fullPath: this.workItemFullpath,
+ iid: this.workItemIid,
+ pageSize: DEFAULT_PAGE_SIZE_EMOJIS,
+ },
};
const sourceData = cache.readQuery(query);
@@ -117,7 +172,6 @@ export default {
const newData = produce(sourceData, (draftState) => {
const { widgets } = draftState.workspace.workItems.nodes[0];
const widgetAwardEmoji = widgets.find((widget) => widget.type === WIDGET_TYPE_AWARD_EMOJI);
-
widgetAwardEmoji.awardEmoji.nodes = this.getAwardEmojiNodes(name, toggledOn);
});
@@ -175,7 +229,7 @@ export default {
</script>
<template>
- <div class="gl-mt-3">
+ <div v-if="!isLoading" class="gl-mt-3">
<awards-list
data-testid="work-item-award-list"
:awards="awards"
diff --git a/app/assets/javascripts/work_items/constants.js b/app/assets/javascripts/work_items/constants.js
index a9f190b1763..b8324d7d552 100644
--- a/app/assets/javascripts/work_items/constants.js
+++ b/app/assets/javascripts/work_items/constants.js
@@ -79,6 +79,10 @@ export const I18N_WORK_ITEM_FETCH_ITERATIONS_ERROR = s__(
'WorkItem|Something went wrong when fetching iterations. Please try again.',
);
+export const I18N_WORK_ITEM_FETCH_AWARD_EMOJI_ERROR = s__(
+ 'WorkItem|Something went wrong while fetching work item award emojis. Please try again.',
+);
+
export const I18N_WORK_ITEM_CREATE_BUTTON_LABEL = s__('WorkItem|Create %{workItemType}');
export const I18N_WORK_ITEM_ADD_BUTTON_LABEL = s__('WorkItem|Add %{workItemType}');
export const I18N_WORK_ITEM_ADD_MULTIPLE_BUTTON_LABEL = s__('WorkItem|Add %{workItemType}s');
@@ -192,6 +196,7 @@ export const FORM_TYPES = {
export const DEFAULT_PAGE_SIZE_ASSIGNEES = 10;
export const DEFAULT_PAGE_SIZE_NOTES = 30;
+export const DEFAULT_PAGE_SIZE_EMOJIS = 100;
export const WORK_ITEM_NOTES_SORT_ORDER_KEY = 'sort_direction_work_item';
diff --git a/app/assets/javascripts/work_items/graphql/award_emoji.query.graphql b/app/assets/javascripts/work_items/graphql/award_emoji.query.graphql
new file mode 100644
index 00000000000..82a532e1bea
--- /dev/null
+++ b/app/assets/javascripts/work_items/graphql/award_emoji.query.graphql
@@ -0,0 +1,27 @@
+#import "~/graphql_shared/fragments/page_info.fragment.graphql"
+#import "~/work_items/graphql/award_emoji.fragment.graphql"
+
+query workItemAwardEmojis($fullPath: ID!, $iid: String, $after: String, $pageSize: Int) {
+ workspace: project(fullPath: $fullPath) {
+ id
+ workItems(iid: $iid) {
+ nodes {
+ id
+ iid
+ widgets {
+ ... on WorkItemWidgetAwardEmoji {
+ type
+ awardEmoji(first: $pageSize, after: $after) {
+ pageInfo {
+ ...PageInfo
+ }
+ nodes {
+ ...AwardEmojiFragment
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/app/assets/javascripts/work_items/graphql/work_item_metadata_widgets.fragment.graphql b/app/assets/javascripts/work_items/graphql/work_item_metadata_widgets.fragment.graphql
index b19a6d5a27c..f303a797e9c 100644
--- a/app/assets/javascripts/work_items/graphql/work_item_metadata_widgets.fragment.graphql
+++ b/app/assets/javascripts/work_items/graphql/work_item_metadata_widgets.fragment.graphql
@@ -1,7 +1,6 @@
#import "~/graphql_shared/fragments/label.fragment.graphql"
#import "~/graphql_shared/fragments/user.fragment.graphql"
#import "~/work_items/graphql/milestone.fragment.graphql"
-#import "~/work_items/graphql/award_emoji.fragment.graphql"
fragment WorkItemMetadataWidgets on WorkItemWidget {
... on WorkItemWidgetDescription {
@@ -52,10 +51,5 @@ fragment WorkItemMetadataWidgets on WorkItemWidget {
}
... on WorkItemWidgetAwardEmoji {
type
- awardEmoji {
- nodes {
- ...AwardEmojiFragment
- }
- }
}
}
diff --git a/app/assets/javascripts/work_items/graphql/work_item_widgets.fragment.graphql b/app/assets/javascripts/work_items/graphql/work_item_widgets.fragment.graphql
index 3bf93a6d13b..383d003e78c 100644
--- a/app/assets/javascripts/work_items/graphql/work_item_widgets.fragment.graphql
+++ b/app/assets/javascripts/work_items/graphql/work_item_widgets.fragment.graphql
@@ -1,7 +1,6 @@
#import "~/graphql_shared/fragments/label.fragment.graphql"
#import "~/graphql_shared/fragments/user.fragment.graphql"
#import "~/work_items/graphql/milestone.fragment.graphql"
-#import "~/work_items/graphql/award_emoji.fragment.graphql"
#import "ee_else_ce/work_items/graphql/work_item_metadata_widgets.fragment.graphql"
fragment WorkItemWidgets on WorkItemWidget {
@@ -100,10 +99,5 @@ fragment WorkItemWidgets on WorkItemWidget {
}
... on WorkItemWidgetAwardEmoji {
type
- awardEmoji {
- nodes {
- ...AwardEmojiFragment
- }
- }
}
}
diff --git a/app/views/admin/application_settings/_slack.html.haml b/app/views/admin/application_settings/_slack.html.haml
index 140539ab151..e4f46fdf7f2 100644
--- a/app/views/admin/application_settings/_slack.html.haml
+++ b/app/views/admin/application_settings/_slack.html.haml
@@ -18,10 +18,8 @@
%p
= s_('SlackIntegration|You must do this step only once.')
%p
- = link_to slack_app_manifest_share_admin_application_settings_path, class: 'btn btn-default gl-button' do
- = image_tag 'illustrations/slack_logo.svg', class: 'gl-w-9! gl-h-9! gl-my-n4! gl-ml-n4 gl-mr-n2!'
- %strong.gl-button-text
- = s_("SlackIntegration|Create Slack app")
+ = render Pajamas::ButtonComponent.new(href: slack_app_manifest_share_admin_application_settings_path) do
+ = s_("SlackIntegration|Create Slack app")
%hr
%h5
= s_('SlackIntegration|Step 2: Configure the app settings')
diff --git a/app/views/projects/compare/index.html.haml b/app/views/projects/compare/index.html.haml
index 58da76a3231..4a29402bfe7 100644
--- a/app/views/projects/compare/index.html.haml
+++ b/app/views/projects/compare/index.html.haml
@@ -1,16 +1,6 @@
-- breadcrumb_title _("Compare revisions")
-- page_title _("Compare revisions")
+- breadcrumb_title s_("CompareRevisions|Compare revisions")
-%h1.page-title.gl-font-size-h-display
- = _("Compare Git revisions")
-%div
- - example_branch = capture do
- %code.ref-name= @project.default_branch_or_main
- - example_sha = capture do
- %code.ref-name 4eedf23
- = html_escape(_("To see what's changed or create a merge request, choose a branch or tag (like %{branch}), or enter a commit (like %{sha}).")) % { branch: example_branch.html_safe, sha: example_sha.html_safe }
- %br
- = html_escape(_("Changes are shown as if the %{b_open}source%{b_close} revision was being merged into the %{b_open}target%{b_close} revision.")) % { b_open: '<b>'.html_safe, b_close: '</b>'.html_safe }
+- page_title _("CompareRevisions|Compare revisions")
.prepend-top-20
#js-compare-selector{ data: project_compare_selector_data(@project, @merge_request, @compare_params) }
diff --git a/app/views/projects/compare/show.html.haml b/app/views/projects/compare/show.html.haml
index 19db86a086e..5b6f7c392dd 100644
--- a/app/views/projects/compare/show.html.haml
+++ b/app/views/projects/compare/show.html.haml
@@ -1,4 +1,4 @@
-- add_to_breadcrumbs _("Compare revisions"), project_compare_index_path(@project)
+- add_to_breadcrumbs s_("CompareRevisions|Compare revisions"), project_compare_index_path(@project)
- page_title "#{params[:from]} to #{params[:to]}"
.sub-header-block.gl-border-b-0.gl-mb-0.gl-pt-4
@@ -20,13 +20,13 @@
= render Pajamas::CardComponent.new(card_options: { class: "gl-bg-gray-50 gl-mb-5 gl-border-none gl-text-center" }) do |c|
- c.with_body do
%h4
- = s_("CompareBranches|There isn't anything to compare.")
+ = s_("CompareRevisions|There isn't anything to compare.")
%p.gl-mb-4.gl-line-height-24
- if params[:to] == params[:from]
- source_branch = capture do
%span.ref-name= params[:from]
- target_branch = capture do
%span.ref-name= params[:to]
- = (s_("CompareBranches|%{source_branch} and %{target_branch} are the same.") % { source_branch: source_branch, target_branch: target_branch }).html_safe
+ = (s_("CompareRevisions|%{source_branch} and %{target_branch} are the same.") % { source_branch: source_branch, target_branch: target_branch }).html_safe
- else
= _("You'll need to use different branch names to get a valid comparison.")
diff --git a/config/feature_flags/development/global_file_size_check.yml b/config/feature_flags/development/global_file_size_check.yml
new file mode 100644
index 00000000000..eea775cdad5
--- /dev/null
+++ b/config/feature_flags/development/global_file_size_check.yml
@@ -0,0 +1,8 @@
+---
+name: global_file_size_check
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/125956
+rollout_issue_url:
+milestone: '16.2'
+type: development
+group: group::source code
+default_enabled: false
diff --git a/config/feature_flags/development/notify_kas_on_git_push.yml b/config/feature_flags/development/notify_kas_on_git_push.yml
index df90a4d1942..32806418bce 100644
--- a/config/feature_flags/development/notify_kas_on_git_push.yml
+++ b/config/feature_flags/development/notify_kas_on_git_push.yml
@@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/410429
milestone: '16.0'
type: development
group: group::environments
-default_enabled: false
+default_enabled: true
diff --git a/db/docs/batched_background_migrations/backfill_uuid_conversion_column_in_vulnerability_occurrences.yml b/db/docs/batched_background_migrations/backfill_uuid_conversion_column_in_vulnerability_occurrences.yml
new file mode 100644
index 00000000000..43171193f28
--- /dev/null
+++ b/db/docs/batched_background_migrations/backfill_uuid_conversion_column_in_vulnerability_occurrences.yml
@@ -0,0 +1,6 @@
+---
+migration_job_name: BackfillUuidConversionColumnInVulnerabilityOccurrences
+description: backfill values for `uuid_convert_string_to_uuid` column in vulnerability_occurrences table
+feature_category: vulnerability_management
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/124986
+milestone: 16.2
diff --git a/db/post_migrate/20230629095819_queue_backfill_uuid_conversion_column_in_vulnerability_occurrences.rb b/db/post_migrate/20230629095819_queue_backfill_uuid_conversion_column_in_vulnerability_occurrences.rb
new file mode 100644
index 00000000000..0ea7e2da38c
--- /dev/null
+++ b/db/post_migrate/20230629095819_queue_backfill_uuid_conversion_column_in_vulnerability_occurrences.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+class QueueBackfillUuidConversionColumnInVulnerabilityOccurrences < Gitlab::Database::Migration[2.1]
+ MIGRATION = "BackfillUuidConversionColumnInVulnerabilityOccurrences"
+ DELAY_INTERVAL = 2.minutes
+ BATCH_SIZE = 10_000
+ SUB_BATCH_SIZE = 1000
+
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+ def up
+ queue_batched_background_migration(
+ MIGRATION,
+ :vulnerability_occurrences,
+ :id,
+ job_interval: DELAY_INTERVAL,
+ batch_size: BATCH_SIZE,
+ sub_batch_size: SUB_BATCH_SIZE
+ )
+ end
+
+ def down
+ delete_batched_background_migration(MIGRATION, :vulnerability_occurrences, :id, [])
+ end
+end
diff --git a/db/schema_migrations/20230629095819 b/db/schema_migrations/20230629095819
new file mode 100644
index 00000000000..13c1b53ca4b
--- /dev/null
+++ b/db/schema_migrations/20230629095819
@@ -0,0 +1 @@
+4e169ac2e0dd9df9f3f8ebf6041189ccdde1d683d9e64ced6743abdcc22eea7b \ No newline at end of file
diff --git a/doc/administration/admin_area.md b/doc/administration/admin_area.md
index 82ee7c92c6d..1e103bb55c8 100644
--- a/doc/administration/admin_area.md
+++ b/doc/administration/admin_area.md
@@ -196,7 +196,7 @@ You must be an administrator to manually add emails to users:
## User cohorts
-The [Cohorts](../user/admin_area/user_cohorts.md) tab displays the monthly cohorts of new users and their activities over time.
+The [Cohorts](user_cohorts.md) tab displays the monthly cohorts of new users and their activities over time.
## Prevent a user from creating groups
diff --git a/doc/administration/appearance.md b/doc/administration/appearance.md
index ba63f5bfe76..c5c50d95eb6 100644
--- a/doc/administration/appearance.md
+++ b/doc/administration/appearance.md
@@ -69,7 +69,7 @@ to activate it in the GitLab instance. You can also select **Sign-in page**,
to review the saved appearance settings:
NOTE:
-You can add also add a [customized hcelp message](../user/admin_area/settings/help_page.md) below the sign in message or add [a Sign in text message](settings/sign_in_restrictions.md#sign-in-information).
+You can add also add a [customized hcelp message](settings/help_page.md) below the sign in message or add [a Sign in text message](settings/sign_in_restrictions.md#sign-in-information).
## Progressive Web App
diff --git a/doc/administration/compliance.md b/doc/administration/compliance.md
index cc162e8ec53..978e43b2e2c 100644
--- a/doc/administration/compliance.md
+++ b/doc/administration/compliance.md
@@ -20,7 +20,7 @@ and secure supply chain best practices:
| Feature | Instances | Groups | Projects | Description |
|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-----------------------|:-----------------------|:-----------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| [Credentials inventory](../user/admin_area/credentials_inventory.md) | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Keep track of the credentials used by all of the users in a GitLab instance. |
+| [Credentials inventory](credentials_inventory.md) | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Keep track of the credentials used by all of the users in a GitLab instance. |
| [Granular user roles<br/>and flexible permissions](../user/permissions.md) | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | Manage access and permissions with five different user roles and settings for external users. Set permissions according to people's role, rather than either read or write access to a repository. Don't share the source code with people that only need access to the issue tracker. |
| [Merge request approvals](../user/project/merge_requests/approvals/index.md) | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | Configure approvals required for merge requests. |
| [Push rules](../user/project/repository/push_rules.md) | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | Control pushes to your repositories. |
@@ -65,8 +65,8 @@ These features can also help with compliance requirements:
| Feature | Instances | Groups | Projects | Description |
|:------------------------------------------------------------------------------------------------------------------------------------|:-----------------------|:-----------------------|:-----------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| [Email all users of a project,<br/>group, or entire server](../user/admin_area/email_from_gitlab.md) | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Email groups of users based on project or group membership, or email everyone using the GitLab instance. These emails are great for scheduled maintenance or upgrades. |
-| [Enforce ToS acceptance](../user/admin_area/settings/terms.md) | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Enforce your users accepting new terms of service by blocking GitLab traffic. |
+| [Email all users of a project,<br/>group, or entire server](email_from_gitlab.md) | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Email groups of users based on project or group membership, or email everyone using the GitLab instance. These emails are great for scheduled maintenance or upgrades. |
+| [Enforce ToS acceptance](settings/terms.md) | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Enforce your users accepting new terms of service by blocking GitLab traffic. |
| [External Status Checks](../user/project/merge_requests/status_checks.md) | **{dotted-circle}** No | **{dotted-circle}** No | **{check-circle}** Yes | Interface with third-party systems you already use during development to ensure you remain compliant. |
| [Generate reports on permission<br/>levels of users](../administration/admin_area.md#user-permission-export) | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Generate a report listing all users' access permissions for groups and projects in the instance. |
| [License compliance](../user/compliance/license_compliance/index.md) | **{dotted-circle}** No | **{dotted-circle}** No | **{check-circle}** Yes | Search dependencies for their licenses. This lets you determine if the licenses of your project's dependencies are compatible with your project's license. |
diff --git a/doc/administration/configure.md b/doc/administration/configure.md
index 72ee7c3da77..8ff2ae5aa9d 100644
--- a/doc/administration/configure.md
+++ b/doc/administration/configure.md
@@ -35,7 +35,7 @@ Customize and configure your self-managed GitLab installation.
- [Agent server for Kubernetes](../administration/clusters/kas.md)
- [Server hooks](../administration/server_hooks.md)
- [Terraform state](../administration/terraform_state.md)
-- [Terraform limits](../user/admin_area/settings/terraform_limits.md)
+- [Terraform limits](settings/terraform_limits.md)
- [Packages](../administration/packages/index.md)
- [Web terminals](../administration/integration/terminal.md)
- [Wikis](../administration/wikis/index.md)
diff --git a/doc/administration/docs_self_host.md b/doc/administration/docs_self_host.md
index 43aa5f3d871..1eecc139d1f 100644
--- a/doc/administration/docs_self_host.md
+++ b/doc/administration/docs_self_host.md
@@ -173,9 +173,9 @@ documentation URL requests as needed. For example, if your GitLab version is
14.5:
- The GitLab documentation URL becomes `http://0.0.0.0:4000/14.5/`.
-- The link in GitLab displays as `<instance_url>/help/user/admin_area/settings/help_page#destination-requirements`.
+- The link in GitLab displays as `<instance_url>/help/administration/settings/help_page#destination-requirements`.
- When you select the link, you are redirected to
-`http://0.0.0.0:4000/14.5/ee/user/admin_area/settings/help_page/#destination-requirements`.
+`http://0.0.0.0:4000/14.5/ee/administration/settings/help_page/#destination-requirements`.
To test the setting, in GitLab, select a **Learn more** link. For example:
diff --git a/doc/administration/get_started.md b/doc/administration/get_started.md
index bdc57754233..bf3d38657f8 100644
--- a/doc/administration/get_started.md
+++ b/doc/administration/get_started.md
@@ -85,7 +85,7 @@ While this isn't an exhaustive list, following these steps gives you a solid sta
- Set up [email notification for unknown sign-ins](settings/sign_in_restrictions.md#email-notification-for-unknown-sign-ins).
- Configure [user and IP rate limits](https://about.gitlab.com/blog/2020/05/20/gitlab-instance-security-best-practices/#user-and-ip-rate-limits).
- Limit [webhooks local access](https://about.gitlab.com/blog/2020/05/20/gitlab-instance-security-best-practices/#webhooks).
-- Set [rate limits for protected paths](../user/admin_area/settings/protected_paths.md).
+- Set [rate limits for protected paths](settings/protected_paths.md).
- Sign up for [Security Alerts](https://about.gitlab.com/company/preference-center/) from the Communication Preference Center.
- Keep track of security best practices on our [blog page](https://about.gitlab.com/blog/2020/05/20/gitlab-instance-security-best-practices/).
@@ -236,10 +236,10 @@ Rate limits also improve the security of your application.
You can make changes to your default rate limits from the Admin Area. For more information about configuration, see the [Admin Area page](../security/rate_limits.md#configurable-limits).
-- Define [issues rate limits](../user/admin_area/settings/rate_limit_on_issues_creation.md) to set a maximum number of issue creation requests per minute, per user.
-- Enforce [user and IP rate limits](../user/admin_area/settings/user_and_ip_rate_limits.md) for unauthenticated web requests.
-- Review the [rate limit on raw endpoints](../user/admin_area/settings/rate_limits_on_raw_endpoints.md). The default setting is 300 requests per minute for raw file access.
-- Review the [import/export rate limits](../user/admin_area/settings/import_export_rate_limits.md) of the six active defaults.
+- Define [issues rate limits](settings/rate_limit_on_issues_creation.md) to set a maximum number of issue creation requests per minute, per user.
+- Enforce [user and IP rate limits](settings/user_and_ip_rate_limits.md) for unauthenticated web requests.
+- Review the [rate limit on raw endpoints](settings/rate_limits_on_raw_endpoints.md). The default setting is 300 requests per minute for raw file access.
+- Review the [import/export rate limits](settings/import_export_rate_limits.md) of the six active defaults.
For more information about API and rate limits, see our [API page](../api/rest/index.md).
diff --git a/doc/administration/gitaly/troubleshooting.md b/doc/administration/gitaly/troubleshooting.md
index afef787e9c3..3d8110e1dab 100644
--- a/doc/administration/gitaly/troubleshooting.md
+++ b/doc/administration/gitaly/troubleshooting.md
@@ -12,7 +12,7 @@ Refer to the information below when troubleshooting Gitaly and Gitaly Cluster.
The following sections provide possible solutions to Gitaly errors.
-See also [Gitaly timeout](../../user/admin_area/settings/gitaly_timeouts.md) settings,
+See also [Gitaly timeout](../settings/gitaly_timeouts.md) settings,
and our advice on [parsing the `gitaly/current` file](../logs/log_parsing.md#parsing-gitalycurrent).
### Check versions when using standalone Gitaly servers
diff --git a/doc/administration/instance_limits.md b/doc/administration/instance_limits.md
index 81caf0ed62c..679042c3114 100644
--- a/doc/administration/instance_limits.md
+++ b/doc/administration/instance_limits.md
@@ -21,7 +21,7 @@ Read more about [configuring rate limits](../security/rate_limits.md).
This setting limits the request rate to the issue creation endpoint.
-Read more about [issue creation rate limits](../user/admin_area/settings/rate_limit_on_issues_creation.md).
+Read more about [issue creation rate limits](settings/rate_limit_on_issues_creation.md).
- **Default rate limit**: Disabled by default.
@@ -29,7 +29,7 @@ Read more about [issue creation rate limits](../user/admin_area/settings/rate_li
This setting limits the request rate per user or IP.
-Read more about [User and IP rate limits](../user/admin_area/settings/user_and_ip_rate_limits.md).
+Read more about [User and IP rate limits](settings/user_and_ip_rate_limits.md).
- **Default rate limit**: Disabled by default.
@@ -37,7 +37,7 @@ Read more about [User and IP rate limits](../user/admin_area/settings/user_and_i
This setting limits the request rate per endpoint.
-Read more about [raw endpoint rate limits](../user/admin_area/settings/rate_limits_on_raw_endpoints.md).
+Read more about [raw endpoint rate limits](settings/rate_limits_on_raw_endpoints.md).
- **Default rate limit**: 300 requests per project, per commit and per file path.
@@ -59,14 +59,14 @@ GitLab rate limits the following paths by default:
'/admin/session'
```
-Read more about [protected path rate limits](../user/admin_area/settings/protected_paths.md).
+Read more about [protected path rate limits](settings/protected_paths.md).
- **Default rate limit**: After 10 requests, the client must wait 60 seconds before trying again.
### Package Registry
This setting limits the request rate on the Packages API per user or IP. For more information, see
-[Package Registry Rate Limits](../user/admin_area/settings/package_registry_rate_limits.md).
+[Package Registry Rate Limits](settings/package_registry_rate_limits.md).
- **Default rate limit**: Disabled by default.
@@ -86,7 +86,7 @@ requests per user. For more information, read
> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75918) in GitLab 14.6. [Feature flag `files_api_throttling`](https://gitlab.com/gitlab-org/gitlab/-/issues/338903) removed.
This setting limits the request rate on the Packages API per user or IP address. For more information, read
-[Files API rate limits](../user/admin_area/settings/files_api_rate_limits.md).
+[Files API rate limits](settings/files_api_rate_limits.md).
- **Default rate limit**: Disabled by default.
@@ -95,7 +95,7 @@ This setting limits the request rate on the Packages API per user or IP address.
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/68645) in GitLab 14.4.
This setting limits the request rate on deprecated API endpoints per user or IP address. For more information, read
-[Deprecated API rate limits](../user/admin_area/settings/deprecated_api_rate_limits.md).
+[Deprecated API rate limits](settings/deprecated_api_rate_limits.md).
- **Default rate limit**: Disabled by default.
@@ -112,7 +112,7 @@ This setting limits the import/export actions for groups and projects.
| Group Export | 6 |
| Group Export Download | 1 |
-Read more about [import/export rate limits](../user/admin_area/settings/import_export_rate_limits.md).
+Read more about [import/export rate limits](settings/import_export_rate_limits.md).
### Member Invitations
@@ -171,7 +171,7 @@ This endpoint has been requested too many times. Try again later.
This setting limits the request rate to the pipeline creation endpoints.
-Read more about [pipeline creation rate limits](../user/admin_area/settings/rate_limit_on_pipelines_creation.md).
+Read more about [pipeline creation rate limits](settings/rate_limit_on_pipelines_creation.md).
## Gitaly concurrency limit
@@ -800,7 +800,7 @@ Plan.default.actual_limits.update!(dotenv_size: 5.kilobytes)
This setting limits the number of inbound alert payloads over a period of time.
-Read more about [incident management rate limits](../user/admin_area/settings/rate_limit_on_pipelines_creation.md).
+Read more about [incident management rate limits](settings/rate_limit_on_pipelines_creation.md).
### Prometheus Alert JSON payloads
@@ -945,7 +945,7 @@ More information can be found in these documentations:
Total number of changes (branches or tags) in a single push to determine whether
individual push events or a bulk push event are created.
-More information can be found in the [Push event activities limit and bulk push events documentation](../user/admin_area/settings/push_event_activities_limit.md).
+More information can be found in the [Push event activities limit and bulk push events documentation](settings/push_event_activities_limit.md).
## Package Registry Limits
diff --git a/doc/administration/logs/index.md b/doc/administration/logs/index.md
index 28d4a4eedc9..449f33fbbef 100644
--- a/doc/administration/logs/index.md
+++ b/doc/administration/logs/index.md
@@ -754,8 +754,8 @@ This file is located at:
This log records:
-- Requests over the [Rate Limit](../../user/admin_area/settings/rate_limits_on_raw_endpoints.md) on raw endpoints.
-- [Protected paths](../../user/admin_area/settings/protected_paths.md) abusive requests.
+- Requests over the [Rate Limit](../settings/rate_limits_on_raw_endpoints.md) on raw endpoints.
+- [Protected paths](../settings/protected_paths.md) abusive requests.
- In GitLab versions [12.3](https://gitlab.com/gitlab-org/gitlab/-/issues/29239) and later,
user ID and username, if available.
diff --git a/doc/administration/packages/index.md b/doc/administration/packages/index.md
index b735204c323..77730384623 100644
--- a/doc/administration/packages/index.md
+++ b/doc/administration/packages/index.md
@@ -55,7 +55,7 @@ guides you through the process.
When downloading packages as dependencies in downstream projects, many requests are made through the
Packages API. You may therefore reach enforced user and IP rate limits. To address this issue, you
-can define specific rate limits for the Packages API. For more details, see [Package Registry Rate Limits](../../user/admin_area/settings/package_registry_rate_limits.md).
+can define specific rate limits for the Packages API. For more details, see [Package Registry Rate Limits](../settings/package_registry_rate_limits.md).
## Enable or disable the Package Registry
diff --git a/doc/administration/redis/replication_and_failover.md b/doc/administration/redis/replication_and_failover.md
index 4a6f58a8d6a..1db5b82e7dc 100644
--- a/doc/administration/redis/replication_and_failover.md
+++ b/doc/administration/redis/replication_and_failover.md
@@ -659,7 +659,7 @@ persistence classes.
| `shared_state` | Store session-related and other persistent data. |
| `actioncable` | Pub/Sub queue backend for ActionCable. |
| `trace_chunks` | Store [CI trace chunks](../job_logs.md#enable-or-disable-incremental-logging) data. |
-| `rate_limiting` | Store [rate limiting](../../user/admin_area/settings/user_and_ip_rate_limits.md) state. |
+| `rate_limiting` | Store [rate limiting](../settings/user_and_ip_rate_limits.md) state. |
| `sessions` | Store [sessions](../../../ee/development/session.md#gitlabsession). |
| `repository_cache` | Store cache data specific to repositories. |
diff --git a/doc/administration/settings/deprecated_api_rate_limits.md b/doc/administration/settings/deprecated_api_rate_limits.md
index 40d8d704722..f8db0810af5 100644
--- a/doc/administration/settings/deprecated_api_rate_limits.md
+++ b/doc/administration/settings/deprecated_api_rate_limits.md
@@ -51,4 +51,4 @@ To override the general user and IP rate limits for requests to deprecated API e
## Related topics
- [Rate limits](../../security/rate_limits.md)
-- [User and IP rate limits](../../user/admin_area/settings/user_and_ip_rate_limits.md)
+- [User and IP rate limits](../settings/user_and_ip_rate_limits.md)
diff --git a/doc/ci/yaml/signing_examples.md b/doc/ci/yaml/signing_examples.md
index 8aec404502e..5609bd2374e 100644
--- a/doc/ci/yaml/signing_examples.md
+++ b/doc/ci/yaml/signing_examples.md
@@ -70,7 +70,7 @@ verify:
- apk add --update cosign docker
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
script:
- - cosign verify "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA" --certificate-identity "https://gitlab.com/my-group/my-project@refs/heads/main" --certificate-oidc-issuer "https://gitlab.com"
+ - cosign verify "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA" --certificate-identity "https://gitlab.com/my-group/my-project//path/to/.gitlab-ci.yml@refs/heads/main" --certificate-oidc-issuer "https://gitlab.com"
```
## Use Sigstore and npm to generate keyless provenance
@@ -306,5 +306,5 @@ verify_artifact:
before_script:
- apk add --update cosign
script:
- - cosign verify-blob artifact.txt --bundle cosign.bundle --certificate-identity "https://gitlab.com/my-group/my-project@refs/heads/main" --certificate-oidc-issuer "https://gitlab.com"
+ - cosign verify-blob artifact.txt --bundle cosign.bundle --certificate-identity "https://gitlab.com/my-group/my-project//path/to/.gitlab-ci.yml@refs/heads/main" --certificate-oidc-issuer "https://gitlab.com"
```
diff --git a/doc/development/fe_guide/index.md b/doc/development/fe_guide/index.md
index b5ecc000da1..8675866fce6 100644
--- a/doc/development/fe_guide/index.md
+++ b/doc/development/fe_guide/index.md
@@ -77,7 +77,11 @@ Now that our values have been defined, we can base our goals on these values and
- Improve our pipelines speed
- Build a better set of shared components with documentation
-## Browser Support
+### Frontend onboarding course
+
+The [Frontend onboarding course](onboarding_course/index.md) provides a 6-week structured curriculum to learn how to contribute to the GitLab frontend.
+
+### Browser Support
For supported browsers, see our [requirements](../../install/requirements.md#supported-web-browsers).
diff --git a/doc/development/fe_guide/onboarding_course/index.md b/doc/development/fe_guide/onboarding_course/index.md
new file mode 100644
index 00000000000..0b0ffc69f1b
--- /dev/null
+++ b/doc/development/fe_guide/onboarding_course/index.md
@@ -0,0 +1,64 @@
+---
+stage: Manage
+group: Foundations
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+---
+
+# Frontend onboarding course
+
+Welcome to the Frontend Onboarding Course at GitLab!
+In this course, we walk you through your first professional frontend development experience, helping you gain real world skills and learn how to contribute to a large-scale codebase effectively.
+
+Throughout the course, we'll follow a structured approach.
+Each lesson focuses on solving a specific problem on GitLab, giving you hands-on experience.
+You'll learn theory that you can immediately put into practice.
+By working on real-world GitLab issues, you'll encounter challenges and learn how to navigate the codebase effectively while at the same time improving GitLab the product.
+
+We believe in an interactive learning experience.
+You'll have the opportunity to ask questions and seek help from the GitLab community.
+We appreciate your contributions and are here to support your learning while at the same time making GitLab better.
+
+Our teaching style prioritizes practical learning.
+Lessons include an introduction to the problem, theory, live coding walkthroughs, and similar issues for you to tackle.
+As you progress, the complexity of the tasks increase, helping you grow your skills.
+
+Join us on this journey of front-end development at GitLab. Say hello in [the Discord community](https://discord.gg/gitlab) and let's learn and improve together.
+
+## Lessons
+
+- [Lesson 1](lesson_1.md)
+
+## Structure and timings
+
+The course is run over 6 weeks, with a required time commitment of 5-10 hours per week.
+
+The course is free of charge, but we do ask for a commitment to complete the curriculum (including 10 merged merge requests).
+
+After completing the course, you receive a certificate and GitLab achievement.
+
+Each week consists of the following sessions:
+
+- 1-hour relaxed discussion-style lesson with explanation of how GitLab frontend works. Each week features a different guest and includes an AMA portion.
+- 2-hour live coding lesson with a practical task for participants to complete.
+- 2 x 2-hour dedicated “Office Hours” sessions where participants can work on the task assigned in the lesson with GitLab frontend engineers. (2 sessions in different timezones as this will require participants to join synchronously)
+
+A fortnightly 1-on-1 mentoring sessions are also available to each participant.
+
+There are 10 places available on the course.
+The date will be set after the course material has been prepared.
+Please complete the [Frontend Onboarding Course Application Form](https://forms.gle/39Rs4w4ZxQuByhE4A) to apply.
+
+You may also participate in the course informally at your own pace, without the benefit of the synchronous office hours or mentoring session.
+GitLab team members are happy to support you regardless.
+
+## Curriculum summary
+
+### Lesson 1
+
+- What is a development environment?
+ - What is the GDK?
+ - Installing the GDK.
+ - GDK tips and tricks.
+ - Using GitPod to run the GDK.
+- Navigating the GitLab codebase.
+- Writing a good merge request.
diff --git a/doc/development/fe_guide/onboarding_course/lesson_1.md b/doc/development/fe_guide/onboarding_course/lesson_1.md
new file mode 100644
index 00000000000..e82d350f854
--- /dev/null
+++ b/doc/development/fe_guide/onboarding_course/lesson_1.md
@@ -0,0 +1,183 @@
+---
+stage: manage
+group: foundations
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+---
+
+# Lesson 1
+
+<div class="video-fallback">
+ See the video: <a href="https://www.youtube.com/watch?v=k4C3-FKvZyI">Lesson 1 intro</a>.
+</div>
+<figure class="video-container">
+ <iframe src="https://www.youtube-nocookie.com/embed/k4C3-FKvZyI" frameborder="0" allowfullscreen> </iframe>
+</figure>
+
+In this lesson you tackle the smallest of problems - a one-character text change. To do so, we have to learn:
+
+- How to set up a GitLab Development Environment.
+- How to navigate the GitLab code base.
+- How to create a merge request in the GitLab project.
+
+After we have learned these 3 things, a GitLab team member will do a live coding demo.
+In the demo, they'll use each of the things learned by completing one of these small issues, so that you can complete an issue by yourself.
+
+There is a list of issues that are very similar to the one we'll be live coding [here in the "Linked items" section](https://gitlab.com/gitlab-org/gitlab/-/issues/389920), it would be worth commenting on one of these now to get yourself assigned to one so that you can follow along.
+
+## What is the GDK?
+
+<div class="video-fallback">
+ See the video: <a href="https://www.youtube.com/watch?v=qXGXshfo934">What is the GDK</a>?
+</div>
+<figure class="video-container">
+ <iframe src="https://www.youtube-nocookie.com/embed/qXGXshfo934" frameborder="0" allowfullscreen> </iframe>
+</figure>
+
+The GDK (GitLab Development Kit) is a local instance of GitLab that allows developers to run and test GitLab on their own computers.
+Unlike frontend only applications, the GDK runs the entire GitLab application, including the back-end services, APIs, and a local database.
+This allows developers to make changes, test them in real-time, and validate their modifications.
+
+Tips for using the GDK:
+
+- Troubleshooting documentation: When encountering issues with the GDK, refer to the troubleshooting documentation in the [GDK repository](https://gitlab.com/gitlab-org/gitlab-development-kit/-/tree/main/doc/troubleshooting).
+ These resources provide useful commands and tips to help resolve common problems.
+- Using the Rails console: The Rails console is an essential tool for interacting with your local instance of GitLab.
+ You can access it by running `gdk rails c` and use it to enable or disable feature flags, perform backend operations, and more.
+- Stay updated: Regularly update your GDK by running `gdk update`.
+ This command fetches the latest branch of the GitLab project, as well as the latest branch of the GDK and its dependencies.
+ Keeping your GDK up to date helps ensure you will be working with the latest version of GitLab and make sure you have the latest bug fixes.
+
+Remember, if you need further assistance or have specific questions, you can reach out to the GitLab community through our [Discord](https://discord.gg/gitlab) or [other available support channels](https://about.gitlab.com/community/contribute/).
+
+## Installing and using the GDK locally
+
+<div class="video-fallback">
+ See the video: <a href="https://www.youtube.com/watch?v=fcOyjuCizmY">Installing the GDK</a>.
+</div>
+<figure class="video-container">
+ <iframe src="https://www.youtube-nocookie.com/embed/fcOyjuCizmY" frameborder="0" allowfullscreen> </iframe>
+</figure>
+
+For the latest installation instructions, refer to the [GitLab Development Kit documentation](https://gitlab.com/gitlab-org/gitlab-development-kit#installation).
+
+Here's a step-by-step summary:
+
+1. Prerequisites:
+ - 16 GB RAM. If you have less, consider [using Gitpod](#using-gitpod-instead-of-running-the-gdk-locally)
+ - Ensure that Git is installed on your machine.
+ - Install a code editor, such as Visual Studio Code.
+ - [Create an account](https://gitlab.com/users/sign_up) or [sign in](https://gitlab.com/users/sign_in) on GitLab.com and join the [community members group](https://gitlab.com/gitlab-community/meta#request-access-to-community-forks).
+1. Installation:
+ - Choose a directory to install the GitLab Development Kit (GDK).
+ - Open your terminal and navigate to the chosen directory.
+ - Download and run the installation script from the terminal:
+
+ ```shell
+ curl "https://gitlab.com/gitlab-org/gitlab-development-kit/-/raw/main/support/install" | bash
+ ```
+
+ - Only run scripts from trusted sources to ensure your safety.
+ - The installation process may take around 20 minutes or more.
+1. Choosing the repository:
+ - Instead of cloning the main GitLab repository, use the community fork recommended for wider community members.
+ - Follow the instructions provided to install the community fork.
+1. GDK structure:
+ - After the installation, the GDK directory is created.
+ - Inside the GDK directory, you'll find the GitLab project folder.
+1. Working with the GDK:
+ - GDK offers lots of commands you can use to interact with your installation. To run those commands you must be inside the GDK or GitLab folder.
+ - To start the GDK, run the command `gdk start` in your terminal.
+ - You can explore available commands and options by running `gdk help` in the terminal.
+
+Remember to consult the documentation or seek community support if you have any further questions or issues.
+
+## Using Gitpod instead of running the GDK locally
+
+<div class="video-fallback">
+ See the video: <a href="https://www.youtube.com/watch?v=RI2kM5_oii4">Using Gitpod with GitLab</a>.
+</div>
+<figure class="video-container">
+ <iframe src="https://www.youtube-nocookie.com/embed/RI2kM5_oii4" frameborder="0" allowfullscreen> </iframe>
+</figure>
+
+Gitpod is a service that allows you to run a virtual machine, specifically the GitLab Development Kit (GDK), on the Gitpod server instead of running it on your own machine.
+It provides a web-based Integrated Development Environment (IDE) where you can edit code and see the GDK in action.
+Gitpod is useful for quickly getting a GDK environment up and running, for making small merge requests without installing the GDK locally, or for running GDK on a machine that may not have enough resources.
+
+To use Gitpod:
+
+1. Go to the [GitLab community fork website](https://gitlab.com/gitlab-community/gitlab), select **Edit**, then select **Gitpod**.
+1. Configure your settings, such as the editor (VS Code desktop or browser) and the context (usually the `main` or `master` branch).
+1. Select **Open** to create your Gitpod workspace. This process may take up to 20 minutes. The GitLab Development Kit (GDK) will be installed in the Gitpod workspace. This installation is faster than downloading and installing the full GDK locally.
+
+After the workspace is created, you'll find your chosen IDE running in your browser. You can also connect it to your desktop IDE if preferred.
+Treat Gitpod just like you would use VS Code locally. Create branches, make code changes, commit them, and push them back to the community fork.
+
+Other tips:
+
+- Remember to push your code regularly to avoid the workspace timing out. Idle workspaces are eventually destroyed.
+- Customize your Gitpod workspace settings if needed, such as making your instance of GitLab frontend publicly available.
+- If you run out of minutes, contact the support team on the Discord server.
+- Troubleshoot issues by using commands like `gdk start` and `gdk status` in the Gitpod workspace as you would if it was running locally.
+
+By following these steps, you can leverage Gitpod to efficiently develop with the GitLab Development Kit without the need for local installation.
+
+## Navigating the GitLab codebase
+
+<div class="video-fallback">
+ See the video: <a href="https://www.youtube.com/watch?v=Wc5u879_0Aw">How to navigate the GitLab codebase</a>.
+</div>
+<figure class="video-container">
+ <iframe src="https://www.youtube-nocookie.com/embed/Wc5u879_0Aw" frameborder="0" allowfullscreen> </iframe>
+</figure>
+
+Understanding how to navigate the GitLab codebase is essential for contributors.
+Navigating the codebase and locating specific files can be challenging but crucial for making changes and addressing issues effectively.
+Here we'll explore a step-by-step process for finding files and finding where they are rendered in GitLab.
+
+If you already know the file you are going to work on and now you want to find where it is rendered:
+
+1. Start by gathering clues to understand the file’s purpose. Look for relevant information within the file itself, such as keywords or specific content that might indicate its context.
+1. You can also examine the file path (or folder structure) to gain insights into where the file might be rendered.
+ A lot of routing in GitLab is very similar to the folder structure.
+1. If you can work out which feature (or one of the features) that this component is used in, you can then leverage the GitLab user documentation to find out how to navigate to the feature page.
+1. Follow the component hierarchy, do a global search for the file name to identify the parent component that renders the component.
+ Continue to follow the hierarchy of components to trace back to a feature you recognize or can search for in the GitLab user docs.
+1. You can use `git blame` with an extension like GitLens to find a recent MR where this file was changed.
+ Most MR’s have a "How to validate" section that you can follow, if the MR doesn't have one, look for the previous change and until you find one that have validation steps.
+
+If you know which page you need to fix and you want to find the file path, here are some things you can try:
+
+- Look for content that is unique and doesn’t contain variables so that you can search for the translation variable.
+- Try using Vue Dev Tools to find the component name.
+- Look for unique identifiers like a `data-testid`,`id` or a unique looking CSS class in the HTML of the component and then search globally the codebase for those identifying strings.
+
+## Writing a good merge request
+
+<div class="video-fallback">
+ See the video: <a href="https://www.youtube.com/watch?v=H5zozDNIn98">How to write a good MR</a>.
+</div>
+<figure class="video-container">
+ <iframe src="https://www.youtube-nocookie.com/embed/H5zozDNIn98" frameborder="0" allowfullscreen> </iframe>
+</figure>
+
+When writing a merge request there are some important things to be aware of:
+
+- Your MR will become a permanent part of the documentation of the GitLab project.
+ It may be used in the future to help people understand why some code works the way it does and why it doesn't use an alternative solution.
+- At least 2 other engineers are going to review your code. For the sake of efficiency (much like the code itself you have written) it is best to take a little while longer to get your MR right so that it is quicker and easier for others to read.
+- The MRs that you create on GitLab are available to the public. This means you can add a link to MRs you are particularly proud of to your portfolio page when looking for a job.
+- Since an MR is a technical document, you should try to implement a technical writing style.
+ If you don’t know what that is, here is a highly recommended short course from [Google on Technical writing](https://developers.google.com/tech-writing/one).
+ If you are also contributing to the documentation at GitLab, there is a [Technical Writing Fundamentals course available here from GitLab](https://about.gitlab.com/handbook/product/ux/technical-writing/fundamentals/).
+
+## Live coding
+
+<div class="video-fallback">
+ See the video: <a href="https://www.youtube.com/watch?v=BJCCwc1Czt4">Lesson 1 code walkthrough</a>.
+</div>
+<figure class="video-container">
+ <iframe src="https://www.youtube-nocookie.com/embed/BJCCwc1Czt4" frameborder="0" allowfullscreen> </iframe>
+</figure>
+
+Now it is your turn to complete your first MR, there is a list of issues that are very similar to the one we just finished that need completing [here in the "Linked items" section](https://gitlab.com/gitlab-org/gitlab/-/issues/389920). Thanks for contributing! (if there are none left, let us know on [Discord](https://discord.gg/gitlab) or [other available support channels](https://about.gitlab.com/community/contribute/) and we'll find more for you)
diff --git a/doc/user/asciidoc.md b/doc/user/asciidoc.md
index f04fece7b76..d2041083d36 100644
--- a/doc/user/asciidoc.md
+++ b/doc/user/asciidoc.md
@@ -411,7 +411,7 @@ Color written inside backticks is followed by a color "chip":
### Equations and Formulas (STEM)
-If you need to include Science, Technology, Engineering and Math (STEM)
+If you need to include Science, Technology, Engineering, and Math (STEM)
expressions, set the `stem` attribute in the document's header to `latexmath`.
Equations and formulas are rendered using [KaTeX](https://katex.org/):
diff --git a/doc/user/product_analytics/index.md b/doc/user/product_analytics/index.md
index 0446f720430..e04c61b2c00 100644
--- a/doc/user/product_analytics/index.md
+++ b/doc/user/product_analytics/index.md
@@ -125,6 +125,29 @@ The `cube_analytics` data type connects to the Cube instance defined when [produ
All filters and queries are sent to the Cube instance and the returned data is processed by the
product analytics data source to be rendered by the appropriate visualizations.
+### Filling missing data
+
+- Introduced in GitLab 16.3 behind the [feature flag](../../administration/feature_flags.md) named `product_analytics_dashboards`. Disabled by default.
+
+When [exporting data](#raw-data-export) or [viewing dashboards](../analytics/analytics_dashboards.md#view-project-dashboards),
+if there is no data for a given day, the missing data is autofilled with `0`.
+
+This approach has the following benefits:
+
+- The visualization's day axis matches the selected date range, removing ambiguity about missing data.
+- Data exports have rows for the entire date range, making data analysis easier.
+
+However, this approach also has the following limitations:
+
+- The `day` [granularity](https://cube.dev/docs/product/apis-integrations/rest-api/query-format) must be used.
+ All other granularities are not supported at this time.
+- It only fills a date range defined by the [`inDateRange`](https://cube.dev/docs/product/apis-integrations/rest-api/query-format#indaterange) filter.
+ - The date selector in the UI already uses this filter.
+- The filling of data ignores the query-defined limit. If you set a limit of 10 data points over 20 days, it
+ returns 20 data points, with the missing data filled by `0`.
+
+[Issue 417231](https://gitlab.com/gitlab-org/gitlab/-/issues/417231) proposes a solution to this limitation.
+
## Funnel analysis
Use funnel analysis to understand the flow of users through your application, and where
diff --git a/doc/user/project/repository/code_suggestions.md b/doc/user/project/repository/code_suggestions.md
index 7976b0a9dea..95d5873a535 100644
--- a/doc/user/project/repository/code_suggestions.md
+++ b/doc/user/project/repository/code_suggestions.md
@@ -291,7 +291,7 @@ To confirm that your account is enabled, go to [https://gitlab.com/api/v4/ml/ai-
#### Code Suggestions not displayed in VS Code or GitLab WebIDE
-Check all steps above first.
+Check all the steps in [Code Suggestions aren't displayed](#code-suggestions-arent-displayed) first.
If you are a self-managed user, ensure that Code Suggestions for the [GitLab WebIDE](../../project/web_ide/index.md) are enabled. The same settings apply to VS Code as local IDE.
@@ -303,7 +303,7 @@ If you are a self-managed user, ensure that Code Suggestions for the [GitLab Web
If the settings are enabled, but Code Suggestions are still not displayed, try the following steps:
1. Enable the `Debug` checkbox in the GitLab Workflow **Extension Settings**.
-1. Open the extension log in **View > Output** and change the dropdown to **GitLab Workflow** as log filter. The command palette command is `GitLab: Show Extension Logs`.
+1. Open the extension log in **View > Output** and change the dropdown list to **GitLab Workflow** as the log filter. The command palette command is `GitLab: Show Extension Logs`.
1. Disable and re-enable the **Enable code completion (Beta)** checkbox.
1. Verify that the debug log contains similar output:
@@ -313,6 +313,21 @@ If the settings are enabled, but Code Suggestions are still not displayed, try t
2023-07-14T17:29:01:802 [debug]: AI Assist: Using server: https://codesuggestions.gitlab.com/v2/completions
```
+#### Code Suggestions not displayed in Microsoft Visual Studio
+
+Check all the steps in [Code Suggestions aren't displayed](#code-suggestions-arent-displayed) first.
+
+1. Ensure you have properly [set up the extension](https://gitlab.com/gitlab-org/editor-extensions/gitlab-visual-studio-extension#setup).
+1. From the **Tools > Options** menu, find the **GitLab** option. Ensure **Log Level** is set to **Debug**.
+1. Open the extension log in **View > Output** and change the dropdown list to **GitLab Extension** as the log filter.
+1. Verify that the debug log contains similar output:
+
+```shell
+14:48:21:344 GitlabProposalSource.GetCodeSuggestionAsync
+14:48:21:344 LsClient.SendTextDocumentCompletionAsync("GitLab.Extension.Test\TestData.cs", 34, 0)
+14:48:21:346 LS(55096): time="2023-07-17T14:48:21-05:00" level=info msg="update context"
+```
+
### Authentication troubleshooting
If the above steps do not solve your issue, the problem may be related to the recent changes in authentication,
diff --git a/lib/gitlab/background_migration/backfill_uuid_conversion_column_in_vulnerability_occurrences.rb b/lib/gitlab/background_migration/backfill_uuid_conversion_column_in_vulnerability_occurrences.rb
new file mode 100644
index 00000000000..4dccd3fd852
--- /dev/null
+++ b/lib/gitlab/background_migration/backfill_uuid_conversion_column_in_vulnerability_occurrences.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BackgroundMigration
+ # This batched background migration will backfill values for `uuid_convert_string_to_uuid` column in
+ # vulnerability_occurrences table to allow us to migrate the column type from `varchar(36)` to `uuid`
+ class BackfillUuidConversionColumnInVulnerabilityOccurrences < BatchedMigrationJob
+ operation_name :backfill_uuid_conversion_column_in_vulnerability_occurrences
+ scope_to ->(relation) do
+ relation.where("uuid_convert_string_to_uuid = '00000000-0000-0000-0000-000000000000'::uuid")
+ end
+ feature_category :vulnerability_management
+
+ def perform
+ each_sub_batch do |sub_batch|
+ sub_batch.update_all("uuid_convert_string_to_uuid = uuid::uuid")
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/checks/changes_access.rb b/lib/gitlab/checks/changes_access.rb
index 194e3f6e938..3fd7e44985e 100644
--- a/lib/gitlab/checks/changes_access.rb
+++ b/lib/gitlab/checks/changes_access.rb
@@ -117,6 +117,7 @@ module Gitlab
def bulk_access_checks!
Gitlab::Checks::LfsCheck.new(self).validate!
+ Gitlab::Checks::GlobalFileSizeCheck.new(self).validate!
end
def blank_rev?(rev)
diff --git a/lib/gitlab/checks/global_file_size_check.rb b/lib/gitlab/checks/global_file_size_check.rb
new file mode 100644
index 00000000000..418d2d32b57
--- /dev/null
+++ b/lib/gitlab/checks/global_file_size_check.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Checks
+ class GlobalFileSizeCheck < BaseBulkChecker
+ MAX_FILE_SIZE_MB = 100
+ LOG_MESSAGE = 'Checking for blobs over the file size limit'
+
+ def validate!
+ return unless Feature.enabled?(:global_file_size_check, project)
+
+ Gitlab::AppJsonLogger.info(LOG_MESSAGE)
+ logger.log_timed(LOG_MESSAGE) do
+ Gitlab::Checks::FileSizeCheck::AllowExistingOversizedBlobs.new(
+ project: project,
+ changes: changes,
+ file_size_limit_megabytes: MAX_FILE_SIZE_MB
+ ).find
+
+ # TODO: https://gitlab.com/gitlab-org/gitlab/-/issues/393535
+ # - set limit per plan tier
+ # - raise an error if large blobs are found
+ end
+
+ true
+ end
+ end
+ end
+end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index e1c08b66967..5708517ac66 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -2279,9 +2279,15 @@ msgstr ""
msgid "AbuseReport|Confirmed violation of a copyright or a trademark"
msgstr ""
+msgid "AbuseReport|Copyright or trademark violation"
+msgstr ""
+
msgid "AbuseReport|Credit card"
msgstr ""
+msgid "AbuseReport|Crypto Mining"
+msgstr ""
+
msgid "AbuseReport|Delete user"
msgstr ""
@@ -2309,6 +2315,9 @@ msgstr ""
msgid "AbuseReport|Last login"
msgstr ""
+msgid "AbuseReport|Malware"
+msgstr ""
+
msgid "AbuseReport|Member since"
msgstr ""
@@ -2321,6 +2330,18 @@ msgstr ""
msgid "AbuseReport|Normal location"
msgstr ""
+msgid "AbuseReport|Offensive or Abusive"
+msgstr ""
+
+msgid "AbuseReport|Other"
+msgstr ""
+
+msgid "AbuseReport|Personal information or credentials"
+msgstr ""
+
+msgid "AbuseReport|Phishing"
+msgstr ""
+
msgid "AbuseReport|Phone"
msgstr ""
@@ -2360,6 +2381,9 @@ msgstr ""
msgid "AbuseReport|Something else"
msgstr ""
+msgid "AbuseReport|Spam"
+msgstr ""
+
msgid "AbuseReport|Tier"
msgstr ""
@@ -6371,9 +6395,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign myself"
-msgstr ""
-
msgid "Assign reviewer"
msgstr ""
@@ -6395,6 +6416,9 @@ msgstr ""
msgid "Assign to me"
msgstr ""
+msgid "Assign yourself"
+msgstr ""
+
msgid "Assigned"
msgstr ""
@@ -9243,9 +9267,6 @@ msgstr ""
msgid "Changes"
msgstr ""
-msgid "Changes are shown as if the %{b_open}source%{b_close} revision was being merged into the %{b_open}target%{b_close} revision."
-msgstr ""
-
msgid "Changes saved."
msgstr ""
@@ -11536,9 +11557,6 @@ msgstr ""
msgid "Compare %{oldCommitId}...%{newCommitId}"
msgstr ""
-msgid "Compare Git revisions"
-msgstr ""
-
msgid "Compare GitLab editions"
msgstr ""
@@ -11566,10 +11584,7 @@ msgstr ""
msgid "Compare with previous version"
msgstr ""
-msgid "CompareBranches|%{source_branch} and %{target_branch} are the same."
-msgstr ""
-
-msgid "CompareBranches|There isn't anything to compare."
+msgid "CompareRevisions|%{source_branch} and %{target_branch} are the same."
msgstr ""
msgid "CompareRevisions|Branches"
@@ -11620,6 +11635,9 @@ msgstr ""
msgid "CompareRevisions|Tags"
msgstr ""
+msgid "CompareRevisions|There isn't anything to compare."
+msgstr ""
+
msgid "CompareRevisions|There was an error while loading the branch/tag list. Please try again."
msgstr ""
@@ -48118,9 +48136,6 @@ msgstr ""
msgid "To see this project's operational details, contact an owner of group %{groupName} to upgrade the plan. You can also remove the project from the dashboard."
msgstr ""
-msgid "To see what's changed or create a merge request, choose a branch or tag (like %{branch}), or enter a commit (like %{sha})."
-msgstr ""
-
msgid "To set up SAML authentication for your group through an identity provider like Azure, Okta, Onelogin, Ping Identity, or your custom SAML 2.0 provider:"
msgstr ""
@@ -52297,6 +52312,9 @@ msgstr ""
msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching work item award emojis. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while promoting the %{workItemType}. Please try again."
msgstr ""
diff --git a/spec/frontend/admin/abuse_reports/components/abuse_category_spec.js b/spec/frontend/admin/abuse_reports/components/abuse_category_spec.js
new file mode 100644
index 00000000000..456df3b1857
--- /dev/null
+++ b/spec/frontend/admin/abuse_reports/components/abuse_category_spec.js
@@ -0,0 +1,43 @@
+import { GlLabel } from '@gitlab/ui';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import AbuseCategory from '~/admin/abuse_reports/components/abuse_category.vue';
+import { ABUSE_CATEGORIES } from '~/admin/abuse_reports/constants';
+import { mockAbuseReports } from '../mock_data';
+
+describe('AbuseCategory', () => {
+ let wrapper;
+
+ const mockAbuseReport = mockAbuseReports[0];
+ const category = ABUSE_CATEGORIES[mockAbuseReport.category];
+
+ const findLabel = () => wrapper.findComponent(GlLabel);
+
+ const createComponent = (props = {}) => {
+ wrapper = shallowMountExtended(AbuseCategory, {
+ propsData: {
+ category: mockAbuseReport.category,
+ ...props,
+ },
+ });
+ };
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('renders a label', () => {
+ expect(findLabel().exists()).toBe(true);
+ });
+
+ it('renders the label with the right background color for the category', () => {
+ expect(findLabel().props()).toMatchObject({
+ backgroundColor: category.backgroundColor,
+ title: category.title,
+ target: null,
+ });
+ });
+
+ it('renders the label with the right text color for the category', () => {
+ expect(findLabel().attributes('class')).toBe(`gl-text-${category.color}`);
+ });
+});
diff --git a/spec/frontend/admin/abuse_reports/components/abuse_report_row_spec.js b/spec/frontend/admin/abuse_reports/components/abuse_report_row_spec.js
index f3cced81478..03bf510f3ad 100644
--- a/spec/frontend/admin/abuse_reports/components/abuse_report_row_spec.js
+++ b/spec/frontend/admin/abuse_reports/components/abuse_report_row_spec.js
@@ -1,6 +1,7 @@
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import setWindowLocation from 'helpers/set_window_location_helper';
import AbuseReportRow from '~/admin/abuse_reports/components/abuse_report_row.vue';
+import AbuseCategory from '~/admin/abuse_reports/components/abuse_category.vue';
import ListItem from '~/vue_shared/components/registry/list_item.vue';
import { getTimeago } from '~/lib/utils/datetime_utility';
import { SORT_UPDATED_AT } from '~/admin/abuse_reports/constants';
@@ -11,7 +12,8 @@ describe('AbuseReportRow', () => {
const mockAbuseReport = mockAbuseReports[0];
const findListItem = () => wrapper.findComponent(ListItem);
- const findTitle = () => wrapper.findByTestId('title');
+ const findAbuseCategory = () => wrapper.findComponent(AbuseCategory);
+ const findAbuseReportTitle = () => wrapper.findByTestId('abuse-report-title');
const findDisplayedDate = () => wrapper.findByTestId('abuse-report-date');
const createComponent = (props = {}) => {
@@ -35,13 +37,13 @@ describe('AbuseReportRow', () => {
const { reporter, reportedUser, category, reportPath } = mockAbuseReport;
it('displays correctly formatted title', () => {
- expect(findTitle().text()).toMatchInterpolatedText(
+ expect(findAbuseReportTitle().text()).toMatchInterpolatedText(
`${reportedUser.name} reported for ${category} by ${reporter.name}`,
);
});
it('links to the details page', () => {
- expect(findTitle().attributes('href')).toEqual(reportPath);
+ expect(findAbuseReportTitle().attributes('href')).toEqual(reportPath);
});
describe('when the reportedUser is missing', () => {
@@ -50,7 +52,7 @@ describe('AbuseReportRow', () => {
});
it('displays correctly formatted title', () => {
- expect(findTitle().text()).toMatchInterpolatedText(
+ expect(findAbuseReportTitle().text()).toMatchInterpolatedText(
`Deleted user reported for ${category} by ${reporter.name}`,
);
});
@@ -62,7 +64,7 @@ describe('AbuseReportRow', () => {
});
it('displays correctly formatted title', () => {
- expect(findTitle().text()).toMatchInterpolatedText(
+ expect(findAbuseReportTitle().text()).toMatchInterpolatedText(
`${reportedUser.name} reported for ${category} by Deleted user`,
);
});
@@ -88,4 +90,8 @@ describe('AbuseReportRow', () => {
});
});
});
+
+ it('renders abuse category', () => {
+ expect(findAbuseCategory().exists()).toBe(true);
+ });
});
diff --git a/spec/frontend/work_items/components/work_item_assignees_spec.js b/spec/frontend/work_items/components/work_item_assignees_spec.js
index 94d47bfb3be..ff1998ab2ed 100644
--- a/spec/frontend/work_items/components/work_item_assignees_spec.js
+++ b/spec/frontend/work_items/components/work_item_assignees_spec.js
@@ -274,14 +274,14 @@ describe('WorkItemAssignees component', () => {
});
describe('when assigning to current user', () => {
- it('does not show `Assign myself` button if current user is loading', () => {
+ it('does not show `Assign yourself` button if current user is loading', () => {
createComponent();
findTokenSelector().trigger('mouseover');
expect(findAssignSelfButton().exists()).toBe(false);
});
- it('does not show `Assign myself` button if work item has assignees', async () => {
+ it('does not show `Assign yourself` button if work item has assignees', async () => {
createComponent();
await waitForPromises();
findTokenSelector().trigger('mouseover');
@@ -289,7 +289,7 @@ describe('WorkItemAssignees component', () => {
expect(findAssignSelfButton().exists()).toBe(false);
});
- it('does now show `Assign myself` button if user is not logged in', async () => {
+ it('does now show `Assign yourself` button if user is not logged in', async () => {
createComponent({ currentUserQueryHandler: noCurrentUserQueryHandler, assignees: [] });
await waitForPromises();
findTokenSelector().trigger('mouseover');
@@ -304,7 +304,7 @@ describe('WorkItemAssignees component', () => {
return waitForPromises();
});
- it('renders `Assign myself` button', () => {
+ it('renders `Assign yourself` button', () => {
findTokenSelector().trigger('mouseover');
expect(findAssignSelfButton().exists()).toBe(true);
});
diff --git a/spec/frontend/work_items/components/work_item_award_emoji_spec.js b/spec/frontend/work_items/components/work_item_award_emoji_spec.js
index 82be6d990e4..f8c5f8edc4c 100644
--- a/spec/frontend/work_items/components/work_item_award_emoji_spec.js
+++ b/spec/frontend/work_items/components/work_item_award_emoji_spec.js
@@ -1,4 +1,4 @@
-import Vue from 'vue';
+import Vue, { nextTick } from 'vue';
import VueApollo from 'vue-apollo';
import { shallowMount } from '@vue/test-utils';
@@ -9,36 +9,67 @@ import { isLoggedIn } from '~/lib/utils/common_utils';
import AwardList from '~/vue_shared/components/awards_list.vue';
import WorkItemAwardEmoji from '~/work_items/components/work_item_award_emoji.vue';
import updateAwardEmojiMutation from '~/work_items/graphql/update_award_emoji.mutation.graphql';
-import workItemByIidQuery from '~/work_items/graphql/work_item_by_iid.query.graphql';
-import { EMOJI_THUMBSUP, EMOJI_THUMBSDOWN } from '~/work_items/constants';
+import workItemAwardEmojiQuery from '~/work_items/graphql/award_emoji.query.graphql';
+import {
+ EMOJI_THUMBSUP,
+ EMOJI_THUMBSDOWN,
+ DEFAULT_PAGE_SIZE_EMOJIS,
+ I18N_WORK_ITEM_FETCH_AWARD_EMOJI_ERROR,
+} from '~/work_items/constants';
import {
workItemByIidResponseFactory,
mockAwardsWidget,
mockAwardEmojiThumbsUp,
getAwardEmojiResponse,
+ mockMoreThanDefaultAwardEmojisWidget,
} from '../mock_data';
jest.mock('~/lib/utils/common_utils');
+jest.mock('~/work_items/constants', () => ({
+ ...jest.requireActual('~/work_items/constants'),
+ DEFAULT_PAGE_SIZE_EMOJIS: 5,
+}));
+
Vue.use(VueApollo);
describe('WorkItemAwardEmoji component', () => {
let wrapper;
let mockApolloProvider;
- const errorMessage = 'Failed to update the award';
+ const mutationErrorMessage = 'Failed to update the award';
+
const workItemQueryResponse = workItemByIidResponseFactory();
- const workItemQueryAddAwardEmojiResponse = workItemByIidResponseFactory({
- awardEmoji: { ...mockAwardsWidget, nodes: [mockAwardEmojiThumbsUp] },
- });
- const workItemQueryRemoveAwardEmojiResponse = workItemByIidResponseFactory({
- awardEmoji: { ...mockAwardsWidget, nodes: [] },
- });
+ const mockWorkItem = workItemQueryResponse.data.workspace.workItems.nodes[0];
+
+ const awardEmojiQuerySuccessHandler = jest.fn().mockResolvedValue(workItemQueryResponse);
+ const awardEmojiQueryEmptyHandler = jest.fn().mockResolvedValue(
+ workItemByIidResponseFactory({
+ awardEmoji: {
+ ...mockAwardsWidget,
+ nodes: [],
+ },
+ }),
+ );
+ const awardEmojiQueryThumbsUpHandler = jest.fn().mockResolvedValue(
+ workItemByIidResponseFactory({
+ awardEmoji: {
+ ...mockAwardsWidget,
+ nodes: [mockAwardEmojiThumbsUp],
+ },
+ }),
+ );
+ const awardEmojiQueryFailureHandler = jest
+ .fn()
+ .mockRejectedValue(new Error(I18N_WORK_ITEM_FETCH_AWARD_EMOJI_ERROR));
+
const awardEmojiAddSuccessHandler = jest.fn().mockResolvedValue(getAwardEmojiResponse(true));
const awardEmojiRemoveSuccessHandler = jest.fn().mockResolvedValue(getAwardEmojiResponse(false));
- const awardEmojiUpdateFailureHandler = jest.fn().mockRejectedValue(new Error(errorMessage));
- const mockWorkItem = workItemQueryResponse.data.workspace.workItems.nodes[0];
- const mockAwardEmojiDifferentUserThumbsUp = {
+ const awardEmojiUpdateFailureHandler = jest
+ .fn()
+ .mockRejectedValue(new Error(mutationErrorMessage));
+
+ const mockAwardEmojiDifferentUser = {
name: 'thumbsup',
__typename: 'AwardEmoji',
user: {
@@ -49,35 +80,37 @@ describe('WorkItemAwardEmoji component', () => {
};
const createComponent = ({
- awardMutationHandler = awardEmojiAddSuccessHandler,
- workItem = mockWorkItem,
+ awardEmojiQueryHandler = awardEmojiQuerySuccessHandler,
+ awardEmojiMutationHandler = awardEmojiAddSuccessHandler,
workItemIid = '1',
- awardEmoji = { ...mockAwardsWidget, nodes: [] },
} = {}) => {
- mockApolloProvider = createMockApollo([[updateAwardEmojiMutation, awardMutationHandler]]);
-
- mockApolloProvider.clients.defaultClient.writeQuery({
- query: workItemByIidQuery,
- variables: { fullPath: workItem.project.fullPath, iid: workItemIid },
- data: {
- ...workItemQueryResponse.data,
- workspace: {
- __typename: 'Project',
- id: 'gid://gitlab/Project/1',
- workItems: {
- nodes: [workItem],
+ mockApolloProvider = createMockApollo(
+ [
+ [workItemAwardEmojiQuery, awardEmojiQueryHandler],
+ [updateAwardEmojiMutation, awardEmojiMutationHandler],
+ ],
+ {},
+ {
+ typePolicies: {
+ WorkItemWidgetAwardEmoji: {
+ fields: {
+ // If we add any key args, the awardEmoji field becomes awardEmoji({"first":10}) and
+ // kills any possibility to handle it on the widget level without hardcoding a string.
+ awardEmoji: {
+ keyArgs: false,
+ },
+ },
},
},
},
- });
+ );
wrapper = shallowMount(WorkItemAwardEmoji, {
isLoggedIn: isLoggedIn(),
apolloProvider: mockApolloProvider,
propsData: {
- workItemId: workItem.id,
- workItemFullpath: workItem.project.fullPath,
- awardEmoji,
+ workItemId: 'gid://gitlab/WorkItem/1',
+ workItemFullpath: 'test-project-path',
workItemIid,
},
});
@@ -85,17 +118,23 @@ describe('WorkItemAwardEmoji component', () => {
const findAwardsList = () => wrapper.findComponent(AwardList);
- beforeEach(() => {
+ beforeEach(async () => {
isLoggedIn.mockReturnValue(true);
window.gon = {
current_user_id: 5,
current_user_fullname: 'Dave Smith',
};
- createComponent();
+ await createComponent();
});
- it('renders the award-list component with default props', () => {
+ it('renders the award-list component with default props', async () => {
+ createComponent({
+ awardEmojiQueryHandler: awardEmojiQueryEmptyHandler,
+ });
+
+ await waitForPromises();
+
expect(findAwardsList().exists()).toBe(true);
expect(findAwardsList().props()).toEqual({
boundary: '',
@@ -108,8 +147,6 @@ describe('WorkItemAwardEmoji component', () => {
});
it('renders awards-list component with awards present', () => {
- createComponent({ awardEmoji: mockAwardsWidget });
-
expect(findAwardsList().props('awards')).toEqual([
{
name: EMOJI_THUMBSUP,
@@ -128,13 +165,32 @@ describe('WorkItemAwardEmoji component', () => {
]);
});
- it('renders awards list given by multiple users', () => {
+ it('emits error when there is an error while fetching award emojis', async () => {
createComponent({
+ awardEmojiQueryHandler: awardEmojiQueryFailureHandler,
+ });
+
+ await waitForPromises();
+
+ expect(wrapper.emitted('error')).toEqual([[I18N_WORK_ITEM_FETCH_AWARD_EMOJI_ERROR]]);
+ });
+
+ it('renders awards list given by multiple users', async () => {
+ const mockWorkItemAwardEmojiDifferentUser = workItemByIidResponseFactory({
awardEmoji: {
...mockAwardsWidget,
- nodes: [mockAwardEmojiThumbsUp, mockAwardEmojiDifferentUserThumbsUp],
+ nodes: [mockAwardEmojiThumbsUp, mockAwardEmojiDifferentUser],
},
});
+ const awardEmojiWithDifferentUsersQueryHandler = jest
+ .fn()
+ .mockResolvedValue(mockWorkItemAwardEmojiDifferentUser);
+
+ createComponent({
+ awardEmojiQueryHandler: awardEmojiWithDifferentUsersQueryHandler,
+ });
+
+ await waitForPromises();
expect(findAwardsList().props('awards')).toEqual([
{
@@ -155,21 +211,19 @@ describe('WorkItemAwardEmoji component', () => {
});
it.each`
- expectedAssertion | awardEmojiMutationHandler | mockAwardEmojiNodes | workItem
- ${'added'} | ${awardEmojiAddSuccessHandler} | ${[]} | ${workItemQueryRemoveAwardEmojiResponse.data.workspace.workItems.nodes[0]}
- ${'removed'} | ${awardEmojiRemoveSuccessHandler} | ${[mockAwardEmojiThumbsUp]} | ${workItemQueryAddAwardEmojiResponse.data.workspace.workItems.nodes[0]}
+ expectedAssertion | awardEmojiMutationHandler | awardEmojiQueryHandler
+ ${'added'} | ${awardEmojiAddSuccessHandler} | ${awardEmojiQueryEmptyHandler}
+ ${'removed'} | ${awardEmojiRemoveSuccessHandler} | ${awardEmojiQueryThumbsUpHandler}
`(
'calls mutation when an award emoji is $expectedAssertion',
- ({ awardEmojiMutationHandler, mockAwardEmojiNodes, workItem }) => {
+ async ({ awardEmojiMutationHandler, awardEmojiQueryHandler }) => {
createComponent({
- awardMutationHandler: awardEmojiMutationHandler,
- awardEmoji: {
- ...mockAwardsWidget,
- nodes: mockAwardEmojiNodes,
- },
- workItem,
+ awardEmojiMutationHandler,
+ awardEmojiQueryHandler,
});
+ await waitForPromises();
+
findAwardsList().vm.$emit('award', EMOJI_THUMBSUP);
expect(awardEmojiMutationHandler).toHaveBeenCalledWith({
@@ -183,21 +237,24 @@ describe('WorkItemAwardEmoji component', () => {
it('emits error when the update mutation fails', async () => {
createComponent({
- awardMutationHandler: awardEmojiUpdateFailureHandler,
+ awardEmojiMutationHandler: awardEmojiUpdateFailureHandler,
+ awardEmojiQueryHandler: awardEmojiQueryEmptyHandler,
});
+ await waitForPromises();
+
findAwardsList().vm.$emit('award', EMOJI_THUMBSUP);
await waitForPromises();
- expect(wrapper.emitted('error')).toEqual([[errorMessage]]);
+ expect(wrapper.emitted('error')).toEqual([[mutationErrorMessage]]);
});
describe('when user is not logged in', () => {
- beforeEach(() => {
+ beforeEach(async () => {
isLoggedIn.mockReturnValue(false);
- createComponent();
+ await createComponent();
});
it('renders the component with required props and canAwardEmoji false', () => {
@@ -213,15 +270,13 @@ describe('WorkItemAwardEmoji component', () => {
};
});
- it('calls mutation succesfully and adds the award emoji with proper user details', () => {
+ it('calls mutation succesfully and adds the award emoji with proper user details', async () => {
createComponent({
- awardMutationHandler: awardEmojiAddSuccessHandler,
- awardEmoji: {
- ...mockAwardsWidget,
- nodes: [mockAwardEmojiThumbsUp],
- },
+ awardEmojiMutationHandler: awardEmojiAddSuccessHandler,
});
+ await waitForPromises();
+
findAwardsList().vm.$emit('award', EMOJI_THUMBSUP);
expect(awardEmojiAddSuccessHandler).toHaveBeenCalledWith({
@@ -232,4 +287,62 @@ describe('WorkItemAwardEmoji component', () => {
});
});
});
+
+ describe('pagination', () => {
+ describe('when there is no next page', () => {
+ const awardEmojiQuerySingleItemHandler = jest.fn().mockResolvedValue(
+ workItemByIidResponseFactory({
+ awardEmoji: {
+ ...mockAwardsWidget,
+ nodes: [mockAwardEmojiThumbsUp],
+ },
+ }),
+ );
+
+ it('fetch more award emojis should not be called', async () => {
+ createComponent({ awardEmojiQueryHandler: awardEmojiQuerySingleItemHandler });
+ await waitForPromises();
+
+ expect(awardEmojiQuerySingleItemHandler).toHaveBeenCalledWith({
+ fullPath: 'test-project-path',
+ iid: '1',
+ pageSize: DEFAULT_PAGE_SIZE_EMOJIS,
+ after: undefined,
+ });
+ expect(awardEmojiQuerySingleItemHandler).toHaveBeenCalledTimes(1);
+ });
+ });
+
+ describe('when there is next page', () => {
+ const awardEmojisQueryMoreThanDefaultHandler = jest.fn().mockResolvedValueOnce(
+ workItemByIidResponseFactory({
+ awardEmoji: mockMoreThanDefaultAwardEmojisWidget,
+ }),
+ );
+
+ it('fetch more award emojis should be called', async () => {
+ createComponent({
+ awardEmojiQueryHandler: awardEmojisQueryMoreThanDefaultHandler,
+ });
+ await waitForPromises();
+
+ expect(awardEmojisQueryMoreThanDefaultHandler).toHaveBeenCalledWith({
+ fullPath: 'test-project-path',
+ iid: '1',
+ pageSize: DEFAULT_PAGE_SIZE_EMOJIS,
+ after: 'endCursor',
+ });
+
+ await nextTick();
+
+ expect(awardEmojisQueryMoreThanDefaultHandler).toHaveBeenCalledWith({
+ fullPath: 'test-project-path',
+ iid: '1',
+ pageSize: DEFAULT_PAGE_SIZE_EMOJIS,
+ after: mockMoreThanDefaultAwardEmojisWidget.pageInfo.endCursor,
+ });
+ expect(awardEmojisQueryMoreThanDefaultHandler).toHaveBeenCalledTimes(2);
+ });
+ });
+ });
});
diff --git a/spec/frontend/work_items/mock_data.js b/spec/frontend/work_items/mock_data.js
index b3e716a4d4a..f88e69a7ffe 100644
--- a/spec/frontend/work_items/mock_data.js
+++ b/spec/frontend/work_items/mock_data.js
@@ -68,6 +68,38 @@ export const mockAwardEmojiThumbsDown = {
export const mockAwardsWidget = {
nodes: [mockAwardEmojiThumbsUp, mockAwardEmojiThumbsDown],
+ pageInfo: {
+ hasNextPage: false,
+ hasPreviousPage: false,
+ startCursor: null,
+ endCursor: null,
+ __typename: 'PageInfo',
+ },
+ __typename: 'AwardEmojiConnection',
+};
+
+export const mockMoreThanDefaultAwardEmojisWidget = {
+ nodes: [
+ mockAwardEmojiThumbsUp,
+ mockAwardEmojiThumbsDown,
+ { ...mockAwardEmojiThumbsUp, name: 'one' },
+ { ...mockAwardEmojiThumbsUp, name: 'two' },
+ { ...mockAwardEmojiThumbsUp, name: 'three' },
+ { ...mockAwardEmojiThumbsUp, name: 'four' },
+ { ...mockAwardEmojiThumbsUp, name: 'five' },
+ { ...mockAwardEmojiThumbsUp, name: 'six' },
+ { ...mockAwardEmojiThumbsUp, name: 'seven' },
+ { ...mockAwardEmojiThumbsUp, name: 'eight' },
+ { ...mockAwardEmojiThumbsUp, name: 'nine' },
+ { ...mockAwardEmojiThumbsUp, name: 'ten' },
+ ],
+ pageInfo: {
+ hasNextPage: true,
+ hasPreviousPage: false,
+ startCursor: null,
+ endCursor: 'endCursor',
+ __typename: 'PageInfo',
+ },
__typename: 'AwardEmojiConnection',
};
diff --git a/spec/frontend/work_items/router_spec.js b/spec/frontend/work_items/router_spec.js
index 4e31ee30552..79ba31e7012 100644
--- a/spec/frontend/work_items/router_spec.js
+++ b/spec/frontend/work_items/router_spec.js
@@ -53,6 +53,7 @@ describe('Work items router', () => {
WorkItemIteration: true,
WorkItemHealthStatus: true,
WorkItemNotes: true,
+ WorkItemAwardEmoji: true,
},
});
};
diff --git a/spec/lib/gitlab/background_migration/backfill_uuid_conversion_column_in_vulnerability_occurrences_spec.rb b/spec/lib/gitlab/background_migration/backfill_uuid_conversion_column_in_vulnerability_occurrences_spec.rb
new file mode 100644
index 00000000000..699fa39c309
--- /dev/null
+++ b/spec/lib/gitlab/background_migration/backfill_uuid_conversion_column_in_vulnerability_occurrences_spec.rb
@@ -0,0 +1,133 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BackgroundMigration::BackfillUuidConversionColumnInVulnerabilityOccurrences, schema: 20230629095819, feature_category: :vulnerability_management do # rubocop:disable Layout/LineLength
+ let(:namespaces) { table(:namespaces) }
+ let(:projects) { table(:projects) }
+ let(:users) { table(:users) }
+ let(:members) { table(:members) }
+ let(:vulnerability_identifiers) { table(:vulnerability_identifiers) }
+ let(:vulnerability_scanners) { table(:vulnerability_scanners) }
+ let(:vulnerability_findings) { table(:vulnerability_occurrences) }
+ let!(:user) { create_user(email: "test1@example.com", username: "test1") }
+ let!(:namespace) { namespaces.create!(name: "test-1", path: "test-1", owner_id: user.id) }
+ let!(:project) do
+ projects.create!(
+ id: 9999, namespace_id: namespace.id,
+ project_namespace_id: namespace.id,
+ creator_id: user.id
+ )
+ end
+
+ let!(:membership) do
+ members.create!(access_level: 50, source_id: project.id, source_type: "Project", user_id: user.id, state: 0,
+ notification_level: 3, type: "ProjectMember", member_namespace_id: namespace.id)
+ end
+
+ let(:scanner) { create_scanner(project) }
+ let(:null_uuid) { '00000000-0000-0000-0000-000000000000' }
+
+ let(:migration_attrs) do
+ {
+ start_id: finding_with_no_converted_uuid_1.id,
+ end_id: finding_with_converted_uuid.id,
+ batch_table: :vulnerability_occurrences,
+ batch_column: :id,
+ sub_batch_size: 100,
+ pause_ms: 0,
+ connection: ApplicationRecord.connection
+ }
+ end
+
+ describe "#perform" do
+ subject(:background_migration) { described_class.new(**migration_attrs).perform }
+
+ before do
+ # We have to disable it in tests because it's triggered BEFORE INSERT OR UPDATE ON vulnerability_occurrences
+ # so it's hard to create or update the uuid_convert_string_to_uuid with null UUID value
+
+ # In reality the UPDATE query in the batched background migration could be SET id = id which would
+ # trigger UUID update trigger but we can't exactly do that and expect readable tests
+ ApplicationRecord.connection.execute("ALTER TABLE vulnerability_occurrences DISABLE TRIGGER trigger_1a857e8db6cd")
+ end
+
+ let(:finding_with_no_converted_uuid_1) do
+ create_finding(project, scanner, uuid_convert_string_to_uuid: null_uuid)
+ end
+
+ let(:finding_with_converted_uuid) do
+ uuid = SecureRandom.uuid
+ create_finding(project, scanner, uuid: uuid, uuid_convert_string_to_uuid: uuid)
+ end
+
+ after do
+ ApplicationRecord.connection.execute("ALTER TABLE vulnerability_occurrences ENABLE TRIGGER trigger_1a857e8db6cd")
+ end
+
+ it "backfills the uuid_convert_string_to_uuid column" do
+ expect { background_migration }.to change { finding_with_no_converted_uuid_1.reload.uuid_convert_string_to_uuid }
+ .from(null_uuid).to(finding_with_no_converted_uuid_1.uuid)
+ end
+
+ it "doesn't change the UUID for exisiting records" do
+ expect { background_migration }.not_to change { finding_with_converted_uuid.uuid_convert_string_to_uuid }
+ end
+ end
+
+ private
+
+ def create_scanner(project, overrides = {})
+ attrs = {
+ project_id: project.id,
+ external_id: "test_vulnerability_scanner",
+ name: "Test Vulnerabilities::Scanner"
+ }.merge(overrides)
+
+ vulnerability_scanners.create!(attrs)
+ end
+
+ def create_identifier(project, overrides = {})
+ attrs = {
+ project_id: project.id,
+ external_id: "CVE-2018-1234",
+ external_type: "CVE",
+ name: "CVE-2018-1234",
+ fingerprint: SecureRandom.hex(20)
+ }.merge(overrides)
+
+ vulnerability_identifiers.create!(attrs)
+ end
+
+ def create_finding(project, scanner, overrides = {})
+ attrs = {
+ project_id: project.id,
+ scanner_id: scanner.id,
+ severity: 5, # medium
+ confidence: 2, # unknown,
+ report_type: 99, # generic
+ primary_identifier_id: create_identifier(project).id,
+ project_fingerprint: SecureRandom.hex(20),
+ location_fingerprint: SecureRandom.hex(20),
+ uuid: SecureRandom.uuid,
+ name: "CVE-2018-1234",
+ raw_metadata: "{}",
+ metadata_version: "test:1.0"
+ }.merge(overrides)
+
+ vulnerability_findings.create!(attrs)
+ end
+
+ def create_user(overrides = {})
+ attrs = {
+ email: "test@example.com",
+ notification_email: "test@example.com",
+ name: "test",
+ username: "test",
+ state: "active",
+ projects_limit: 10
+ }.merge(overrides)
+
+ users.create!(attrs)
+ end
+end
diff --git a/spec/lib/gitlab/checks/changes_access_spec.rb b/spec/lib/gitlab/checks/changes_access_spec.rb
index 552afcdb180..854c04dd581 100644
--- a/spec/lib/gitlab/checks/changes_access_spec.rb
+++ b/spec/lib/gitlab/checks/changes_access_spec.rb
@@ -24,6 +24,14 @@ RSpec.describe Gitlab::Checks::ChangesAccess, feature_category: :source_code_man
subject.validate!
end
+
+ it 'calls file size check' do
+ expect_next_instance_of(Gitlab::Checks::GlobalFileSizeCheck) do |instance|
+ expect(instance).to receive(:validate!)
+ end
+
+ subject.validate!
+ end
end
context 'when time limit was reached' do
diff --git a/spec/lib/gitlab/checks/global_file_size_check_spec.rb b/spec/lib/gitlab/checks/global_file_size_check_spec.rb
new file mode 100644
index 00000000000..9ea0c73b1c7
--- /dev/null
+++ b/spec/lib/gitlab/checks/global_file_size_check_spec.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Checks::GlobalFileSizeCheck, feature_category: :source_code_management do
+ include_context 'changes access checks context'
+
+ describe '#validate!' do
+ context 'when global_file_size_check is disabled' do
+ before do
+ stub_feature_flags(global_file_size_check: false)
+ end
+
+ it 'does not log' do
+ expect(subject).not_to receive(:log_timed)
+ expect(Gitlab::AppJsonLogger).not_to receive(:info)
+ expect(Gitlab::Checks::FileSizeCheck::AllowExistingOversizedBlobs).not_to receive(:new)
+ subject.validate!
+ end
+ end
+
+ it 'checks for file sizes' do
+ expect_next_instance_of(Gitlab::Checks::FileSizeCheck::AllowExistingOversizedBlobs,
+ project: project,
+ changes: changes,
+ file_size_limit_megabytes: 100
+ ) do |check|
+ expect(check).to receive(:find).and_call_original
+ end
+ expect(subject.logger).to receive(:log_timed).with('Checking for blobs over the file size limit')
+ .and_call_original
+ expect(Gitlab::AppJsonLogger).to receive(:info).with('Checking for blobs over the file size limit')
+ subject.validate!
+ end
+ end
+end
diff --git a/spec/migrations/20230629095819_queue_backfill_uuid_conversion_column_in_vulnerability_occurrences_spec.rb b/spec/migrations/20230629095819_queue_backfill_uuid_conversion_column_in_vulnerability_occurrences_spec.rb
new file mode 100644
index 00000000000..eb9a131008a
--- /dev/null
+++ b/spec/migrations/20230629095819_queue_backfill_uuid_conversion_column_in_vulnerability_occurrences_spec.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe QueueBackfillUuidConversionColumnInVulnerabilityOccurrences, feature_category: :vulnerability_management do
+ let!(:batched_migration) { described_class::MIGRATION }
+
+ it 'schedules a new batched migration' do
+ reversible_migration do |migration|
+ migration.before -> {
+ expect(batched_migration).not_to have_scheduled_batched_migration
+ }
+
+ migration.after -> {
+ expect(batched_migration).to have_scheduled_batched_migration(
+ table_name: :vulnerability_occurrences,
+ column_name: :id,
+ interval: described_class::DELAY_INTERVAL,
+ batch_size: described_class::BATCH_SIZE,
+ sub_batch_size: described_class::SUB_BATCH_SIZE
+ )
+ }
+ end
+ end
+end