summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-04-01 12:08:56 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2021-04-01 12:08:56 +0000
commit50d66f5ece57dcfbe074d97703691a8d3c38f4ac (patch)
treec96aa5ffd1cb73c18e53356680cb9792d24c257b
parentcfec4ed6fe77e4150b1ea83b87f407aa0cca944c (diff)
downloadgitlab-ce-50d66f5ece57dcfbe074d97703691a8d3c38f4ac.tar.gz
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.rubocop_manual_todo.yml4
-rw-r--r--GITALY_SERVER_VERSION2
-rw-r--r--app/assets/javascripts/boards/components/board_card_loading_skeleton.vue26
-rw-r--r--app/assets/javascripts/boards/components/board_content.vue2
-rw-r--r--app/assets/javascripts/boards/components/board_new_issue.vue2
-rw-r--r--app/assets/javascripts/boards/components/board_new_issue_deprecated.vue2
-rw-r--r--app/assets/javascripts/boards/graphql/issue.fragment.graphql4
-rw-r--r--app/assets/javascripts/members/components/avatars/user_avatar.vue3
-rw-r--r--app/assets/javascripts/members/components/filter_sort/members_filtered_search_bar.vue3
-rw-r--r--app/assets/javascripts/members/components/table/members_table.vue3
-rw-r--r--app/assets/javascripts/members/components/table/members_table_cell.vue3
-rw-r--r--app/assets/javascripts/members/index.js10
-rw-r--r--app/assets/javascripts/members/store/state.js6
-rw-r--r--app/assets/javascripts/pages/projects/packages/infrastructure_registry/index/index.js3
-rw-r--r--app/assets/stylesheets/framework/common.scss1
-rw-r--r--app/assets/stylesheets/page_bundles/boards.scss10
-rw-r--r--app/assets/stylesheets/pages/commits.scss8
-rw-r--r--app/assets/stylesheets/pages/editor.scss2
-rw-r--r--app/assets/stylesheets/pages/groups.scss11
-rw-r--r--app/assets/stylesheets/pages/help.scss7
-rw-r--r--app/assets/stylesheets/pages/issuable.scss2
-rw-r--r--app/assets/stylesheets/pages/projects.scss6
-rw-r--r--app/controllers/projects/packages/infrastructure_registry_controller.rb9
-rw-r--r--app/controllers/registrations/experience_levels_controller.rb2
-rw-r--r--app/finders/git_refs_finder.rb12
-rw-r--r--app/helpers/projects_helper.rb4
-rw-r--r--app/models/ci/processable.rb8
-rw-r--r--app/presenters/ci/build_runner_presenter.rb12
-rw-r--r--app/serializers/merge_request_poll_cached_widget_entity.rb8
-rw-r--r--app/serializers/merge_request_poll_widget_entity.rb6
-rw-r--r--app/views/admin/application_settings/_realtime.html.haml11
-rw-r--r--app/views/admin/application_settings/_repository_check.html.haml33
-rw-r--r--app/views/layouts/nav/sidebar/_project_packages_link.html.haml8
-rw-r--r--app/views/projects/packages/infrastructure_registry/index.html.haml10
-rw-r--r--changelogs/unreleased/325630-cablett-filter-epics-by-reaction-be.yml5
-rw-r--r--changelogs/unreleased/9152-check-sso-status-on-git-activity-and-direct-user-to-sso.yml5
-rw-r--r--changelogs/unreleased/Externalise-strings-in-_realtime-html-haml.yml5
-rw-r--r--changelogs/unreleased/Externalise-strings-in-_repository_check-html-haml.yml5
-rw-r--r--changelogs/unreleased/issue-220040-fix-rails-savebang-legacy-github-import-module.yml5
-rw-r--r--changelogs/unreleased/issue_322686-improve_award_emoji_filtering_query.yml5
-rw-r--r--changelogs/unreleased/ref-finder-performance-improvement.yml5
-rw-r--r--changelogs/unreleased/rename-create-issue.yml5
-rw-r--r--config/feature_flags/development/infrastructure_registry_page.yml8
-rw-r--r--config/feature_flags/development/merge_request_cached_merge_pipeline_serializer.yml8
-rw-r--r--config/feature_flags/development/preload_associations_jobs_request_api_endpoint.yml8
-rw-r--r--config/routes/project.rb2
-rw-r--r--db/migrate/20210312174321_add_enforced_git_check_to_saml_provider.rb13
-rw-r--r--db/migrate/20210329192716_add_composite_index_to_award_emoji.rb18
-rw-r--r--db/migrate/20210331180118_remove_deprecated_index_from_award_emoji.rb19
-rw-r--r--db/schema_migrations/202103121743211
-rw-r--r--db/schema_migrations/202103291927161
-rw-r--r--db/schema_migrations/202103311801181
-rw-r--r--db/structure.sql7
-rw-r--r--doc/administration/nfs.md20
-rw-r--r--doc/development/api_graphql_styleguide.md26
-rw-r--r--doc/development/code_review.md4
-rw-r--r--doc/development/documentation/structure.md2
-rw-r--r--doc/development/snowplow.md2
-rw-r--r--doc/operations/incident_management/incidents.md2
-rw-r--r--doc/user/discussions/index.md2
-rw-r--r--doc/user/group/saml_sso/index.md11
-rw-r--r--doc/user/project/issues/confidential_issues.md2
-rw-r--r--doc/user/project/pages/introduction.md2
-rw-r--r--lib/gitlab/git_access.rb5
-rw-r--r--lib/gitlab/tracking.rb4
-rw-r--r--lib/gitlab/tracking/standard_context.rb11
-rw-r--r--locale/gitlab.pot98
-rwxr-xr-xscripts/gitaly-test-build2
-rwxr-xr-xscripts/gitaly-test-spawn1
-rw-r--r--scripts/gitaly_test.rb20
-rw-r--r--spec/features/boards/new_issue_spec.rb6
-rw-r--r--spec/features/boards/sidebar_spec.rb40
-rw-r--r--spec/features/boards/sidebar_subscription_spec.rb54
-rw-r--r--spec/features/boards/sidebar_time_tracking_spec.rb52
-rw-r--r--spec/features/groups/board_spec.rb2
-rw-r--r--spec/features/groups/navbar_spec.rb4
-rw-r--r--spec/features/projects/navbar_spec.rb4
-rw-r--r--spec/features/users/terms_spec.rb2
-rw-r--r--spec/frontend/boards/board_new_issue_deprecated_spec.js16
-rw-r--r--spec/frontend/boards/components/board_new_issue_spec.js6
-rw-r--r--spec/frontend/members/components/avatars/user_avatar_spec.js16
-rw-r--r--spec/frontend/members/components/filter_sort/members_filtered_search_bar_spec.js27
-rw-r--r--spec/frontend/members/components/filter_sort/sort_dropdown_spec.js4
-rw-r--r--spec/frontend/members/components/table/members_table_cell_spec.js12
-rw-r--r--spec/frontend/members/components/table/members_table_spec.js11
-rw-r--r--spec/frontend/members/index_spec.js27
-rw-r--r--spec/lib/gitlab/error_tracking/processor/context_payload_processor_spec.rb4
-rw-r--r--spec/lib/gitlab/legacy_github_import/importer_spec.rb2
-rw-r--r--spec/lib/gitlab/legacy_github_import/issue_formatter_spec.rb2
-rw-r--r--spec/lib/gitlab/legacy_github_import/milestone_formatter_spec.rb2
-rw-r--r--spec/lib/gitlab/legacy_github_import/pull_request_formatter_spec.rb2
-rw-r--r--spec/lib/gitlab/tracking/standard_context_spec.rb12
-rw-r--r--spec/lib/gitlab/tracking_spec.rb5
-rw-r--r--spec/requests/api/ci/runner/jobs_request_post_spec.rb30
-rw-r--r--spec/serializers/merge_request_poll_cached_widget_entity_spec.rb45
-rw-r--r--spec/serializers/merge_request_poll_widget_entity_spec.rb29
-rw-r--r--spec/support/helpers/navbar_structure_helper.rb12
-rw-r--r--spec/support/matchers/exceed_query_limit.rb5
-rw-r--r--spec/support/shared_examples/features/sidebar_shared_examples.rb165
-rw-r--r--spec/support_specs/matchers/exceed_query_limit_helpers_spec.rb10
100 files changed, 831 insertions, 360 deletions
diff --git a/.rubocop_manual_todo.yml b/.rubocop_manual_todo.yml
index 5a1e5dc316a..2ca2a1d28ce 100644
--- a/.rubocop_manual_todo.yml
+++ b/.rubocop_manual_todo.yml
@@ -278,10 +278,6 @@ Rails/SaveBang:
- 'spec/lib/gitlab/import_export/uploads_manager_spec.rb'
- 'spec/lib/gitlab/import_export/uploads_saver_spec.rb'
- 'spec/lib/gitlab/import_export/wiki_restorer_spec.rb'
- - 'spec/lib/gitlab/legacy_github_import/importer_spec.rb'
- - 'spec/lib/gitlab/legacy_github_import/issue_formatter_spec.rb'
- - 'spec/lib/gitlab/legacy_github_import/milestone_formatter_spec.rb'
- - 'spec/lib/gitlab/legacy_github_import/pull_request_formatter_spec.rb'
- 'spec/lib/gitlab/lets_encrypt/client_spec.rb'
- 'spec/lib/gitlab/markdown_cache/active_record/extension_spec.rb'
- 'spec/lib/gitlab/markdown_cache/redis/store_spec.rb'
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION
index a8a3d86d5a3..0020837c7c6 100644
--- a/GITALY_SERVER_VERSION
+++ b/GITALY_SERVER_VERSION
@@ -1 +1 @@
-c5786b09543e40acc6e05bd4d29f6d89106b8e8a
+46db2b9e1da386cc081455eef16f5fa1a9fefa51
diff --git a/app/assets/javascripts/boards/components/board_card_loading_skeleton.vue b/app/assets/javascripts/boards/components/board_card_loading_skeleton.vue
new file mode 100644
index 00000000000..15bff1226a6
--- /dev/null
+++ b/app/assets/javascripts/boards/components/board_card_loading_skeleton.vue
@@ -0,0 +1,26 @@
+<script>
+import { GlSkeletonLoader } from '@gitlab/ui';
+
+export default {
+ name: 'BoardCardLoading',
+ components: {
+ GlSkeletonLoader,
+ },
+};
+</script>
+
+<template>
+ <div
+ class="board-card-skeleton gl-mb-3 gl-bg-white gl-rounded-base gl-p-5 gl-border-1 gl-border-solid gl-border-gray-50"
+ >
+ <div class="board-card-skeleton-inner">
+ <gl-skeleton-loader :width="340" :height="100">
+ <rect width="340" height="16" rx="4" />
+ <rect y="30" width="118" height="16" rx="8" />
+ <rect x="122" y="30" width="130" height="16" rx="8" />
+ <rect y="62" width="38" height="16" rx="4" />
+ <circle cx="320" cy="68" r="16" />
+ </gl-skeleton-loader>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/boards/components/board_content.vue b/app/assets/javascripts/boards/components/board_content.vue
index b30d766f15a..8423457ac07 100644
--- a/app/assets/javascripts/boards/components/board_content.vue
+++ b/app/assets/javascripts/boards/components/board_content.vue
@@ -127,7 +127,7 @@ export default {
</component>
<epics-swimlanes
- v-else
+ v-else-if="boardListsToUse.length"
ref="swimlanes"
:lists="boardListsToUse"
:can-admin-list="canAdminList"
diff --git a/app/assets/javascripts/boards/components/board_new_issue.vue b/app/assets/javascripts/boards/components/board_new_issue.vue
index 944eb25bf7e..144cae15ab3 100644
--- a/app/assets/javascripts/boards/components/board_new_issue.vue
+++ b/app/assets/javascripts/boards/components/board_new_issue.vue
@@ -10,7 +10,7 @@ import ProjectSelect from './project_select.vue';
export default {
name: 'BoardNewIssue',
i18n: {
- submit: __('Submit issue'),
+ submit: __('Create issue'),
cancel: __('Cancel'),
},
components: {
diff --git a/app/assets/javascripts/boards/components/board_new_issue_deprecated.vue b/app/assets/javascripts/boards/components/board_new_issue_deprecated.vue
index 16f23dfff0e..1218941065f 100644
--- a/app/assets/javascripts/boards/components/board_new_issue_deprecated.vue
+++ b/app/assets/javascripts/boards/components/board_new_issue_deprecated.vue
@@ -121,7 +121,7 @@ export default {
variant="success"
category="primary"
type="submit"
- >{{ __('Submit issue') }}</gl-button
+ >{{ __('Create issue') }}</gl-button
>
<gl-button
ref="cancelButton"
diff --git a/app/assets/javascripts/boards/graphql/issue.fragment.graphql b/app/assets/javascripts/boards/graphql/issue.fragment.graphql
index 1395bef39ed..7ecf9261214 100644
--- a/app/assets/javascripts/boards/graphql/issue.fragment.graphql
+++ b/app/assets/javascripts/boards/graphql/issue.fragment.graphql
@@ -7,6 +7,10 @@ fragment IssueNode on Issue {
referencePath: reference(full: true)
dueDate
timeEstimate
+ totalTimeSpent
+ humanTimeEstimate
+ humanTotalTimeSpent
+ emailsDisabled
confidential
webUrl
subscribed
diff --git a/app/assets/javascripts/members/components/avatars/user_avatar.vue b/app/assets/javascripts/members/components/avatars/user_avatar.vue
index 658fb43cecb..9687eacb036 100644
--- a/app/assets/javascripts/members/components/avatars/user_avatar.vue
+++ b/app/assets/javascripts/members/components/avatars/user_avatar.vue
@@ -5,7 +5,6 @@ import {
GlBadge,
GlSafeHtmlDirective as SafeHtml,
} from '@gitlab/ui';
-import { mapState } from 'vuex';
import { generateBadges } from 'ee_else_ce/members/utils';
import { glEmojiTag } from '~/emoji';
import { __ } from '~/locale';
@@ -24,6 +23,7 @@ export default {
directives: {
SafeHtml,
},
+ inject: ['canManageMembers'],
props: {
member: {
type: Object,
@@ -35,7 +35,6 @@ export default {
},
},
computed: {
- ...mapState(['canManageMembers']),
user() {
return this.member.user;
},
diff --git a/app/assets/javascripts/members/components/filter_sort/members_filtered_search_bar.vue b/app/assets/javascripts/members/components/filter_sort/members_filtered_search_bar.vue
index 039ee9a0207..9e58c7022b8 100644
--- a/app/assets/javascripts/members/components/filter_sort/members_filtered_search_bar.vue
+++ b/app/assets/javascripts/members/components/filter_sort/members_filtered_search_bar.vue
@@ -37,13 +37,14 @@ export default {
],
},
],
+ inject: ['sourceId', 'canManageMembers'],
data() {
return {
initialFilterValue: [],
};
},
computed: {
- ...mapState(['sourceId', 'filteredSearchBar', 'canManageMembers']),
+ ...mapState(['filteredSearchBar']),
tokens() {
return this.$options.availableTokens.filter((token) => {
if (
diff --git a/app/assets/javascripts/members/components/table/members_table.vue b/app/assets/javascripts/members/components/table/members_table.vue
index 9a3edff19ff..5db29951d94 100644
--- a/app/assets/javascripts/members/components/table/members_table.vue
+++ b/app/assets/javascripts/members/components/table/members_table.vue
@@ -31,8 +31,9 @@ export default {
LdapOverrideConfirmationModal: () =>
import('ee_component/members/components/ldap/ldap_override_confirmation_modal.vue'),
},
+ inject: ['currentUserId'],
computed: {
- ...mapState(['members', 'tableFields', 'tableAttrs', 'currentUserId']),
+ ...mapState(['members', 'tableFields', 'tableAttrs']),
filteredFields() {
return FIELDS.filter(
(field) => this.tableFields.includes(field.key) && this.showField(field),
diff --git a/app/assets/javascripts/members/components/table/members_table_cell.vue b/app/assets/javascripts/members/components/table/members_table_cell.vue
index 1f537740f94..3436bcab2fc 100644
--- a/app/assets/javascripts/members/components/table/members_table_cell.vue
+++ b/app/assets/javascripts/members/components/table/members_table_cell.vue
@@ -1,5 +1,4 @@
<script>
-import { mapState } from 'vuex';
import { MEMBER_TYPES } from '../../constants';
import {
isGroup,
@@ -12,6 +11,7 @@ import {
export default {
name: 'MembersTableCell',
+ inject: ['currentUserId'],
props: {
member: {
type: Object,
@@ -19,7 +19,6 @@ export default {
},
},
computed: {
- ...mapState(['currentUserId']),
isGroup() {
return isGroup(this.member);
},
diff --git a/app/assets/javascripts/members/index.js b/app/assets/javascripts/members/index.js
index fe174d9beb6..2f3589bbf6a 100644
--- a/app/assets/javascripts/members/index.js
+++ b/app/assets/javascripts/members/index.js
@@ -22,10 +22,11 @@ export const initMembersApp = (
Vue.use(Vuex);
Vue.use(GlToast);
+ const { sourceId, canManageMembers, ...vuexStoreAttributes } = parseDataAttributes(el);
+
const store = new Vuex.Store(
membersStore({
- ...parseDataAttributes(el),
- currentUserId: gon.current_user_id || null,
+ ...vuexStoreAttributes,
tableFields,
tableAttrs,
tableSortableFields,
@@ -38,6 +39,11 @@ export const initMembersApp = (
el,
components: { App },
store,
+ provide: {
+ currentUserId: gon.current_user_id || null,
+ sourceId,
+ canManageMembers,
+ },
render: (createElement) => createElement('app'),
});
};
diff --git a/app/assets/javascripts/members/store/state.js b/app/assets/javascripts/members/store/state.js
index 23a7983adcc..4006b4b501d 100644
--- a/app/assets/javascripts/members/store/state.js
+++ b/app/assets/javascripts/members/store/state.js
@@ -1,8 +1,5 @@
export default ({
members,
- sourceId,
- currentUserId,
- canManageMembers,
tableFields,
tableAttrs,
tableSortableFields,
@@ -11,9 +8,6 @@ export default ({
filteredSearchBar,
}) => ({
members,
- sourceId,
- currentUserId,
- canManageMembers,
tableFields,
tableAttrs,
tableSortableFields,
diff --git a/app/assets/javascripts/pages/projects/packages/infrastructure_registry/index/index.js b/app/assets/javascripts/pages/projects/packages/infrastructure_registry/index/index.js
new file mode 100644
index 00000000000..c94782fdf1b
--- /dev/null
+++ b/app/assets/javascripts/pages/projects/packages/infrastructure_registry/index/index.js
@@ -0,0 +1,3 @@
+import initPackageList from '~/packages/list/packages_list_app_bundle';
+
+initPackageList();
diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss
index 54a2284a3ab..8dd0ffabb82 100644
--- a/app/assets/stylesheets/framework/common.scss
+++ b/app/assets/stylesheets/framework/common.scss
@@ -421,7 +421,6 @@ img.emoji {
.mw-460 { max-width: 460px; }
.mw-6em { max-width: 6em; }
.mw-70p { max-width: 70%; }
-.mw-90p { max-width: 90%; }
// By default flex items don't shrink below their minimum content size.
// To change this, these clases set a min-width or min-height
diff --git a/app/assets/stylesheets/page_bundles/boards.scss b/app/assets/stylesheets/page_bundles/boards.scss
index 4ec9e414749..568d71105fa 100644
--- a/app/assets/stylesheets/page_bundles/boards.scss
+++ b/app/assets/stylesheets/page_bundles/boards.scss
@@ -471,3 +471,13 @@
.board-header-collapsed-info-icon:hover {
color: var(--gray-900, $gray-900);
}
+
+.board-card-skeleton {
+ height: 110px;
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
+
+ .board-card-skeleton-inner {
+ width: 340px;
+ height: 100px;
+ }
+}
diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss
index 7111d3d4107..a114a1dc82d 100644
--- a/app/assets/stylesheets/pages/commits.scss
+++ b/app/assets/stylesheets/pages/commits.scss
@@ -1,4 +1,5 @@
-%commit-description-base {
+.commit-description,
+.commit-row-description {
padding: $gl-padding-8 0 $gl-padding-8 $gl-padding-8;
margin-top: $gl-padding-8;
border: 0;
@@ -10,10 +11,6 @@
color: $gl-text-color-secondary;
}
-.commit-description {
- @extend %commit-description-base;
-}
-
.commit-box {
border-top: 1px solid $border-color;
padding: $gl-padding 0;
@@ -249,7 +246,6 @@
}
.commit-row-description {
- @extend %commit-description-base;
display: none;
flex: 1;
}
diff --git a/app/assets/stylesheets/pages/editor.scss b/app/assets/stylesheets/pages/editor.scss
index ef737e11799..14cff5b038a 100644
--- a/app/assets/stylesheets/pages/editor.scss
+++ b/app/assets/stylesheets/pages/editor.scss
@@ -36,7 +36,7 @@
}
.file-title {
- @extend .monospace;
+ @include gl-font-monospace;
line-height: 35px;
padding-top: 7px;
padding-bottom: 7px;
diff --git a/app/assets/stylesheets/pages/groups.scss b/app/assets/stylesheets/pages/groups.scss
index d8d6b4ce416..2ec2da9241b 100644
--- a/app/assets/stylesheets/pages/groups.scss
+++ b/app/assets/stylesheets/pages/groups.scss
@@ -160,17 +160,6 @@
vertical-align: top;
}
-
- .notification-dropdown {
- .dropdown-menu {
- @extend .dropdown-menu-right;
- }
-
- .icon {
- fill: $gl-text-color-secondary;
- }
- }
-
.new-project-subgroup {
.dropdown-primary {
min-width: 115px;
diff --git a/app/assets/stylesheets/pages/help.scss b/app/assets/stylesheets/pages/help.scss
index 540060d60de..c05216ac6e6 100644
--- a/app/assets/stylesheets/pages/help.scss
+++ b/app/assets/stylesheets/pages/help.scss
@@ -26,13 +26,6 @@
text-align: right;
white-space: nowrap;
}
-
- .key {
- @extend .badge.badge-pill;
- background-color: $label-inverse-bg;
- font: 11px Consolas, 'Liberation Mono', Menlo, Courier, monospace;
- padding: 3px 5px;
- }
}
.documentation {
diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss
index ee3ecf46f60..0a36051948e 100644
--- a/app/assets/stylesheets/pages/issuable.scss
+++ b/app/assets/stylesheets/pages/issuable.scss
@@ -633,7 +633,7 @@
}
.btn-link:hover {
- @extend a:hover;
+ color: $blue-800;
text-decoration: none;
}
diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss
index bcb950a2b87..16f96ebadc9 100644
--- a/app/assets/stylesheets/pages/projects.scss
+++ b/app/assets/stylesheets/pages/projects.scss
@@ -136,10 +136,6 @@
}
}
- .notification-dropdown .dropdown-menu {
- @extend .dropdown-menu-right;
- }
-
.download-button {
@include media-breakpoint-down(md) {
margin-left: 0;
@@ -838,7 +834,7 @@ pre.light-well {
}
.form-control {
- @extend .monospace;
+ @include gl-font-monospace;
background-color: $white;
border-color: $border-color;
font-size: 14px;
diff --git a/app/controllers/projects/packages/infrastructure_registry_controller.rb b/app/controllers/projects/packages/infrastructure_registry_controller.rb
new file mode 100644
index 00000000000..22ae1d65013
--- /dev/null
+++ b/app/controllers/projects/packages/infrastructure_registry_controller.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+module Projects
+ module Packages
+ class InfrastructureRegistryController < Projects::ApplicationController
+ feature_category :infrastructure_as_code
+ end
+ end
+end
diff --git a/app/controllers/registrations/experience_levels_controller.rb b/app/controllers/registrations/experience_levels_controller.rb
index b6ed0366177..3a721823d89 100644
--- a/app/controllers/registrations/experience_levels_controller.rb
+++ b/app/controllers/registrations/experience_levels_controller.rb
@@ -6,7 +6,7 @@ module Registrations
before_action :ensure_namespace_path_param
- feature_category :navigation
+ feature_category :onboarding
def update
current_user.experience_level = params[:experience_level]
diff --git a/app/finders/git_refs_finder.rb b/app/finders/git_refs_finder.rb
index 2289b34e562..11af659d37c 100644
--- a/app/finders/git_refs_finder.rb
+++ b/app/finders/git_refs_finder.rb
@@ -33,15 +33,21 @@ class GitRefsFinder
end
def filter_refs_with_prefix(refs, prefix)
- refs.select { |ref| ref.name.upcase.starts_with?(prefix.upcase) }
+ prefix = prefix.downcase
+
+ refs.select { |ref| ref.name.downcase.starts_with?(prefix) }
end
def filter_refs_with_suffix(refs, suffix)
- refs.select { |ref| ref.name.upcase.ends_with?(suffix.upcase) }
+ suffix = suffix.downcase
+
+ refs.select { |ref| ref.name.downcase.ends_with?(suffix) }
end
def filter_refs_by_name(refs, term)
- refs.select { |ref| ref.name.upcase.include?(term.upcase) }
+ term = term.downcase
+
+ refs.select { |ref| ref.name.downcase.include?(term) }
end
def set_exact_match_as_first_result(matches, term)
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index b6b9ad806f7..70c094c7ec6 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -410,6 +410,10 @@ module ProjectsHelper
nav_tabs << :container_registry
end
+ if Feature.enabled?(:infrastructure_registry_page)
+ nav_tabs << :infrastructure_registry
+ end
+
# Pipelines feature is tied to presence of builds
if can?(current_user, :read_build, project)
nav_tabs << :pipelines
diff --git a/app/models/ci/processable.rb b/app/models/ci/processable.rb
index 0ad1ed2fce8..3b61840805a 100644
--- a/app/models/ci/processable.rb
+++ b/app/models/ci/processable.rb
@@ -165,7 +165,13 @@ module Ci
end
def all_dependencies
- dependencies.all
+ if Feature.enabled?(:preload_associations_jobs_request_api_endpoint, project, default_enabled: :yaml)
+ strong_memoize(:all_dependencies) do
+ dependencies.all
+ end
+ else
+ dependencies.all
+ end
end
private
diff --git a/app/presenters/ci/build_runner_presenter.rb b/app/presenters/ci/build_runner_presenter.rb
index 297dc503294..6978bc46475 100644
--- a/app/presenters/ci/build_runner_presenter.rb
+++ b/app/presenters/ci/build_runner_presenter.rb
@@ -55,6 +55,18 @@ module Ci
specs
end
+ # rubocop: disable CodeReuse/ActiveRecord
+ def all_dependencies
+ dependencies = super
+
+ if Feature.enabled?(:preload_associations_jobs_request_api_endpoint, project, default_enabled: :yaml)
+ ActiveRecord::Associations::Preloader.new.preload(dependencies, :job_artifacts_archive)
+ end
+
+ dependencies
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+
private
def create_archive(artifacts)
diff --git a/app/serializers/merge_request_poll_cached_widget_entity.rb b/app/serializers/merge_request_poll_cached_widget_entity.rb
index 4fb61c9273f..845d7a0c52a 100644
--- a/app/serializers/merge_request_poll_cached_widget_entity.rb
+++ b/app/serializers/merge_request_poll_cached_widget_entity.rb
@@ -50,6 +50,14 @@ class MergeRequestPollCachedWidgetEntity < IssuableEntity
MergeRequests::PipelineEntity.represent(merge_request.actual_head_pipeline, options)
end
+ expose :merge_pipeline, if: ->(mr, _) {
+ Feature.enabled?(:merge_request_cached_merge_pipeline_serializer, mr.project, default_enabled: :yaml) &&
+ mr.merged? &&
+ can?(request.current_user, :read_pipeline, mr.target_project)
+ } do |merge_request, options|
+ MergeRequests::PipelineEntity.represent(merge_request.merge_pipeline, options)
+ end
+
# Paths
#
expose :target_branch_commits_path do |merge_request|
diff --git a/app/serializers/merge_request_poll_widget_entity.rb b/app/serializers/merge_request_poll_widget_entity.rb
index e8d7cabc68e..fc064a3a3b1 100644
--- a/app/serializers/merge_request_poll_widget_entity.rb
+++ b/app/serializers/merge_request_poll_widget_entity.rb
@@ -19,7 +19,11 @@ class MergeRequestPollWidgetEntity < Grape::Entity
# User entities
expose :merge_user, using: UserEntity
- expose :merge_pipeline, if: ->(mr, _) { mr.merged? && can?(request.current_user, :read_pipeline, mr.target_project)} do |merge_request, options|
+ expose :merge_pipeline, if: ->(mr, _) {
+ Feature.disabled?(:merge_request_cached_merge_pipeline_serializer, mr.project, default_enabled: :yaml) &&
+ mr.merged? &&
+ can?(request.current_user, :read_pipeline, mr.target_project)
+ } do |merge_request, options|
MergeRequests::PipelineEntity.represent(merge_request.merge_pipeline, options)
end
diff --git a/app/views/admin/application_settings/_realtime.html.haml b/app/views/admin/application_settings/_realtime.html.haml
index bee120d2f78..545c27d2a7e 100644
--- a/app/views/admin/application_settings/_realtime.html.haml
+++ b/app/views/admin/application_settings/_realtime.html.haml
@@ -3,15 +3,10 @@
%fieldset
.form-group
- = f.label :polling_interval_multiplier, 'Polling interval multiplier', class: 'label-bold'
+ = f.label :polling_interval_multiplier, _('Polling interval multiplier'), class: 'label-bold'
= f.text_field :polling_interval_multiplier, class: 'form-control gl-form-input'
.form-text.text-muted
- Change this value to influence how frequently the GitLab UI polls for updates.
- If you set the value to 2 all polling intervals are multiplied
- by 2, which means that polling happens half as frequently.
- The multiplier can also have a decimal value.
- The default value (1) is a reasonable choice for the majority of GitLab
- installations. Set to 0 to completely disable polling.
+ = _("Change this value to influence how frequently the GitLab UI polls for updates. If you set the value to 2 all polling intervals are multiplied by 2, which means that polling happens half as frequently. The multiplier can also have a decimal value. The default value (1) is a reasonable choice for the majority of GitLab installations. Set to 0 to completely disable polling.")
= link_to sprite_icon('question-o'), help_page_path('administration/polling')
- = f.submit 'Save changes', class: "gl-button btn btn-confirm"
+ = f.submit _('Save changes'), class: "gl-button btn btn-confirm"
diff --git a/app/views/admin/application_settings/_repository_check.html.haml b/app/views/admin/application_settings/_repository_check.html.haml
index ee0281b6e33..edf6853a1aa 100644
--- a/app/views/admin/application_settings/_repository_check.html.haml
+++ b/app/views/admin/application_settings/_repository_check.html.haml
@@ -3,56 +3,51 @@
%fieldset
.sub-section
- %h4 Repository checks
+ %h4= _("Repository checks")
.form-group
.form-check
= f.check_box :repository_checks_enabled, class: 'form-check-input'
= f.label :repository_checks_enabled, class: 'form-check-label' do
- Enable Repository Checks
+ = _("Enable Repository Checks")
.form-text.text-muted
- GitLab will periodically run
- %a{ href: 'https://git-scm.com/docs/git-fsck', target: 'blank' } 'git fsck'
- in all project and wiki repositories to look for silent disk corruption issues.
+ - link_to_git_fsck = link_to('git fsck', 'https://git-scm.com/docs/git-fsck', target: '_blank')
+ = _("GitLab will periodically run %{link_to_git_fsck} in all project and wiki repositories to look for silent disk corruption issues.").html_safe % { link_to_git_fsck: link_to_git_fsck }
.form-group
.form-text.text-muted
- If you got a lot of false alarms from repository checks you can choose to clear all repository check information from the database.
+ = _("If you got a lot of false alarms from repository checks you can choose to clear all repository check information from the database.")
- clear_repository_checks_link = _('Clear all repository checks')
- clear_repository_checks_message = _('This will clear repository check states for ALL projects in the database. This cannot be undone. Are you sure?')
= link_to clear_repository_checks_link, clear_repository_check_states_admin_application_settings_path, data: { confirm: clear_repository_checks_message }, method: :put, class: "gl-button btn btn-sm btn-danger"
.sub-section
- %h4 Housekeeping
+ %h4= _("Housekeeping")
.form-group
.form-check
= f.check_box :housekeeping_enabled, class: 'form-check-input'
= f.label :housekeeping_enabled, class: 'form-check-label' do
- Enable automatic repository housekeeping (git repack, git gc)
+ = _("Enable automatic repository housekeeping (git repack, git gc)")
.form-text.text-muted
- If you keep automatic housekeeping disabled for a long time Git
- repository access on your GitLab server will become slower and your
- repositories will use more disk space. We recommend to always leave
- this enabled.
+ = _("If you keep automatic housekeeping disabled for a long time Git repository access on your GitLab server will become slower and your repositories will use more disk space. We recommend to always leave this enabled.")
.form-check
= f.check_box :housekeeping_bitmaps_enabled, class: 'form-check-input'
= f.label :housekeeping_bitmaps_enabled, class: 'form-check-label' do
- Enable Git pack file bitmap creation
+ = _("Enable Git pack file bitmap creation")
.form-text.text-muted
- Creating pack file bitmaps makes housekeeping take a little longer but
- bitmaps should accelerate 'git clone' performance.
+ = _("Creating pack file bitmaps makes housekeeping take a little longer but bitmaps should accelerate 'git clone' performance.")
.form-group
= f.label :housekeeping_incremental_repack_period, 'Incremental repack period', class: 'label-bold'
= f.number_field :housekeeping_incremental_repack_period, class: 'form-control gl-form-input'
.form-text.text-muted
- Number of Git pushes after which an incremental 'git repack' is run.
+ = _("Number of Git pushes after which an incremental 'git repack' is run.")
.form-group
= f.label :housekeeping_full_repack_period, 'Full repack period', class: 'label-bold'
= f.number_field :housekeeping_full_repack_period, class: 'form-control gl-form-input'
.form-text.text-muted
- Number of Git pushes after which a full 'git repack' is run.
+ = _("Number of Git pushes after which a full 'git repack' is run.")
.form-group
- = f.label :housekeeping_gc_period, 'Git GC period', class: 'label-bold'
+ = f.label :housekeeping_gc_period, _('Git GC period'), class: 'label-bold'
= f.number_field :housekeeping_gc_period, class: 'form-control gl-form-input'
.form-text.text-muted
- Number of Git pushes after which 'git gc' is run.
+ = _("Number of Git pushes after which 'git gc' is run.")
= f.submit _('Save changes'), class: "gl-button btn btn-confirm"
diff --git a/app/views/layouts/nav/sidebar/_project_packages_link.html.haml b/app/views/layouts/nav/sidebar/_project_packages_link.html.haml
index e9989abe5a0..b28468a7969 100644
--- a/app/views/layouts/nav/sidebar/_project_packages_link.html.haml
+++ b/app/views/layouts/nav/sidebar/_project_packages_link.html.haml
@@ -1,14 +1,14 @@
- packages_link = project_nav_tab?(:packages) ? project_packages_path(@project) : project_container_registry_index_path(@project)
- if (project_nav_tab?(:packages) || project_nav_tab?(:container_registry))
- = nav_link controller: [:packages, :repositories] do
+ = nav_link controller: [:packages, :repositories, :infrastructure_registry] do
= link_to packages_link, data: { qa_selector: 'packages_link' } do
.nav-icon-container
= sprite_icon('package')
%span.nav-item-name
= _('Packages & Registries')
%ul.sidebar-sub-level-items
- = nav_link(controller: [:packages, :repositories], html_options: { class: "fly-out-top-item" } ) do
+ = nav_link(controller: [:packages, :repositories, :infrastructure_registry], html_options: { class: "fly-out-top-item" } ) do
= link_to packages_link do
%strong.fly-out-top-item-name
= _('Packages & Registries')
@@ -21,3 +21,7 @@
= nav_link controller: :repositories do
= link_to project_container_registry_index_path(@project), class: 'shortcuts-container-registry', title: _('Container Registry') do
%span= _('Container Registry')
+ - if project_nav_tab? :infrastructure_registry
+ = nav_link controller: :infrastructure_registry do
+ = link_to project_infrastructure_registry_index_path(@project), title: _('Infrastructure Registry') do
+ %span= _('Infrastructure Registry')
diff --git a/app/views/projects/packages/infrastructure_registry/index.html.haml b/app/views/projects/packages/infrastructure_registry/index.html.haml
new file mode 100644
index 00000000000..e8be9051275
--- /dev/null
+++ b/app/views/projects/packages/infrastructure_registry/index.html.haml
@@ -0,0 +1,10 @@
+- page_title _("Infrastructure Registry")
+- @content_class = "limit-container-width" unless fluid_layout
+
+.row
+ .col-12
+ #js-vue-packages-list{ data: { resource_id: @project.id,
+ page_type: 'project',
+ empty_list_help_url: help_page_path('user/packages/package_registry/index'),
+ empty_list_illustration: image_path('illustrations/no-packages.svg'),
+ package_help_url: help_page_path('user/packages/index') } }
diff --git a/changelogs/unreleased/325630-cablett-filter-epics-by-reaction-be.yml b/changelogs/unreleased/325630-cablett-filter-epics-by-reaction-be.yml
new file mode 100644
index 00000000000..301a0d67b10
--- /dev/null
+++ b/changelogs/unreleased/325630-cablett-filter-epics-by-reaction-be.yml
@@ -0,0 +1,5 @@
+---
+title: Allow user to filter epics by their reaction emoji via GraphQL
+merge_request: 58211
+author:
+type: added
diff --git a/changelogs/unreleased/9152-check-sso-status-on-git-activity-and-direct-user-to-sso.yml b/changelogs/unreleased/9152-check-sso-status-on-git-activity-and-direct-user-to-sso.yml
new file mode 100644
index 00000000000..2b681363bfe
--- /dev/null
+++ b/changelogs/unreleased/9152-check-sso-status-on-git-activity-and-direct-user-to-sso.yml
@@ -0,0 +1,5 @@
+---
+title: Group SAML - Check SSO status on Git activity
+merge_request: 56867
+author:
+type: added
diff --git a/changelogs/unreleased/Externalise-strings-in-_realtime-html-haml.yml b/changelogs/unreleased/Externalise-strings-in-_realtime-html-haml.yml
new file mode 100644
index 00000000000..9cf3ee7d762
--- /dev/null
+++ b/changelogs/unreleased/Externalise-strings-in-_realtime-html-haml.yml
@@ -0,0 +1,5 @@
+---
+title: Externalise strings in /application_settings/_realtime.html.haml
+merge_request: 58039
+author: nuwe1
+type: other
diff --git a/changelogs/unreleased/Externalise-strings-in-_repository_check-html-haml.yml b/changelogs/unreleased/Externalise-strings-in-_repository_check-html-haml.yml
new file mode 100644
index 00000000000..9d481093680
--- /dev/null
+++ b/changelogs/unreleased/Externalise-strings-in-_repository_check-html-haml.yml
@@ -0,0 +1,5 @@
+---
+title: Externalise strings in /application_settings/_repository_check.html.haml
+merge_request: 58058
+author: nuwe1
+type: other
diff --git a/changelogs/unreleased/issue-220040-fix-rails-savebang-legacy-github-import-module.yml b/changelogs/unreleased/issue-220040-fix-rails-savebang-legacy-github-import-module.yml
new file mode 100644
index 00000000000..c9dba61ef6c
--- /dev/null
+++ b/changelogs/unreleased/issue-220040-fix-rails-savebang-legacy-github-import-module.yml
@@ -0,0 +1,5 @@
+---
+title: Fix Rails/SaveBang Rubocop offenses for legacy github import
+merge_request: 58054
+author: Huzaifa Iftikhar @huzaifaiftikhar
+type: fixed
diff --git a/changelogs/unreleased/issue_322686-improve_award_emoji_filtering_query.yml b/changelogs/unreleased/issue_322686-improve_award_emoji_filtering_query.yml
new file mode 100644
index 00000000000..a7115072bf3
--- /dev/null
+++ b/changelogs/unreleased/issue_322686-improve_award_emoji_filtering_query.yml
@@ -0,0 +1,5 @@
+---
+title: Add composite index to support epic filtering by award emoji
+merge_request: 57759
+author:
+type: performance
diff --git a/changelogs/unreleased/ref-finder-performance-improvement.yml b/changelogs/unreleased/ref-finder-performance-improvement.yml
new file mode 100644
index 00000000000..f1e1888e58b
--- /dev/null
+++ b/changelogs/unreleased/ref-finder-performance-improvement.yml
@@ -0,0 +1,5 @@
+---
+title: Minor performance improvement for ref finder
+merge_request: 58099
+author:
+type: performance
diff --git a/changelogs/unreleased/rename-create-issue.yml b/changelogs/unreleased/rename-create-issue.yml
new file mode 100644
index 00000000000..468ee2de8ae
--- /dev/null
+++ b/changelogs/unreleased/rename-create-issue.yml
@@ -0,0 +1,5 @@
+---
+title: Rename Submit issue to Create issue in boards and docs
+merge_request: 58243
+author: Yogi (@yo)
+type: changed
diff --git a/config/feature_flags/development/infrastructure_registry_page.yml b/config/feature_flags/development/infrastructure_registry_page.yml
new file mode 100644
index 00000000000..fcb34f9d05b
--- /dev/null
+++ b/config/feature_flags/development/infrastructure_registry_page.yml
@@ -0,0 +1,8 @@
+---
+name: infrastructure_registry_page
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/57338
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/326460
+milestone: '13.11'
+type: development
+group: group::package
+default_enabled: false
diff --git a/config/feature_flags/development/merge_request_cached_merge_pipeline_serializer.yml b/config/feature_flags/development/merge_request_cached_merge_pipeline_serializer.yml
new file mode 100644
index 00000000000..506e59f001b
--- /dev/null
+++ b/config/feature_flags/development/merge_request_cached_merge_pipeline_serializer.yml
@@ -0,0 +1,8 @@
+---
+name: merge_request_cached_merge_pipeline_serializer
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/57827
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/326317
+milestone: '13.11'
+type: development
+group: group::source code
+default_enabled: false
diff --git a/config/feature_flags/development/preload_associations_jobs_request_api_endpoint.yml b/config/feature_flags/development/preload_associations_jobs_request_api_endpoint.yml
new file mode 100644
index 00000000000..92f63808bd8
--- /dev/null
+++ b/config/feature_flags/development/preload_associations_jobs_request_api_endpoint.yml
@@ -0,0 +1,8 @@
+---
+name: preload_associations_jobs_request_api_endpoint
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/57694
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/326477
+milestone: "13.11"
+type: development
+group: group::continuous integration
+default_enabled: true
diff --git a/config/routes/project.rb b/config/routes/project.rb
index 363d23590bf..09b212bc1a2 100644
--- a/config/routes/project.rb
+++ b/config/routes/project.rb
@@ -50,6 +50,8 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
end
end
+ resources :infrastructure_registry, only: [:index], module: :packages
+
resources :jobs, only: [:index, :show], constraints: { id: /\d+/ } do
collection do
resources :artifacts, only: [] do
diff --git a/db/migrate/20210312174321_add_enforced_git_check_to_saml_provider.rb b/db/migrate/20210312174321_add_enforced_git_check_to_saml_provider.rb
new file mode 100644
index 00000000000..89553a53084
--- /dev/null
+++ b/db/migrate/20210312174321_add_enforced_git_check_to_saml_provider.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+class AddEnforcedGitCheckToSamlProvider < ActiveRecord::Migration[6.0]
+ DOWNTIME = false
+
+ def up
+ add_column :saml_providers, :git_check_enforced, :boolean, default: false, null: false
+ end
+
+ def down
+ remove_column :saml_providers, :git_check_enforced
+ end
+end
diff --git a/db/migrate/20210329192716_add_composite_index_to_award_emoji.rb b/db/migrate/20210329192716_add_composite_index_to_award_emoji.rb
new file mode 100644
index 00000000000..ce37afdbc29
--- /dev/null
+++ b/db/migrate/20210329192716_add_composite_index_to_award_emoji.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+class AddCompositeIndexToAwardEmoji < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+ INDEX_NAME = 'idx_award_emoji_on_user_emoji_name_awardable_type_awardable_id'
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :award_emoji, %i[user_id name awardable_type awardable_id], name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name :award_emoji, INDEX_NAME
+ end
+end
diff --git a/db/migrate/20210331180118_remove_deprecated_index_from_award_emoji.rb b/db/migrate/20210331180118_remove_deprecated_index_from_award_emoji.rb
new file mode 100644
index 00000000000..b8787eb171c
--- /dev/null
+++ b/db/migrate/20210331180118_remove_deprecated_index_from_award_emoji.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+class RemoveDeprecatedIndexFromAwardEmoji < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+ INDEX_NAME = 'index_award_emoji_on_user_id_and_name'
+
+ disable_ddl_transaction!
+
+ def up
+ # Index deprecated in favor of idx_award_emoji_on_user_emoji_name_awardable_type_awardable_id
+ remove_concurrent_index_by_name(:award_emoji, INDEX_NAME)
+ end
+
+ def down
+ add_concurrent_index(:award_emoji, [:user_id, :name], name: INDEX_NAME)
+ end
+end
diff --git a/db/schema_migrations/20210312174321 b/db/schema_migrations/20210312174321
new file mode 100644
index 00000000000..5126ab2675d
--- /dev/null
+++ b/db/schema_migrations/20210312174321
@@ -0,0 +1 @@
+4fa88193ae328f04465980210d9a43ce8cad978c157bda5e8ae9951538209268 \ No newline at end of file
diff --git a/db/schema_migrations/20210329192716 b/db/schema_migrations/20210329192716
new file mode 100644
index 00000000000..8767c215335
--- /dev/null
+++ b/db/schema_migrations/20210329192716
@@ -0,0 +1 @@
+d0f5341d76183882b68583bc012154566e99050c24a90c9b895d6863ad8f3273 \ No newline at end of file
diff --git a/db/schema_migrations/20210331180118 b/db/schema_migrations/20210331180118
new file mode 100644
index 00000000000..45e62e7154d
--- /dev/null
+++ b/db/schema_migrations/20210331180118
@@ -0,0 +1 @@
+d8a17ce963801559292265dd0a997d8dbc69d2fa8b8840622490f878bf1eaa6a \ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index c1a2652ff12..0b7c723f1f5 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -17323,7 +17323,8 @@ CREATE TABLE saml_providers (
enforced_sso boolean DEFAULT false NOT NULL,
enforced_group_managed_accounts boolean DEFAULT false NOT NULL,
prohibited_outer_forks boolean DEFAULT true NOT NULL,
- default_membership_role smallint DEFAULT 10 NOT NULL
+ default_membership_role smallint DEFAULT 10 NOT NULL,
+ git_check_enforced boolean DEFAULT false NOT NULL
);
CREATE SEQUENCE saml_providers_id_seq
@@ -21762,6 +21763,8 @@ CREATE INDEX idx_audit_events_on_entity_id_desc_author_id_created_at ON audit_ev
CREATE INDEX idx_audit_events_part_on_entity_id_desc_author_id_created_at ON ONLY audit_events USING btree (entity_id, entity_type, id DESC, author_id, created_at);
+CREATE INDEX idx_award_emoji_on_user_emoji_name_awardable_type_awardable_id ON award_emoji USING btree (user_id, name, awardable_type, awardable_id);
+
CREATE INDEX idx_ci_pipelines_artifacts_locked ON ci_pipelines USING btree (ci_ref_id, id) WHERE (locked = 1);
CREATE INDEX idx_container_exp_policies_on_project_id_next_run_at_enabled ON container_expiration_policies USING btree (project_id, next_run_at, enabled);
@@ -22004,8 +22007,6 @@ CREATE INDEX index_authentication_events_on_user_id ON authentication_events USI
CREATE INDEX index_award_emoji_on_awardable_type_and_awardable_id ON award_emoji USING btree (awardable_type, awardable_id);
-CREATE INDEX index_award_emoji_on_user_id_and_name ON award_emoji USING btree (user_id, name);
-
CREATE UNIQUE INDEX index_aws_roles_on_role_external_id ON aws_roles USING btree (role_external_id);
CREATE UNIQUE INDEX index_aws_roles_on_user_id ON aws_roles USING btree (user_id);
diff --git a/doc/administration/nfs.md b/doc/administration/nfs.md
index 7c80a2a3fe7..d04a86ab4c6 100644
--- a/doc/administration/nfs.md
+++ b/doc/administration/nfs.md
@@ -189,6 +189,7 @@ Note there are several options that you should consider using:
| `nofail` | Don't halt boot process waiting for this mount to become available
| `lookupcache=positive` | Tells the NFS client to honor `positive` cache results but invalidates any `negative` cache results. Negative cache results cause problems with Git. Specifically, a `git push` can fail to register uniformly across all NFS clients. The negative cache causes the clients to 'remember' that the files did not exist previously.
| `hard` | Instead of `soft`. [Further details](#soft-mount-option).
+| `cto` | `cto` is the default option, which you should use. Do not use `nocto`. [Further details](#nocto-mount-option).
#### `soft` mount option
@@ -225,6 +226,25 @@ the mount point. Use `SIGKILL` (`kill -9`) to deal with hung processes.
The `intr` option
[stopped working in the 2.6 kernel](https://access.redhat.com/solutions/157873).
+#### `nocto` mount option
+
+Do not use `nocto`. Instead, use `cto`, which is the default.
+
+When using `nocto`, the dentry cache is always used, up to `acdirmax` seconds (attribute cache time) from the time it's created.
+
+This results in stale dentry cache issues with multiple clients, where each client can see a different (cached)
+version of a directory.
+
+From the [Linux man page](https://linux.die.net/man/5/nfs), the important parts:
+
+> If the nocto option is specified, the client uses a non-standard heuristic to determine when files on the server have changed.
+>
+> Using the nocto option may improve performance for read-only mounts, but should be used only if the data on the server changes only occasionally.
+
+We have noticed this behavior in an issue about [refs not found after a push](https://gitlab.com/gitlab-org/gitaly/-/issues/2589),
+where newly added loose refs can be seen as missing on a different client with a local dentry cache, as
+[described in this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/326066#note_539436931).
+
### A single NFS mount
It's recommended to nest all GitLab data directories within a mount, that allows automatic
diff --git a/doc/development/api_graphql_styleguide.md b/doc/development/api_graphql_styleguide.md
index 8bac02c99af..7e4e7007ca2 100644
--- a/doc/development/api_graphql_styleguide.md
+++ b/doc/development/api_graphql_styleguide.md
@@ -392,6 +392,28 @@ field :blob, type: Types::Snippets::BlobType,
This will increment the [`complexity` score](#field-complexity) of the field by `1`.
+If a resolver calls Gitaly, it can be annotated with
+`BaseResolver.calls_gitaly!`. This passes `calls_gitaly: true` to any
+field that uses this resolver.
+
+For example:
+
+```ruby
+class BranchResolver < BaseResolver
+ type ::Types::BranchType, null: true
+ calls_gitaly!
+
+ argument name: ::GraphQL::STRING_TYPE, required: true
+
+ def resolve(name:)
+ object.branch(name)
+ end
+end
+```
+
+Then when we use it, any field that uses `BranchResolver` has the correct
+value for `calls_gitaly:`.
+
### Exposing permissions for a type
To expose permissions the current user has on a resource, you can call
@@ -1137,9 +1159,10 @@ When using resolvers, they can and should serve as the SSoT for field metadata.
All field options (apart from the field name) can be declared on the resolver.
These include:
-- `type` (this is particularly important, and is planned to be mandatory)
+- `type` (required - all resolvers must include a type annotation)
- `extras`
- `description`
+- Gitaly annotations (with `calls_gitaly!`)
Example:
@@ -1149,6 +1172,7 @@ module Resolvers
type Types::MyType, null: true
extras [:lookahead]
description 'Retrieve a single MyType'
+ calls_gitaly!
end
end
```
diff --git a/doc/development/code_review.md b/doc/development/code_review.md
index f354d7ccbe9..03ebd333e28 100644
--- a/doc/development/code_review.md
+++ b/doc/development/code_review.md
@@ -252,7 +252,7 @@ After merging, a maintainer should stay as the reviewer listed on the merge requ
### Dogfooding the Reviewers feature
-In March 18th 2021, an updated process was put in place aimed at efficiently and consistently dogfooding the Reviewers feature.
+On March 18th 2021, an updated process was put in place aimed at efficiently and consistently dogfooding the Reviewers feature.
Here is a summary of the changes, also reflected in this section above.
@@ -409,6 +409,8 @@ When ready to merge:
- **Start a new merge request pipeline with the `Run Pipeline` button in the merge
request's "Pipelines" tab, and enable "Merge When Pipeline Succeeds" (MWPS).** Note that:
- If **[master is broken](https://about.gitlab.com/handbook/engineering/workflow/#broken-master),
+ do not merge the merge request** except for
+ [very specific cases](https://about.gitlab.com/handbook/engineering/workflow/#criteria-for-merging-during-broken-master).
For other cases, follow these [handbook instructions](https://about.gitlab.com/handbook/engineering/workflow/#merging-during-broken-master).
- If the **latest [Pipeline for Merged Results](../ci/merge_request_pipelines/pipelines_for_merged_results/#pipelines-for-merged-results)** finished less than 2 hours ago, you
might merge without starting a new pipeline as the merge request is close
diff --git a/doc/development/documentation/structure.md b/doc/development/documentation/structure.md
index 8d564078ea2..33bfc040bb6 100644
--- a/doc/development/documentation/structure.md
+++ b/doc/development/documentation/structure.md
@@ -113,7 +113,7 @@ To create an issue:
1. Go to **Issues > List**.
1. In the top right, click **New issue**.
1. Complete the fields. (If you have a reference topic that lists each field, link to it here.)
-1. Click **Submit issue**.
+1. Click **Create issue**.
The issue is created. You can view it by going to **Issues > List**.
```
diff --git a/doc/development/snowplow.md b/doc/development/snowplow.md
index 3d566100677..720e2853851 100644
--- a/doc/development/snowplow.md
+++ b/doc/development/snowplow.md
@@ -314,6 +314,7 @@ Custom event tracking and instrumentation can be added by directly calling the `
| `project` | Project | nil | The project associated with the event. |
| `user` | User | nil | The user associated with the event. |
| `namespace` | Namespace | nil | The namespace associated with the event. |
+| `extra` | Hash | `{}` | Additional keyword arguments are collected into a hash and sent with the event. |
Tracking can be viewed as either tracking user behavior, or can be used for instrumentation to monitor and visualize performance over time in an area or aspect of code.
@@ -495,6 +496,7 @@ The [`StandardContext`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/g
| `namespace_id` | **{dotted-circle}** | integer | |
| `environment` | **{check-circle}** | string (max 32 chars) | Name of the source environment, such as `production` or `staging` |
| `source` | **{check-circle}** | string (max 32 chars) | Name of the source application, such as `gitlab-rails` or `gitlab-javascript` |
+| `extra` | **{dotted-circle}** | JSON | Any additional data associated with the event, in the form of key-value pairs |
### Default Schema
diff --git a/doc/operations/incident_management/incidents.md b/doc/operations/incident_management/incidents.md
index e4d9a87e39d..078a1a0be08 100644
--- a/doc/operations/incident_management/incidents.md
+++ b/doc/operations/incident_management/incidents.md
@@ -39,7 +39,7 @@ Incident, you have two options to do this manually.
1. Go to **Issues > List**, and select **New issue**.
1. In the **Type** dropdown, select **Incident**. Only fields relevant to
incidents are displayed on the page.
-1. Create the incident as needed, and select **Submit issue** to save the
+1. Create the incident as needed, and select **Create issue** to save the
incident.
![Incident List Create](img/new_incident_create_v13_4.png)
diff --git a/doc/user/discussions/index.md b/doc/user/discussions/index.md
index 9020c6e0b91..f622d075ba4 100644
--- a/doc/user/discussions/index.md
+++ b/doc/user/discussions/index.md
@@ -119,7 +119,7 @@ the unresolved threads.
![Issue mentioning threads in a merge request](img/preview_issue_for_threads.png)
-Hitting **Submit issue** causes all threads to be marked as resolved and
+Hitting **Create issue** causes all threads to be marked as resolved and
add a note referring to the newly created issue.
![Mark threads as resolved notice](img/resolve_thread_issue_notice.png)
diff --git a/doc/user/group/saml_sso/index.md b/doc/user/group/saml_sso/index.md
index 6078de0f9e1..da7e9828d48 100644
--- a/doc/user/group/saml_sso/index.md
+++ b/doc/user/group/saml_sso/index.md
@@ -95,6 +95,7 @@ Please note that the certificate [fingerprint algorithm](../../../integration/sa
- [Improved](https://gitlab.com/gitlab-org/gitlab/-/issues/9255) in GitLab 11.11 with ongoing enforcement in the GitLab UI.
- [Improved](https://gitlab.com/gitlab-org/gitlab/-/issues/292811) in GitLab 13.8, with an updated timeout experience.
- [Improved](https://gitlab.com/gitlab-org/gitlab/-/issues/211962) in GitLab 13.8 with allowing group owners to not go through SSO.
+- [Improved](https://gitlab.com/gitlab-org/gitlab/-/issues/9152) in GitLab 13.11 with enforcing open SSO session to use Git if this setting is switched on.
With this option enabled, users must go through your group's GitLab single sign-on URL if they wish to access group resources through the UI. Users can't be manually added as members.
@@ -104,9 +105,15 @@ However, users are not prompted to sign in through SSO on each visit. GitLab che
has authenticated through SSO. If it's been more than 1 day since the last sign-in, GitLab
prompts the user to sign in again through SSO.
-We intend to add a similar SSO requirement for [Git and API activity](https://gitlab.com/gitlab-org/gitlab/-/issues/9152).
+We intend to add a similar SSO requirement for [API activity](https://gitlab.com/gitlab-org/gitlab/-/issues/9152).
-When SSO enforcement is enabled for a group, users can't share a project in the group outside the top-level group, even if the project is forked.
+SSO has the following effects when enabled:
+
+- For groups, users can't share a project in the group outside the top-level group,
+ even if the project is forked.
+- For a Git activity, users must be signed-in through SSO before they can push to or
+ pull from a GitLab repository.
+<!-- Add bullet for API activity when https://gitlab.com/gitlab-org/gitlab/-/issues/9152 is complete -->
## Providers
diff --git a/doc/user/project/issues/confidential_issues.md b/doc/user/project/issues/confidential_issues.md
index e1918b68ddc..25357a1db0b 100644
--- a/doc/user/project/issues/confidential_issues.md
+++ b/doc/user/project/issues/confidential_issues.md
@@ -19,7 +19,7 @@ You can make an issue confidential during issue creation or by editing
an existing one.
When you create a new issue, a checkbox right below the text area is available
-to mark the issue as confidential. Check that box and hit the **Submit issue**
+to mark the issue as confidential. Check that box and hit the **Create issue**
button to create the issue. For existing issues, edit them, check the
confidential checkbox and hit **Save changes**.
diff --git a/doc/user/project/pages/introduction.md b/doc/user/project/pages/introduction.md
index 277238bfc98..3c3de26d7dd 100644
--- a/doc/user/project/pages/introduction.md
+++ b/doc/user/project/pages/introduction.md
@@ -295,5 +295,5 @@ The contents of the public directory can be confirmed by [browsing the artifacts
Files listed under the public directory can be accessed through the Pages URL for the project.
A 404 can also be related to incorrect permissions. If [Pages Access Control](pages_access_control.md) is enabled, and a user
-navigates to the Pages URL and receives a 404 reponse, it is possible that the user does not have permission to view the site.
+navigates to the Pages URL and receives a 404 response, it is possible that the user does not have permission to view the site.
To fix this, verify that the user is a member of the project.
diff --git a/lib/gitlab/git_access.rb b/lib/gitlab/git_access.rb
index c5ca46827cb..31e4755192e 100644
--- a/lib/gitlab/git_access.rb
+++ b/lib/gitlab/git_access.rb
@@ -91,6 +91,7 @@ module Gitlab
when *PUSH_COMMANDS
check_push_access!
end
+ check_additional_conditions!
success_result
end
@@ -530,6 +531,10 @@ module Gitlab
def size_checker
container.repository_size_checker
end
+
+ # overriden in EE
+ def check_additional_conditions!
+ end
end
end
diff --git a/lib/gitlab/tracking.rb b/lib/gitlab/tracking.rb
index 2f0e7e99305..3f2ff4ce4ac 100644
--- a/lib/gitlab/tracking.rb
+++ b/lib/gitlab/tracking.rb
@@ -9,8 +9,8 @@ module Gitlab
Gitlab::CurrentSettings.snowplow_enabled?
end
- def event(category, action, label: nil, property: nil, value: nil, context: [], project: nil, user: nil, namespace: nil) # rubocop:disable Metrics/ParameterLists
- contexts = [Tracking::StandardContext.new(project: project, user: user, namespace: namespace).to_context, *context]
+ def event(category, action, label: nil, property: nil, value: nil, context: [], project: nil, user: nil, namespace: nil, **extra) # rubocop:disable Metrics/ParameterLists
+ contexts = [Tracking::StandardContext.new(project: project, user: user, namespace: namespace, **extra).to_context, *context]
snowplow.event(category, action, label: label, property: property, value: value, context: contexts)
product_analytics.event(category, action, label: label, property: property, value: value, context: contexts)
diff --git a/lib/gitlab/tracking/standard_context.rb b/lib/gitlab/tracking/standard_context.rb
index 5880116132a..da030649f76 100644
--- a/lib/gitlab/tracking/standard_context.rb
+++ b/lib/gitlab/tracking/standard_context.rb
@@ -3,11 +3,11 @@
module Gitlab
module Tracking
class StandardContext
- GITLAB_STANDARD_SCHEMA_URL = 'iglu:com.gitlab/gitlab_standard/jsonschema/1-0-3'
+ GITLAB_STANDARD_SCHEMA_URL = 'iglu:com.gitlab/gitlab_standard/jsonschema/1-0-4'
GITLAB_RAILS_SOURCE = 'gitlab-rails'
- def initialize(namespace: nil, project: nil, user: nil, **data)
- @data = data
+ def initialize(namespace: nil, project: nil, user: nil, **extra)
+ @extra = extra
end
def to_context
@@ -35,8 +35,9 @@ module Gitlab
def to_h
{
environment: environment,
- source: source
- }.merge(@data)
+ source: source,
+ extra: @extra
+ }
end
end
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 72f5c58d8ed..1afde61f340 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -2076,6 +2076,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
+msgid "Address"
+msgstr ""
+
msgid "Adds"
msgstr ""
@@ -4943,9 +4946,6 @@ msgstr ""
msgid "Boards|An error occurred while fetching group projects. Please try again."
msgstr ""
-msgid "Boards|An error occurred while fetching issues. Please reload the page."
-msgstr ""
-
msgid "Boards|An error occurred while fetching labels. Please reload the page."
msgstr ""
@@ -5694,6 +5694,9 @@ msgstr ""
msgid "Change this value to influence how frequently the GitLab UI polls for updates."
msgstr ""
+msgid "Change this value to influence how frequently the GitLab UI polls for updates. If you set the value to 2 all polling intervals are multiplied by 2, which means that polling happens half as frequently. The multiplier can also have a decimal value. The default value (1) is a reasonable choice for the majority of GitLab installations. Set to 0 to completely disable polling."
+msgstr ""
+
msgid "Change title"
msgstr ""
@@ -6429,12 +6432,39 @@ msgstr ""
msgid "CloudLicense|Activate"
msgstr ""
+msgid "CloudLicense|ID"
+msgstr ""
+
+msgid "CloudLicense|Last Sync"
+msgstr ""
+
+msgid "CloudLicense|Licensed to"
+msgstr ""
+
+msgid "CloudLicense|Manage"
+msgstr ""
+
msgid "CloudLicense|Paste your activation code"
msgstr ""
msgid "CloudLicense|Paste your activation code below"
msgstr ""
+msgid "CloudLicense|Plan"
+msgstr ""
+
+msgid "CloudLicense|Renews"
+msgstr ""
+
+msgid "CloudLicense|Started"
+msgstr ""
+
+msgid "CloudLicense|Subscription details"
+msgstr ""
+
+msgid "CloudLicense|Sync Subscription details"
+msgstr ""
+
msgid "CloudLicense|This instance is currently using the %{planName} plan."
msgstr ""
@@ -7763,6 +7793,9 @@ msgstr ""
msgid "Community forum"
msgstr ""
+msgid "Company"
+msgstr ""
+
msgid "Company name"
msgstr ""
@@ -9170,6 +9203,9 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
+msgid "Creating pack file bitmaps makes housekeeping take a little longer but bitmaps should accelerate 'git clone' performance."
+msgstr ""
+
msgid "Creation date"
msgstr ""
@@ -11511,6 +11547,9 @@ msgstr ""
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Git pack file bitmap creation"
+msgstr ""
+
msgid "Enable Gitpod"
msgstr ""
@@ -11535,6 +11574,9 @@ msgstr ""
msgid "Enable Pseudonymizer data collection"
msgstr ""
+msgid "Enable Repository Checks"
+msgstr ""
+
msgid "Enable SSL verification"
msgstr ""
@@ -11559,6 +11601,9 @@ msgstr ""
msgid "Enable and disable Service Desk. Some additional configuration might be required. %{link_start}Learn more%{link_end}."
msgstr ""
+msgid "Enable automatic repository housekeeping (git repack, git gc)"
+msgstr ""
+
msgid "Enable classification control using an external service"
msgstr ""
@@ -14195,6 +14240,9 @@ msgstr ""
msgid "Git"
msgstr ""
+msgid "Git GC period"
+msgstr ""
+
msgid "Git LFS is not enabled on this GitLab server, contact your admin."
msgstr ""
@@ -14327,6 +14375,9 @@ msgstr ""
msgid "GitLab version"
msgstr ""
+msgid "GitLab will periodically run %{link_to_git_fsck} in all project and wiki repositories to look for silent disk corruption issues."
+msgstr ""
+
msgid "GitLab will run a background job that will produce pseudonymized CSVs of the GitLab database that will be uploaded to your configured object storage directory."
msgstr ""
@@ -14906,9 +14957,15 @@ msgstr ""
msgid "GroupSAML|Are you sure you want to remove the SAML group link?"
msgstr ""
+msgid "GroupSAML|Before enforcing SSO, enable SAML authentication."
+msgstr ""
+
msgid "GroupSAML|Certificate fingerprint"
msgstr ""
+msgid "GroupSAML|Check SSO on git activity"
+msgstr ""
+
msgid "GroupSAML|Configuration"
msgstr ""
@@ -14924,7 +14981,10 @@ msgstr ""
msgid "GroupSAML|Enable SAML authentication for this group."
msgstr ""
-msgid "GroupSAML|Enforce SSO-only authentication for this group."
+msgid "GroupSAML|Enforce SSO-access for Git in this group."
+msgstr ""
+
+msgid "GroupSAML|Enforce SSO-only authentication for web activity for this group."
msgstr ""
msgid "GroupSAML|Enforce users to have dedicated group managed accounts for this group."
@@ -15020,9 +15080,6 @@ msgstr ""
msgid "GroupSAML|This will be set as the access level of users added to the group."
msgstr ""
-msgid "GroupSAML|To be able to enable enforced SSO, you first need to enable SAML authentication."
-msgstr ""
-
msgid "GroupSAML|To be able to enable group managed accounts, you first need to enable enforced SSO."
msgstr ""
@@ -15699,6 +15756,12 @@ msgstr ""
msgid "If you did not recently sign in, you should immediately change your password: %{password_link}."
msgstr ""
+msgid "If you got a lot of false alarms from repository checks you can choose to clear all repository check information from the database."
+msgstr ""
+
+msgid "If you keep automatic housekeeping disabled for a long time Git repository access on your GitLab server will become slower and your repositories will use more disk space. We recommend to always leave this enabled."
+msgstr ""
+
msgid "If you lose your recovery codes you can generate new ones, invalidating all previous codes."
msgstr ""
@@ -16509,6 +16572,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Infrastructure Registry"
+msgstr ""
+
msgid "Inherited"
msgstr ""
@@ -21351,6 +21417,15 @@ msgstr ""
msgid "Number of Elasticsearch shards"
msgstr ""
+msgid "Number of Git pushes after which 'git gc' is run."
+msgstr ""
+
+msgid "Number of Git pushes after which a full 'git repack' is run."
+msgstr ""
+
+msgid "Number of Git pushes after which an incremental 'git repack' is run."
+msgstr ""
+
msgid "Number of LOCs per commit"
msgstr ""
@@ -23147,6 +23222,9 @@ msgstr ""
msgid "Policy project doesn't exist"
msgstr ""
+msgid "Polling interval multiplier"
+msgstr ""
+
msgid "Popularity"
msgstr ""
@@ -26033,6 +26111,9 @@ msgstr ""
msgid "Repository check was triggered."
msgstr ""
+msgid "Repository checks"
+msgstr ""
+
msgid "Repository cleanup"
msgstr ""
@@ -29319,9 +29400,6 @@ msgstr ""
msgid "Submit feedback"
msgstr ""
-msgid "Submit issue"
-msgstr ""
-
msgid "Submit review"
msgstr ""
diff --git a/scripts/gitaly-test-build b/scripts/gitaly-test-build
index bb561e2906a..849c08df527 100755
--- a/scripts/gitaly-test-build
+++ b/scripts/gitaly-test-build
@@ -13,6 +13,8 @@ class GitalyTestBuild
include GitalyTest
def run
+ set_bundler_config
+
abort 'gitaly build failed' unless build_gitaly
ensure_gitlab_shell_secret!
diff --git a/scripts/gitaly-test-spawn b/scripts/gitaly-test-spawn
index 8547d0b13e4..7cb9ea803f8 100755
--- a/scripts/gitaly-test-spawn
+++ b/scripts/gitaly-test-spawn
@@ -9,6 +9,7 @@ class GitalyTestSpawn
include GitalyTest
def run
+ set_bundler_config
install_gitaly_gems if ENV['CI']
check_gitaly_config!
diff --git a/scripts/gitaly_test.rb b/scripts/gitaly_test.rb
index 7ce1d7b16e4..f970457fea7 100644
--- a/scripts/gitaly_test.rb
+++ b/scripts/gitaly_test.rb
@@ -34,6 +34,10 @@ module GitalyTest
File.join(tmp_tests_gitaly_dir, 'ruby', 'Gemfile')
end
+ def gemfile_dir
+ File.dirname(gemfile)
+ end
+
def gitlab_shell_secret_file
File.join(tmp_tests_gitlab_shell_dir, '.gitlab_shell_secret')
end
@@ -42,8 +46,7 @@ module GitalyTest
env_hash = {
'HOME' => File.expand_path('tmp/tests'),
'GEM_PATH' => Gem.path.join(':'),
- 'BUNDLE_APP_CONFIG' => File.join(File.dirname(gemfile), '.bundle/config'),
- 'BUNDLE_FLAGS' => "--jobs=4 --retry=3",
+ 'BUNDLE_APP_CONFIG' => File.join(gemfile_dir, '.bundle'),
'BUNDLE_INSTALL_FLAGS' => nil,
'BUNDLE_GEMFILE' => gemfile,
'RUBYOPT' => nil,
@@ -52,13 +55,20 @@ module GitalyTest
'GITALY_TESTING_NO_GIT_HOOKS' => "1"
}
+ env_hash
+ end
+
+ # rubocop:disable GitlabSecurity/SystemCommandInjection
+ def set_bundler_config
+ system('bundle config set --local jobs 4', chdir: gemfile_dir)
+ system('bundle config set --local retry 3', chdir: gemfile_dir)
+
if ENV['CI']
bundle_path = File.expand_path('../vendor/gitaly-ruby', __dir__)
- env_hash['BUNDLE_FLAGS'] += " --path=#{bundle_path}"
+ system('bundle', 'config', 'set', '--local', 'path', bundle_path, chdir: gemfile_dir)
end
-
- env_hash
end
+ # rubocop:enable GitlabSecurity/SystemCommandInjection
def config_path(service)
case service
diff --git a/spec/features/boards/new_issue_spec.rb b/spec/features/boards/new_issue_spec.rb
index 4d419f89aa3..feb0b0b992f 100644
--- a/spec/features/boards/new_issue_spec.rb
+++ b/spec/features/boards/new_issue_spec.rb
@@ -60,7 +60,7 @@ RSpec.describe 'Issue Boards new issue', :js do
page.within(first('.board-new-issue-form')) do
find('.form-control').set('bug')
- click_button 'Submit issue'
+ click_button 'Create issue'
end
wait_for_requests
@@ -85,7 +85,7 @@ RSpec.describe 'Issue Boards new issue', :js do
page.within(first('.board-new-issue-form')) do
find('.form-control').set('bug')
- click_button 'Submit issue'
+ click_button 'Create issue'
end
wait_for_requests
@@ -100,7 +100,7 @@ RSpec.describe 'Issue Boards new issue', :js do
page.within(first('.board-new-issue-form')) do
find('.form-control').set('new issue')
- click_button 'Submit issue'
+ click_button 'Create issue'
end
wait_for_requests
diff --git a/spec/features/boards/sidebar_spec.rb b/spec/features/boards/sidebar_spec.rb
index 57e88fac013..977147c3c6b 100644
--- a/spec/features/boards/sidebar_spec.rb
+++ b/spec/features/boards/sidebar_spec.rb
@@ -7,10 +7,10 @@ RSpec.describe 'Project issue boards sidebar', :js do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, :public) }
- let_it_be(:issue) { create(:issue, project: project, relative_position: 1) }
let_it_be(:board) { create(:board, project: project) }
let_it_be(:list) { create(:list, board: board, position: 0) }
- let(:card) { find('.board:nth-child(1)').first('.board-card') }
+
+ let_it_be(:issue, reload: true) { create(:issue, project: project, relative_position: 1) }
before do
project.add_maintainer(user)
@@ -18,41 +18,17 @@ RSpec.describe 'Project issue boards sidebar', :js do
sign_in(user)
visit project_board_path(project, board)
- wait_for_requests
- end
-
- it 'shows sidebar when clicking issue' do
- click_card(card)
-
- expect(page).to have_selector('.issue-boards-sidebar')
- end
-
- it 'closes sidebar when clicking issue' do
- click_card(card)
- expect(page).to have_selector('.issue-boards-sidebar')
-
- click_card(card)
-
- expect(page).not_to have_selector('.issue-boards-sidebar')
+ wait_for_requests
end
- it 'closes sidebar when clicking close button' do
- click_card(card)
+ it_behaves_like 'issue boards sidebar'
- expect(page).to have_selector('.issue-boards-sidebar')
-
- find("[data-testid='sidebar-drawer'] .gl-drawer-close-button").click
-
- expect(page).not_to have_selector('.issue-boards-sidebar')
+ def first_card
+ find('.board:nth-child(1)').first("[data-testid='board_card']")
end
- it 'shows issue details when sidebar is open' do
- click_card(card)
-
- page.within('.issue-boards-sidebar') do
- expect(page).to have_content(issue.title)
- expect(page).to have_content(issue.to_reference)
- end
+ def click_first_issue_card
+ click_card(first_card)
end
end
diff --git a/spec/features/boards/sidebar_subscription_spec.rb b/spec/features/boards/sidebar_subscription_spec.rb
deleted file mode 100644
index 598fec7514e..00000000000
--- a/spec/features/boards/sidebar_subscription_spec.rb
+++ /dev/null
@@ -1,54 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe 'Project issue boards sidebar subscription', :js do
- include BoardHelpers
-
- let_it_be(:user) { create(:user) }
- let_it_be(:project) { create(:project, :public) }
- let_it_be(:issue1) { create(:issue, project: project, relative_position: 1) }
- let_it_be(:issue2) { create(:issue, project: project, relative_position: 2) }
- let_it_be(:subscription) { create(:subscription, user: user, project: project, subscribable: issue2, subscribed: true) }
- let_it_be(:board) { create(:board, project: project) }
- let_it_be(:list) { create(:list, board: board, position: 0) }
- let(:card1) { find('.board:nth-child(1) .board-card:nth-of-type(1)') }
- let(:card2) { find('.board:nth-child(1) .board-card:nth-of-type(2)') }
-
- before do
- stub_feature_flags(graphql_board_lists: false)
-
- project.add_maintainer(user)
-
- sign_in(user)
-
- visit project_board_path(project, board)
- wait_for_requests
- end
-
- context 'subscription' do
- it 'changes issue subscription' do
- click_card(card1)
- wait_for_requests
-
- page.within('.subscriptions') do
- find('[data-testid="subscription-toggle"] button:not(.is-checked)').click
- wait_for_requests
-
- expect(page).to have_css('[data-testid="subscription-toggle"] button.is-checked')
- end
- end
-
- it 'has checked subscription toggle when already subscribed' do
- click_card(card2)
- wait_for_requests
-
- page.within('.subscriptions') do
- find('[data-testid="subscription-toggle"] button.is-checked').click
- wait_for_requests
-
- expect(page).to have_css('[data-testid="subscription-toggle"] button:not(.is-checked)')
- end
- end
- end
-end
diff --git a/spec/features/boards/sidebar_time_tracking_spec.rb b/spec/features/boards/sidebar_time_tracking_spec.rb
deleted file mode 100644
index 3ac8b93692a..00000000000
--- a/spec/features/boards/sidebar_time_tracking_spec.rb
+++ /dev/null
@@ -1,52 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe 'Project issue boards sidebar time tracking', :js do
- include BoardHelpers
-
- let_it_be(:user) { create(:user) }
- let_it_be(:project) { create(:project, :public) }
- let_it_be(:board) { create(:board, project: project) }
- let_it_be(:list) { create(:list, board: board, position: 0) }
- let!(:issue) { create(:issue, project: project, relative_position: 1) }
- let(:card) { find('.board:nth-child(1)').first('.board-card') }
-
- let(:application_settings) { {} }
-
- before do
- stub_feature_flags(graphql_board_lists: false)
-
- project.add_maintainer(user)
-
- sign_in(user)
-
- stub_application_setting(application_settings)
-
- visit project_board_path(project, board)
- wait_for_requests
- end
-
- context 'time tracking' do
- let(:compare_meter_tooltip) { find('.time-tracking .time-tracking-content .compare-meter')['title'] }
-
- before do
- issue.timelogs.create!(time_spent: 14400, user: user)
- issue.update!(time_estimate: 128800)
-
- click_card(card)
- end
-
- it 'shows time tracking progress bar' do
- expect(compare_meter_tooltip).to eq('Time remaining: 3d 7h 46m')
- end
-
- context 'when time_tracking_limit_to_hours is true' do
- let(:application_settings) { { time_tracking_limit_to_hours: true } }
-
- it 'shows time tracking progress bar' do
- expect(compare_meter_tooltip).to eq('Time remaining: 31h 46m')
- end
- end
- end
-end
diff --git a/spec/features/groups/board_spec.rb b/spec/features/groups/board_spec.rb
index aab3f5e68d5..b4c60ff4fa3 100644
--- a/spec/features/groups/board_spec.rb
+++ b/spec/features/groups/board_spec.rb
@@ -33,7 +33,7 @@ RSpec.describe 'Group Boards' do
find('.gl-new-dropdown-item button').click
end
- click_button 'Submit issue'
+ click_button 'Create issue'
expect(page).to have_content(issue_title)
end
diff --git a/spec/features/groups/navbar_spec.rb b/spec/features/groups/navbar_spec.rb
index 710755ce306..021b1af54d4 100644
--- a/spec/features/groups/navbar_spec.rb
+++ b/spec/features/groups/navbar_spec.rb
@@ -68,7 +68,7 @@ RSpec.describe 'Group navbar' do
before do
stub_config(registry: { enabled: true })
- insert_container_nav(_('Kubernetes'))
+ insert_container_nav
visit group_path(group)
end
@@ -80,7 +80,7 @@ RSpec.describe 'Group navbar' do
before do
stub_config(dependency_proxy: { enabled: true })
- insert_dependency_proxy_nav(_('Dependency Proxy'))
+ insert_dependency_proxy_nav
visit group_path(group)
end
diff --git a/spec/features/projects/navbar_spec.rb b/spec/features/projects/navbar_spec.rb
index 4ff3827b240..7dc3ee63669 100644
--- a/spec/features/projects/navbar_spec.rb
+++ b/spec/features/projects/navbar_spec.rb
@@ -13,6 +13,8 @@ RSpec.describe 'Project navbar' do
before do
insert_package_nav(_('Operations'))
+ insert_infrastructure_registry_nav
+ stub_config(registry: { enabled: false })
project.add_maintainer(user)
sign_in(user)
@@ -60,7 +62,7 @@ RSpec.describe 'Project navbar' do
before do
stub_config(registry: { enabled: true })
- insert_container_nav(_('Operations'))
+ insert_container_nav
visit project_path(project)
end
diff --git a/spec/features/users/terms_spec.rb b/spec/features/users/terms_spec.rb
index 7500f2fe59a..8ba79d77c22 100644
--- a/spec/features/users/terms_spec.rb
+++ b/spec/features/users/terms_spec.rb
@@ -121,7 +121,7 @@ RSpec.describe 'Users > Terms' do
enforce_terms
- click_button 'Submit issue'
+ click_button 'Create issue'
expect(current_path).to eq(terms_path)
diff --git a/spec/frontend/boards/board_new_issue_deprecated_spec.js b/spec/frontend/boards/board_new_issue_deprecated_spec.js
index 3903ad201b2..3beaf870bf5 100644
--- a/spec/frontend/boards/board_new_issue_deprecated_spec.js
+++ b/spec/frontend/boards/board_new_issue_deprecated_spec.js
@@ -111,7 +111,7 @@ describe('Issue boards new issue form', () => {
describe('submit success', () => {
it('creates new issue', () => {
- wrapper.setData({ title: 'submit issue' });
+ wrapper.setData({ title: 'create issue' });
return Vue.nextTick()
.then(submitIssue)
@@ -122,7 +122,7 @@ describe('Issue boards new issue form', () => {
it('enables button after submit', () => {
jest.spyOn(wrapper.vm, 'submit').mockImplementation();
- wrapper.setData({ title: 'submit issue' });
+ wrapper.setData({ title: 'create issue' });
return Vue.nextTick()
.then(submitIssue)
@@ -132,7 +132,7 @@ describe('Issue boards new issue form', () => {
});
it('clears title after submit', () => {
- wrapper.setData({ title: 'submit issue' });
+ wrapper.setData({ title: 'create issue' });
return Vue.nextTick()
.then(submitIssue)
@@ -143,17 +143,17 @@ describe('Issue boards new issue form', () => {
it('sets detail issue after submit', () => {
expect(boardsStore.detail.issue.title).toBe(undefined);
- wrapper.setData({ title: 'submit issue' });
+ wrapper.setData({ title: 'create issue' });
return Vue.nextTick()
.then(submitIssue)
.then(() => {
- expect(boardsStore.detail.issue.title).toBe('submit issue');
+ expect(boardsStore.detail.issue.title).toBe('create issue');
});
});
it('sets detail list after submit', () => {
- wrapper.setData({ title: 'submit issue' });
+ wrapper.setData({ title: 'create issue' });
return Vue.nextTick()
.then(submitIssue)
@@ -164,7 +164,7 @@ describe('Issue boards new issue form', () => {
it('sets detail weight after submit', () => {
boardsStore.weightFeatureAvailable = true;
- wrapper.setData({ title: 'submit issue' });
+ wrapper.setData({ title: 'create issue' });
return Vue.nextTick()
.then(submitIssue)
@@ -175,7 +175,7 @@ describe('Issue boards new issue form', () => {
it('does not set detail weight after submit', () => {
boardsStore.weightFeatureAvailable = false;
- wrapper.setData({ title: 'submit issue' });
+ wrapper.setData({ title: 'create issue' });
return Vue.nextTick()
.then(submitIssue)
diff --git a/spec/frontend/boards/components/board_new_issue_spec.js b/spec/frontend/boards/components/board_new_issue_spec.js
index 737a18294bc..e6405bbcff3 100644
--- a/spec/frontend/boards/components/board_new_issue_spec.js
+++ b/spec/frontend/boards/components/board_new_issue_spec.js
@@ -86,7 +86,7 @@ describe('Issue boards new issue form', () => {
describe('submit success', () => {
it('creates new issue', async () => {
- wrapper.setData({ title: 'submit issue' });
+ wrapper.setData({ title: 'create issue' });
await vm.$nextTick();
await submitIssue();
@@ -95,7 +95,7 @@ describe('Issue boards new issue form', () => {
it('enables button after submit', async () => {
jest.spyOn(wrapper.vm, 'submit').mockImplementation();
- wrapper.setData({ title: 'submit issue' });
+ wrapper.setData({ title: 'create issue' });
await vm.$nextTick();
await submitIssue();
@@ -103,7 +103,7 @@ describe('Issue boards new issue form', () => {
});
it('clears title after submit', async () => {
- wrapper.setData({ title: 'submit issue' });
+ wrapper.setData({ title: 'create issue' });
await vm.$nextTick();
await submitIssue();
diff --git a/spec/frontend/members/components/avatars/user_avatar_spec.js b/spec/frontend/members/components/avatars/user_avatar_spec.js
index 3f4d9155c5d..5cf3a4cdc13 100644
--- a/spec/frontend/members/components/avatars/user_avatar_spec.js
+++ b/spec/frontend/members/components/avatars/user_avatar_spec.js
@@ -1,31 +1,25 @@
import { GlAvatarLink, GlBadge } from '@gitlab/ui';
import { within } from '@testing-library/dom';
import { mount, createWrapper } from '@vue/test-utils';
-import Vue from 'vue';
-import Vuex from 'vuex';
import UserAvatar from '~/members/components/avatars/user_avatar.vue';
import { member as memberMock, member2faEnabled, orphanedMember } from '../../mock_data';
-Vue.use(Vuex);
-
describe('UserAvatar', () => {
let wrapper;
const { user } = memberMock;
- const createComponent = (propsData = {}, state = {}) => {
+ const createComponent = (propsData = {}, provide = {}) => {
wrapper = mount(UserAvatar, {
propsData: {
member: memberMock,
isCurrentUser: false,
...propsData,
},
- store: new Vuex.Store({
- state: {
- canManageMembers: true,
- ...state,
- },
- }),
+ provide: {
+ canManageMembers: true,
+ ...provide,
+ },
});
};
diff --git a/spec/frontend/members/components/filter_sort/members_filtered_search_bar_spec.js b/spec/frontend/members/components/filter_sort/members_filtered_search_bar_spec.js
index 14b437a8c4e..326a29747ef 100644
--- a/spec/frontend/members/components/filter_sort/members_filtered_search_bar_spec.js
+++ b/spec/frontend/members/components/filter_sort/members_filtered_search_bar_spec.js
@@ -10,10 +10,9 @@ localVue.use(Vuex);
describe('MembersFilteredSearchBar', () => {
let wrapper;
- const createComponent = (state) => {
+ const createComponent = ({ state = {}, provide = {} } = {}) => {
const store = new Vuex.Store({
state: {
- sourceId: 1,
filteredSearchBar: {
show: true,
tokens: ['two_factor'],
@@ -21,13 +20,17 @@ describe('MembersFilteredSearchBar', () => {
placeholder: 'Filter members',
recentSearchesStorageKey: 'group_members',
},
- canManageMembers: true,
...state,
},
});
wrapper = shallowMount(MembersFilteredSearchBar, {
localVue,
+ provide: {
+ sourceId: 1,
+ canManageMembers: true,
+ ...provide,
+ },
store,
});
};
@@ -68,14 +71,18 @@ describe('MembersFilteredSearchBar', () => {
describe('when `canManageMembers` is false', () => {
it('excludes 2FA token', () => {
createComponent({
- filteredSearchBar: {
- show: true,
- tokens: ['two_factor', 'with_inherited_permissions'],
- searchParam: 'search',
- placeholder: 'Filter members',
- recentSearchesStorageKey: 'group_members',
+ state: {
+ filteredSearchBar: {
+ show: true,
+ tokens: ['two_factor', 'with_inherited_permissions'],
+ searchParam: 'search',
+ placeholder: 'Filter members',
+ recentSearchesStorageKey: 'group_members',
+ },
+ },
+ provide: {
+ canManageMembers: false,
},
- canManageMembers: false,
});
expect(findFilteredSearchBar().props('tokens')).toEqual([
diff --git a/spec/frontend/members/components/filter_sort/sort_dropdown_spec.js b/spec/frontend/members/components/filter_sort/sort_dropdown_spec.js
index 357fad741e9..390e12bc0e5 100644
--- a/spec/frontend/members/components/filter_sort/sort_dropdown_spec.js
+++ b/spec/frontend/members/components/filter_sort/sort_dropdown_spec.js
@@ -15,7 +15,6 @@ describe('SortDropdown', () => {
const createComponent = (state) => {
const store = new Vuex.Store({
state: {
- sourceId: 1,
tableSortableFields: ['account', 'granted', 'expires', 'maxRole', 'lastSignIn'],
filteredSearchBar: {
show: true,
@@ -30,6 +29,9 @@ describe('SortDropdown', () => {
wrapper = mount(SortDropdown, {
localVue,
+ provide: {
+ sourceId: 1,
+ },
store,
});
};
diff --git a/spec/frontend/members/components/table/members_table_cell_spec.js b/spec/frontend/members/components/table/members_table_cell_spec.js
index b7dcd2a9fae..5375ee11736 100644
--- a/spec/frontend/members/components/table/members_table_cell_spec.js
+++ b/spec/frontend/members/components/table/members_table_cell_spec.js
@@ -42,21 +42,21 @@ describe('MembersTableCell', () => {
const createStore = (state = {}) => {
return new Vuex.Store({
- state: {
- sourceId: 1,
- currentUserId: 1,
- ...state,
- },
+ state,
});
};
let wrapper;
- const createComponent = (propsData, state = {}) => {
+ const createComponent = (propsData, state) => {
wrapper = mount(MembersTableCell, {
localVue,
propsData,
store: createStore(state),
+ provide: {
+ sourceId: 1,
+ currentUserId: 1,
+ },
scopedSlots: {
default: `
<wrapped-component
diff --git a/spec/frontend/members/components/table/members_table_spec.js b/spec/frontend/members/components/table/members_table_spec.js
index cf5811e72e7..0395dc39880 100644
--- a/spec/frontend/members/components/table/members_table_spec.js
+++ b/spec/frontend/members/components/table/members_table_spec.js
@@ -32,17 +32,20 @@ describe('MembersTable', () => {
table: { 'data-qa-selector': 'members_list' },
tr: { 'data-qa-selector': 'member_row' },
},
- sourceId: 1,
- currentUserId: 1,
...state,
},
});
};
- const createComponent = (state) => {
+ const createComponent = (state, provide = {}) => {
wrapper = mount(MembersTable, {
localVue,
store: createStore(state),
+ provide: {
+ sourceId: 1,
+ currentUserId: 1,
+ ...provide,
+ },
stubs: [
'member-avatar',
'member-source',
@@ -119,7 +122,7 @@ describe('MembersTable', () => {
describe('when user is not logged in', () => {
it('does not render the "Actions" field', () => {
- createComponent({ currentUserId: null, tableFields: ['actions'] });
+ createComponent({ tableFields: ['actions'] }, { currentUserId: null });
expect(within(wrapper.element).queryByTestId('col-actions')).toBe(null);
});
diff --git a/spec/frontend/members/index_spec.js b/spec/frontend/members/index_spec.js
index dd3b9ddd912..f40c08401d4 100644
--- a/spec/frontend/members/index_spec.js
+++ b/spec/frontend/members/index_spec.js
@@ -42,33 +42,6 @@ describe('initMembersApp', () => {
expect(wrapper.find(MembersApp).exists()).toBe(true);
});
- it('sets `currentUserId` in Vuex store', () => {
- setup();
-
- expect(vm.$store.state.currentUserId).toBe(123);
- });
-
- describe('when `gon.current_user_id` is not set (user is not logged in)', () => {
- it('sets `currentUserId` as `null` in Vuex store', () => {
- window.gon = {};
- setup();
-
- expect(vm.$store.state.currentUserId).toBeNull();
- });
- });
-
- it('parses and sets `data-source-id` as `sourceId` in Vuex store', () => {
- setup();
-
- expect(vm.$store.state.sourceId).toBe(234);
- });
-
- it('parses and sets `data-can-manage-members` as `canManageMembers` in Vuex store', () => {
- setup();
-
- expect(vm.$store.state.canManageMembers).toBe(true);
- });
-
it('parses and sets `members` in Vuex store', () => {
setup();
diff --git a/spec/lib/gitlab/error_tracking/processor/context_payload_processor_spec.rb b/spec/lib/gitlab/error_tracking/processor/context_payload_processor_spec.rb
index 2a4478ded6b..24f5299d357 100644
--- a/spec/lib/gitlab/error_tracking/processor/context_payload_processor_spec.rb
+++ b/spec/lib/gitlab/error_tracking/processor/context_payload_processor_spec.rb
@@ -23,10 +23,10 @@ RSpec.describe Gitlab::ErrorTracking::Processor::ContextPayloadProcessor do
end
it 'merges the context payload into event payload', :aggregate_failures do
- expect(result_hash[:user]).to eq(ip_address: '127.0.0.1', username: 'root')
+ expect(result_hash[:user]).to include(ip_address: '127.0.0.1', username: 'root')
expect(result_hash[:tags])
- .to eq(priority: 'high',
+ .to include(priority: 'high',
locale: 'en',
program: 'test',
feature_category: 'feature_a',
diff --git a/spec/lib/gitlab/legacy_github_import/importer_spec.rb b/spec/lib/gitlab/legacy_github_import/importer_spec.rb
index 56074147854..9a4d7bd996e 100644
--- a/spec/lib/gitlab/legacy_github_import/importer_spec.rb
+++ b/spec/lib/gitlab/legacy_github_import/importer_spec.rb
@@ -290,7 +290,7 @@ RSpec.describe Gitlab::LegacyGithubImport::Importer do
subject { described_class.new(project) }
before do
- project.update(import_type: 'gitea', import_url: "#{repo_root}/foo/group/project.git")
+ project.update!(import_type: 'gitea', import_url: "#{repo_root}/foo/group/project.git")
end
it_behaves_like 'Gitlab::LegacyGithubImport::Importer#execute' do
diff --git a/spec/lib/gitlab/legacy_github_import/issue_formatter_spec.rb b/spec/lib/gitlab/legacy_github_import/issue_formatter_spec.rb
index 4b1e0d2c144..454bab8846c 100644
--- a/spec/lib/gitlab/legacy_github_import/issue_formatter_spec.rb
+++ b/spec/lib/gitlab/legacy_github_import/issue_formatter_spec.rb
@@ -152,7 +152,7 @@ RSpec.describe Gitlab::LegacyGithubImport::IssueFormatter do
context 'when importing a Gitea project' do
before do
- project.update(import_type: 'gitea')
+ project.update!(import_type: 'gitea')
end
it_behaves_like 'Gitlab::LegacyGithubImport::IssueFormatter#attributes'
diff --git a/spec/lib/gitlab/legacy_github_import/milestone_formatter_spec.rb b/spec/lib/gitlab/legacy_github_import/milestone_formatter_spec.rb
index 148b59dedab..64fcc46d304 100644
--- a/spec/lib/gitlab/legacy_github_import/milestone_formatter_spec.rb
+++ b/spec/lib/gitlab/legacy_github_import/milestone_formatter_spec.rb
@@ -92,7 +92,7 @@ RSpec.describe Gitlab::LegacyGithubImport::MilestoneFormatter do
let(:iid_attr) { :id }
before do
- project.update(import_type: 'gitea')
+ project.update!(import_type: 'gitea')
end
it_behaves_like 'Gitlab::LegacyGithubImport::MilestoneFormatter#attributes'
diff --git a/spec/lib/gitlab/legacy_github_import/pull_request_formatter_spec.rb b/spec/lib/gitlab/legacy_github_import/pull_request_formatter_spec.rb
index 3e6b9340d0b..7d8875e36c3 100644
--- a/spec/lib/gitlab/legacy_github_import/pull_request_formatter_spec.rb
+++ b/spec/lib/gitlab/legacy_github_import/pull_request_formatter_spec.rb
@@ -260,7 +260,7 @@ RSpec.describe Gitlab::LegacyGithubImport::PullRequestFormatter do
context 'when importing a Gitea project' do
before do
- project.update(import_type: 'gitea')
+ project.update!(import_type: 'gitea')
end
it_behaves_like 'Gitlab::LegacyGithubImport::PullRequestFormatter#attributes'
diff --git a/spec/lib/gitlab/tracking/standard_context_spec.rb b/spec/lib/gitlab/tracking/standard_context_spec.rb
index 561edbd38f8..dacd08cf12b 100644
--- a/spec/lib/gitlab/tracking/standard_context_spec.rb
+++ b/spec/lib/gitlab/tracking/standard_context_spec.rb
@@ -58,10 +58,16 @@ RSpec.describe Gitlab::Tracking::StandardContext do
end
context 'with extra data' do
- subject { described_class.new(foo: 'bar') }
+ subject { described_class.new(extra_key_1: 'extra value 1', extra_key_2: 'extra value 2') }
- it 'creates a Snowplow context with the given data' do
- expect(snowplow_context.to_json.dig(:data, :foo)).to eq('bar')
+ it 'includes extra data in `extra` hash' do
+ expect(snowplow_context.to_json.dig(:data, :extra)).to eq(extra_key_1: 'extra value 1', extra_key_2: 'extra value 2')
+ end
+ end
+
+ context 'without extra data' do
+ it 'contains an empty `extra` hash' do
+ expect(snowplow_context.to_json.dig(:data, :extra)).to be_empty
end
end
diff --git a/spec/lib/gitlab/tracking_spec.rb b/spec/lib/gitlab/tracking_spec.rb
index c1e69b94406..edc19df5e37 100644
--- a/spec/lib/gitlab/tracking_spec.rb
+++ b/spec/lib/gitlab/tracking_spec.rb
@@ -51,7 +51,7 @@ RSpec.describe Gitlab::Tracking do
expect(Gitlab::Tracking::StandardContext)
.to receive(:new)
- .with(project: project, user: user, namespace: namespace)
+ .with(project: project, user: user, namespace: namespace, extra_key_1: 'extra value 1', extra_key_2: 'extra value 2')
.and_call_original
expect_any_instance_of(klass).to receive(:event) do |_, category, action, args|
@@ -66,7 +66,8 @@ RSpec.describe Gitlab::Tracking do
end
described_class.event('category', 'action', label: 'label', property: 'property', value: 1.5,
- context: [other_context], project: project, user: user, namespace: namespace)
+ context: [other_context], project: project, user: user, namespace: namespace,
+ extra_key_1: 'extra value 1', extra_key_2: 'extra value 2')
end
end
diff --git a/spec/requests/api/ci/runner/jobs_request_post_spec.rb b/spec/requests/api/ci/runner/jobs_request_post_spec.rb
index aced094e219..03412fe1b66 100644
--- a/spec/requests/api/ci/runner/jobs_request_post_spec.rb
+++ b/spec/requests/api/ci/runner/jobs_request_post_spec.rb
@@ -490,6 +490,36 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
{ 'id' => job.id, 'name' => job.name, 'token' => job.token },
{ 'id' => job2.id, 'name' => job2.name, 'token' => job2.token })
end
+
+ describe 'preloading job_artifacts_archive' do
+ context 'when the feature flag is disabled' do
+ before do
+ stub_feature_flags(preload_associations_jobs_request_api_endpoint: false)
+ end
+
+ it 'queries the ci_job_artifacts table multiple times' do
+ expect { request_job }.to exceed_all_query_limit(1).for_model(::Ci::JobArtifact)
+ end
+
+ it 'queries the ci_builds table more than five times' do
+ expect { request_job }.to exceed_all_query_limit(5).for_model(::Ci::Build)
+ end
+ end
+
+ context 'when the feature flag is enabled' do
+ before do
+ stub_feature_flags(preload_associations_jobs_request_api_endpoint: true)
+ end
+
+ it 'queries the ci_job_artifacts table once only' do
+ expect { request_job }.not_to exceed_all_query_limit(1).for_model(::Ci::JobArtifact)
+ end
+
+ it 'queries the ci_builds table five times' do
+ expect { request_job }.not_to exceed_all_query_limit(5).for_model(::Ci::Build)
+ end
+ end
+ end
end
context 'when pipeline have jobs with artifacts' do
diff --git a/spec/serializers/merge_request_poll_cached_widget_entity_spec.rb b/spec/serializers/merge_request_poll_cached_widget_entity_spec.rb
index 380e20905c6..cad3d2e3373 100644
--- a/spec/serializers/merge_request_poll_cached_widget_entity_spec.rb
+++ b/spec/serializers/merge_request_poll_cached_widget_entity_spec.rb
@@ -268,4 +268,49 @@ RSpec.describe MergeRequestPollCachedWidgetEntity do
end
end
end
+
+ describe 'merge_pipeline' do
+ it 'returns nil' do
+ expect(subject[:merge_pipeline]).to be_nil
+ end
+
+ context 'when is merged' do
+ let(:resource) { create(:merged_merge_request, source_project: project, merge_commit_sha: project.commit.id) }
+ let(:pipeline) { create(:ci_empty_pipeline, project: project, ref: resource.target_branch, sha: resource.merge_commit_sha) }
+
+ before do
+ project.add_maintainer(user)
+ end
+
+ it 'returns merge_pipeline' do
+ pipeline.reload
+ pipeline_payload =
+ MergeRequests::PipelineEntity
+ .represent(pipeline, request: request)
+ .as_json
+
+ expect(subject[:merge_pipeline]).to eq(pipeline_payload)
+ end
+
+ context 'when user cannot read pipelines on target project' do
+ before do
+ project.add_guest(user)
+ end
+
+ it 'returns nil' do
+ expect(subject[:merge_pipeline]).to be_nil
+ end
+ end
+
+ context 'when merge_request_cached_merge_pipeline_serializer is disabled' do
+ before do
+ stub_feature_flags(merge_request_cached_merge_pipeline_serializer: false)
+ end
+
+ it 'returns nil' do
+ expect(subject[:merge_pipeline]).to be_nil
+ end
+ end
+ end
+ end
end
diff --git a/spec/serializers/merge_request_poll_widget_entity_spec.rb b/spec/serializers/merge_request_poll_widget_entity_spec.rb
index 3bf4f613167..9618624f226 100644
--- a/spec/serializers/merge_request_poll_widget_entity_spec.rb
+++ b/spec/serializers/merge_request_poll_widget_entity_spec.rb
@@ -6,9 +6,9 @@ RSpec.describe MergeRequestPollWidgetEntity do
include ProjectForksHelper
using RSpec::Parameterized::TableSyntax
- let(:project) { create :project, :repository }
- let(:resource) { create(:merge_request, source_project: project, target_project: project) }
- let(:user) { create(:user) }
+ let_it_be(:project) { create :project, :repository }
+ let_it_be(:resource) { create(:merge_request, source_project: project, target_project: project) }
+ let_it_be(:user) { create(:user) }
let(:request) { double('request', current_user: user, project: project) }
@@ -22,20 +22,33 @@ RSpec.describe MergeRequestPollWidgetEntity do
end
describe 'merge_pipeline' do
+ before do
+ stub_feature_flags(merge_request_cached_merge_pipeline_serializer: false)
+ end
+
it 'returns nil' do
expect(subject[:merge_pipeline]).to be_nil
end
context 'when is merged' do
- let(:resource) { create(:merged_merge_request, source_project: project, merge_commit_sha: project.commit.id) }
- let(:pipeline) { create(:ci_empty_pipeline, project: project, ref: resource.target_branch, sha: resource.merge_commit_sha) }
+ let_it_be(:resource) { create(:merged_merge_request, source_project: project, merge_commit_sha: project.commit.id) }
+ let_it_be(:pipeline) { create(:ci_empty_pipeline, project: project, ref: resource.target_branch, sha: resource.merge_commit_sha) }
before do
project.add_maintainer(user)
end
+ context 'when user cannot read pipelines on target project' do
+ before do
+ project.team.truncate
+ end
+
+ it 'returns nil' do
+ expect(subject[:merge_pipeline]).to be_nil
+ end
+ end
+
it 'returns merge_pipeline' do
- pipeline.reload
pipeline_payload =
MergeRequests::PipelineEntity
.represent(pipeline, request: request)
@@ -44,9 +57,9 @@ RSpec.describe MergeRequestPollWidgetEntity do
expect(subject[:merge_pipeline]).to eq(pipeline_payload)
end
- context 'when user cannot read pipelines on target project' do
+ context 'when merge_request_cached_merge_pipeline_serializer is enabled' do
before do
- project.add_guest(user)
+ stub_feature_flags(merge_request_cached_merge_pipeline_serializer: true)
end
it 'returns nil' do
diff --git a/spec/support/helpers/navbar_structure_helper.rb b/spec/support/helpers/navbar_structure_helper.rb
index e18a708e41c..826108a63a5 100644
--- a/spec/support/helpers/navbar_structure_helper.rb
+++ b/spec/support/helpers/navbar_structure_helper.rb
@@ -29,7 +29,7 @@ module NavbarStructureHelper
)
end
- def insert_container_nav(within)
+ def insert_container_nav
insert_after_sub_nav_item(
_('Package Registry'),
within: _('Packages & Registries'),
@@ -37,11 +37,19 @@ module NavbarStructureHelper
)
end
- def insert_dependency_proxy_nav(within)
+ def insert_dependency_proxy_nav
insert_after_sub_nav_item(
_('Package Registry'),
within: _('Packages & Registries'),
new_sub_nav_item_name: _('Dependency Proxy')
)
end
+
+ def insert_infrastructure_registry_nav
+ insert_after_sub_nav_item(
+ _('Package Registry'),
+ within: _('Packages & Registries'),
+ new_sub_nav_item_name: _('Infrastructure Registry')
+ )
+ end
end
diff --git a/spec/support/matchers/exceed_query_limit.rb b/spec/support/matchers/exceed_query_limit.rb
index 7a66eff3a41..b48c7f905b2 100644
--- a/spec/support/matchers/exceed_query_limit.rb
+++ b/spec/support/matchers/exceed_query_limit.rb
@@ -20,6 +20,11 @@ module ExceedQueryLimitHelpers
self
end
+ def for_model(model)
+ table = model.table_name if model < ActiveRecord::Base
+ for_query(/(FROM|UPDATE|INSERT INTO|DELETE FROM)\s+"#{table}"/)
+ end
+
def show_common_queries
@show_common_queries = true
self
diff --git a/spec/support/shared_examples/features/sidebar_shared_examples.rb b/spec/support/shared_examples/features/sidebar_shared_examples.rb
new file mode 100644
index 00000000000..558536a80c6
--- /dev/null
+++ b/spec/support/shared_examples/features/sidebar_shared_examples.rb
@@ -0,0 +1,165 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'issue boards sidebar' do
+ include MobileHelpers
+
+ before do
+ first_card.click
+ end
+
+ it 'shows sidebar when clicking issue' do
+ expect(page).to have_selector('.issue-boards-sidebar')
+ end
+
+ it 'closes sidebar when clicking issue' do
+ expect(page).to have_selector('.issue-boards-sidebar')
+
+ first_card.click
+
+ expect(page).not_to have_selector('.issue-boards-sidebar')
+ end
+
+ it 'shows issue details when sidebar is open', :aggregate_failures do
+ page.within('.issue-boards-sidebar') do
+ expect(page).to have_content(issue.title)
+ expect(page).to have_content(issue.to_reference)
+ end
+ end
+
+ context 'when clicking close button' do
+ before do
+ find("[data-testid='sidebar-drawer'] .gl-drawer-close-button").click
+ end
+
+ it 'unhighlights the active issue card' do
+ expect(first_card[:class]).not_to include('is-active')
+ expect(first_card[:class]).not_to include('multi-select')
+ end
+
+ it 'closes sidebar when clicking close button' do
+ expect(page).not_to have_selector('.issue-boards-sidebar')
+ end
+ end
+
+ context 'in notifications subscription' do
+ it 'displays notifications toggle', :aggregate_failures do
+ page.within('[data-testid="sidebar-notifications"]') do
+ expect(page).to have_selector('[data-testid="notification-subscribe-toggle"]')
+ expect(page).to have_content('Notifications')
+ expect(page).not_to have_content('Notifications have been disabled by the project or group owner')
+ end
+ end
+
+ it 'shows toggle as on then as off as user toggles to subscribe and unsubscribe', :aggregate_failures do
+ toggle = find('[data-testid="notification-subscribe-toggle"]')
+
+ toggle.click
+
+ expect(toggle).to have_css("button.is-checked")
+
+ toggle.click
+
+ expect(toggle).not_to have_css("button.is-checked")
+ end
+
+ context 'when notifications have been disabled' do
+ before do
+ project.update_attribute(:emails_disabled, true)
+
+ refresh_and_click_first_card
+ end
+
+ it 'displays a message that notifications have been disabled' do
+ page.within('[data-testid="sidebar-notifications"]') do
+ expect(page).not_to have_selector('[data-testid="notification-subscribe-toggle"]')
+ expect(page).to have_content('Notifications have been disabled by the project or group owner')
+ end
+ end
+ end
+ end
+
+ context 'in time tracking' do
+ it 'displays time tracking feature with default message' do
+ page.within('[data-testid="time-tracker"]') do
+ expect(page).to have_content('Time tracking')
+ expect(page).to have_content('No estimate or time spent')
+ end
+ end
+
+ context 'when only spent time is recorded' do
+ before do
+ issue.timelogs.create!(time_spent: 3600, user: user)
+
+ refresh_and_click_first_card
+ end
+
+ it 'shows the total time spent only' do
+ page.within('[data-testid="time-tracker"]') do
+ expect(page).to have_content('Spent: 1h')
+ expect(page).not_to have_content('Estimated')
+ end
+ end
+ end
+
+ context 'when only estimated time is recorded' do
+ before do
+ issue.update!(time_estimate: 3600)
+
+ refresh_and_click_first_card
+ end
+
+ it 'shows the estimated time only', :aggregate_failures do
+ page.within('[data-testid="time-tracker"]') do
+ expect(page).to have_content('Estimated: 1h')
+ expect(page).not_to have_content('Spent')
+ end
+ end
+ end
+
+ context 'when estimated and spent times are available' do
+ before do
+ issue.timelogs.create!(time_spent: 1800, user: user)
+ issue.update!(time_estimate: 3600)
+
+ refresh_and_click_first_card
+ end
+
+ it 'shows time tracking progress bar' do
+ page.within('[data-testid="time-tracker"]') do
+ expect(page).to have_selector('[data-testid="timeTrackingComparisonPane"]')
+ end
+ end
+
+ it 'shows both estimated and spent time text', :aggregate_failures do
+ page.within('[data-testid="time-tracker"]') do
+ expect(page).to have_content('Spent 30m')
+ expect(page).to have_content('Est 1h')
+ end
+ end
+ end
+
+ context 'when limitedToHours instance option is turned on' do
+ before do
+ # 3600+3600*24 = 1d 1h or 25h
+ issue.timelogs.create!(time_spent: 3600 + 3600 * 24, user: user)
+ stub_application_setting(time_tracking_limit_to_hours: true)
+
+ refresh_and_click_first_card
+ end
+
+ it 'shows the total time spent only' do
+ page.within('[data-testid="time-tracker"]') do
+ expect(page).to have_content('Spent: 25h')
+ end
+ end
+ end
+ end
+
+ def refresh_and_click_first_card
+ page.refresh
+
+ wait_for_requests
+
+ first_card.click
+ end
+end
diff --git a/spec/support_specs/matchers/exceed_query_limit_helpers_spec.rb b/spec/support_specs/matchers/exceed_query_limit_helpers_spec.rb
index 6d8d9ba0754..67d87fe3c2f 100644
--- a/spec/support_specs/matchers/exceed_query_limit_helpers_spec.rb
+++ b/spec/support_specs/matchers/exceed_query_limit_helpers_spec.rb
@@ -225,6 +225,16 @@ RSpec.describe ExceedQueryLimitHelpers do
expect(test_matcher.actual_count).to eq(2)
end
+ it 'can filter specific models' do
+ test_matcher = TestMatcher.new.for_model(TestQueries)
+ test_matcher.verify_count do
+ TestQueries.first
+ TestQueries.connection.execute('select 1')
+ end
+
+ expect(test_matcher.actual_count).to eq(1)
+ end
+
it 'can ignore specific queries' do
test_matcher = TestMatcher.new.ignoring(/foobar/)
test_matcher.verify_count do