diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-10-23 21:11:07 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-10-23 21:11:07 +0300 |
commit | c5da163db1c10676b1a01a898b7b3a4506e65b89 (patch) | |
tree | 0110bf1518c8049cddab8d62e77d4f7dad2478a7 /app | |
parent | 750a63ac4cc7acbecff3b8d22232cb1c15af34fb (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
21 files changed, 215 insertions, 92 deletions
diff --git a/app/assets/javascripts/ci/catalog/components/details/ci_resource_details.vue b/app/assets/javascripts/ci/catalog/components/details/ci_resource_details.vue index c0feb52c185..026a30988fd 100644 --- a/app/assets/javascripts/ci/catalog/components/details/ci_resource_details.vue +++ b/app/assets/javascripts/ci/catalog/components/details/ci_resource_details.vue @@ -30,12 +30,12 @@ export default { <template> <gl-tabs> - <gl-tab v-if="glFeatures.ciCatalogComponentsTab" :title="$options.i18n.tabs.components" lazy> - <ci-resource-components :resource-id="resourceId" - /></gl-tab> <gl-tab :title="$options.i18n.tabs.readme" lazy> <ci-resource-readme :resource-id="resourceId" /> </gl-tab> + <gl-tab v-if="glFeatures.ciCatalogComponentsTab" :title="$options.i18n.tabs.components" lazy> + <ci-resource-components :resource-id="resourceId" + /></gl-tab> </gl-tabs> </template> <style></style> diff --git a/app/assets/javascripts/ci/constants.js b/app/assets/javascripts/ci/constants.js index 5b60528f521..138a44a8dd0 100644 --- a/app/assets/javascripts/ci/constants.js +++ b/app/assets/javascripts/ci/constants.js @@ -37,4 +37,5 @@ export const TRACKING_CATEGORIES = { search: 'pipelines_filtered_search', failed: 'pipeline_failed_jobs_tab', tests: 'pipeline_tests_tab', + listbox: 'pipeline_id_iid_listbox', }; diff --git a/app/assets/javascripts/ci/pipeline_editor/components/file_nav/branch_switcher.vue b/app/assets/javascripts/ci/pipeline_editor/components/file_nav/branch_switcher.vue index 221a45d4d9a..21e21d54758 100644 --- a/app/assets/javascripts/ci/pipeline_editor/components/file_nav/branch_switcher.vue +++ b/app/assets/javascripts/ci/pipeline_editor/components/file_nav/branch_switcher.vue @@ -1,13 +1,5 @@ <script> -import { - GlDropdown, - GlDropdownItem, - GlDropdownSectionHeader, - GlInfiniteScroll, - GlLoadingIcon, - GlSearchBoxByType, - GlTooltipDirective, -} from '@gitlab/ui'; +import { GlCollapsibleListbox, GlTooltipDirective } from '@gitlab/ui'; import { produce } from 'immer'; import { historyPushState } from '~/lib/utils/common_utils'; import { setUrlParams } from '~/lib/utils/url_utility'; @@ -25,17 +17,11 @@ import getLastCommitBranch from '~/ci/pipeline_editor/graphql/queries/client/las export default { i18n: { dropdownHeader: __('Switch branch'), - title: __('Branches'), fetchError: __('Unable to fetch branch list for this project.'), }, inputDebounce: BRANCH_SEARCH_DEBOUNCE, components: { - GlDropdown, - GlDropdownItem, - GlDropdownSectionHeader, - GlInfiniteScroll, - GlLoadingIcon, - GlSearchBoxByType, + GlCollapsibleListbox, }, directives: { GlTooltip: GlTooltipDirective, @@ -66,6 +52,7 @@ export default { pageCounter: 0, searchTerm: '', lastCommitBranch: '', + infiniteScrollLoading: false, }; }, apollo: { @@ -112,6 +99,18 @@ export default { }, }, computed: { + infiniteScrollEnabled() { + return this.availableBranches.length > 0; + }, + branchesData() { + return this.availableBranches.map((branch) => ({ + text: branch, + extraAttrs: { + 'data-qa-selector': 'branch_menu_item_button', + }, + value: branch, + })); + }, availableBranchesVariables() { if (this.searchTerm.length > 0) { return { @@ -128,7 +127,7 @@ export default { enableBranchSwitcher() { return this.availableBranches.length > 0 || this.searchTerm.length > 0; }, - isBranchesLoading() { + areBranchesLoading() { return this.$apollo.queries.availableBranches.loading; }, }, @@ -143,7 +142,7 @@ export default { // if there is no searchPattern, paginate by {paginationLimit} branches fetchNextBranches() { if ( - this.isBranchesLoading || + this.areBranchesLoading || this.searchTerm.length > 0 || this.availableBranches.length >= this.totalBranches ) { @@ -178,16 +177,14 @@ export default { this.$emit('refetchContent'); }, selectBranch(newBranch) { - if (newBranch !== this.currentBranch) { - // If there are unsaved changes, we want to show the user - // a modal to confirm what to do with these before changing - // branches. - if (this.hasUnsavedChanges) { - this.branchSelected = newBranch; - this.$emit('select-branch', newBranch); - } else { - this.changeBranch(newBranch); - } + // If there are unsaved changes, we want to show the user + // a modal to confirm what to do with these before changing + // branches. + if (this.hasUnsavedChanges) { + this.branchSelected = newBranch; + this.$emit('select-branch', newBranch); + } else { + this.changeBranch(newBranch); } }, async setSearchTerm(newSearchTerm) { @@ -211,41 +208,23 @@ export default { </script> <template> - <gl-dropdown + <gl-collapsible-listbox + v-model="currentBranch" v-gl-tooltip.hover + data-qa-selector="branch_selector_button" + searchable + :items="branchesData" :title="$options.i18n.dropdownHeader" :header-text="$options.i18n.dropdownHeader" - :text="currentBranch" + :toggle-text="currentBranch" :disabled="!enableBranchSwitcher" icon="branch" data-testid="branch-selector" - > - <gl-search-box-by-type :debounce="$options.inputDebounce" @input="setSearchTerm" /> - <gl-dropdown-section-header> - {{ $options.i18n.title }} - </gl-dropdown-section-header> - - <gl-infinite-scroll - :fetched-items="availableBranches.length" - :max-list-height="250" - @bottomReached="fetchNextBranches" - > - <template #items> - <gl-dropdown-item - v-for="branch in availableBranches" - :key="branch" - :is-checked="currentBranch === branch" - is-check-item - @click="selectBranch(branch)" - > - {{ branch }} - </gl-dropdown-item> - </template> - <template #default> - <gl-dropdown-item v-if="isBranchesLoading" key="loading"> - <gl-loading-icon size="lg" /> - </gl-dropdown-item> - </template> - </gl-infinite-scroll> - </gl-dropdown> + :no-results-text="$options.i18n.fetchError" + :infinite-scroll-loading="areBranchesLoading" + :infinite-scroll="infiniteScrollEnabled" + @select="selectBranch" + @search="setSearchTerm" + @bottom-reached="fetchNextBranches" + /> </template> diff --git a/app/assets/javascripts/ci/pipelines_page/pipelines.vue b/app/assets/javascripts/ci/pipelines_page/pipelines.vue index c4db0ecd05a..98e005a162f 100644 --- a/app/assets/javascripts/ci/pipelines_page/pipelines.vue +++ b/app/assets/javascripts/ci/pipelines_page/pipelines.vue @@ -306,6 +306,12 @@ export default { }, changeVisibilityPipelineIDType(idType) { this.visibilityPipelineIdType = idType; + if (idType === PIPELINE_IID_KEY) { + this.track('pipelines_display_options', { + label: TRACKING_CATEGORIES.listbox, + property: idType, + }); + } if (isLoggedIn()) { this.saveVisibilityPipelineIDType(idType); diff --git a/app/assets/javascripts/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue b/app/assets/javascripts/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue index 346384e3023..d39e4d2ee42 100644 --- a/app/assets/javascripts/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue +++ b/app/assets/javascripts/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue @@ -292,7 +292,9 @@ export default { this.recentSearchesService.save(resultantSearches); this.recentSearches = []; }, - handleFilterSubmit() { + async handleFilterSubmit() { + this.blurSearchInput(); + await this.$nextTick(); const filterTokens = uniqueTokens(this.filterValue); this.filterValue = filterTokens; @@ -309,7 +311,6 @@ export default { // https://gitlab.com/gitlab-org/gitlab-foss/issues/30821 }); } - this.blurSearchInput(); this.$emit('onFilter', this.removeQuotesEnclosure(filterTokens)); }, historyTokenOptionTitle(historyToken) { diff --git a/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/base_token.vue b/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/base_token.vue index 23de8dd5596..3857dd9c55d 100644 --- a/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/base_token.vue +++ b/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/base_token.vue @@ -7,9 +7,10 @@ import { GlDropdownText, GlLoadingIcon, } from '@gitlab/ui'; -import { debounce } from 'lodash'; +import { debounce, last } from 'lodash'; import { stripQuotes } from '~/lib/utils/text_utility'; +import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import { DEBOUNCE_DELAY, FILTERS_NONE_ANY, OPERATOR_NOT, OPERATOR_OR } from '../constants'; import { getRecentlyUsedSuggestions, setTokenValueToRecentlyUsed } from '../filtered_search_utils'; @@ -22,6 +23,7 @@ export default { GlDropdownText, GlLoadingIcon, }, + mixins: [glFeatureFlagMixin()], props: { config: { type: Object, @@ -70,6 +72,11 @@ export default { required: false, default: undefined, }, + multiSelectValues: { + type: Array, + required: false, + default: () => [], + }, }, data() { return { @@ -94,7 +101,11 @@ export default { return this.preloadedSuggestions.map((tokenValue) => tokenValue[this.valueIdentifier]); }, activeTokenValue() { - return this.getActiveTokenValue(this.suggestions, this.value.data); + const data = + this.glFeatures.groupMultiSelectTokens && Array.isArray(this.value.data) + ? last(this.value.data) + : this.value.data; + return this.getActiveTokenValue(this.suggestions, data); }, availableDefaultSuggestions() { if ([OPERATOR_NOT, OPERATOR_OR].includes(this.value.operator)) { @@ -146,10 +157,14 @@ export default { watch: { active: { immediate: true, - handler(newValue) { - if (!newValue && !this.suggestions.length) { - const search = this.searchTerm ? this.searchTerm : this.value.data; - this.$emit('fetch-suggestions', search); + handler(active) { + if (!active && !this.suggestions.length) { + // data could be a string or an array of strings + const selectedItems = [this.value.data].flat(); + selectedItems.forEach((item) => { + const search = this.searchTerm ? this.searchTerm : item; + this.$emit('fetch-suggestions', search); + }); } }, }, @@ -163,6 +178,9 @@ export default { }, methods: { handleInput: debounce(function debouncedSearch({ data, operator }) { + // in multiSelect mode, data could be an array + if (Array.isArray(data)) return; + // Prevent fetching suggestions when data or operator is not present if (data || operator) { this.searchKey = data; @@ -181,8 +199,11 @@ export default { } }, DEBOUNCE_DELAY), handleTokenValueSelected(selectedValue) { - const activeTokenValue = this.getActiveTokenValue(this.suggestions, selectedValue); + if (this.glFeatures.groupMultiSelectTokens) { + this.$emit('token-selected', selectedValue); + } + const activeTokenValue = this.getActiveTokenValue(this.suggestions, selectedValue); // Make sure that; // 1. Recently used values feature is enabled // 2. User has actually selected a value @@ -210,6 +231,7 @@ export default { :config="config" :value="value" :active="active" + :multi-select-values="multiSelectValues" v-bind="$attrs" v-on="$listeners" @input="handleInput" diff --git a/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/user_token.vue b/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/user_token.vue index 4601287b417..c5326ead60d 100644 --- a/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/user_token.vue +++ b/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/user_token.vue @@ -1,11 +1,12 @@ <script> -import { GlAvatar, GlFilteredSearchSuggestion } from '@gitlab/ui'; +import { GlAvatar, GlIcon, GlIntersperse, GlFilteredSearchSuggestion } from '@gitlab/ui'; import { compact } from 'lodash'; import { createAlert } from '~/alert'; import { __ } from '~/locale'; import { WORKSPACE_GROUP, WORKSPACE_PROJECT } from '~/issues/constants'; import usersAutocompleteQuery from '~/graphql_shared/queries/users_autocomplete.query.graphql'; +import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import { OPTIONS_NONE_ANY } from '../constants'; import BaseToken from './base_token.vue'; @@ -14,8 +15,11 @@ export default { components: { BaseToken, GlAvatar, + GlIcon, + GlIntersperse, GlFilteredSearchSuggestion, }, + mixins: [glFeatureFlagMixin()], props: { config: { type: Object, @@ -32,8 +36,11 @@ export default { }, data() { return { + // current users visible in list users: this.config.initialUsers || [], + allUsers: this.config.initialUsers || [], loading: false, + selectedUsernames: [], }; }, computed: { @@ -49,13 +56,69 @@ export default { fetchUsersQuery() { return this.config.fetchUsers ? this.config.fetchUsers : this.fetchUsersBySearchTerm; }, + multiSelectEnabled() { + return this.config.multiSelect && this.glFeatures.groupMultiSelectTokens; + }, + }, + watch: { + value: { + deep: true, + immediate: true, + handler(newValue) { + const { data } = newValue; + + if (!this.multiSelectEnabled) { + return; + } + + // don't add empty values to selectedUsernames + if (!data) { + return; + } + + if (Array.isArray(data)) { + this.selectedUsernames = data; + // !active so we don't add strings while searching, e.g. r, ro, roo + // !includes so we don't add the same usernames (if @input is emitted twice) + } else if (!this.active && !this.selectedUsernames.includes(data)) { + this.selectedUsernames = this.selectedUsernames.concat(data); + } + }, + }, }, methods: { getActiveUser(users, data) { return users.find((user) => user.username.toLowerCase() === data.toLowerCase()); }, getAvatarUrl(user) { - return user.avatarUrl || user.avatar_url; + return user?.avatarUrl || user?.avatar_url; + }, + displayNameFor(username) { + return this.getActiveUser(this.allUsers, username)?.name || `@${username}`; + }, + avatarFor(username) { + const user = this.getActiveUser(this.allUsers, username); + return this.getAvatarUrl(user); + }, + addCheckIcon(username) { + return this.multiSelectEnabled && this.selectedUsernames.includes(username); + }, + addPadding(username) { + return this.multiSelectEnabled && !this.selectedUsernames.includes(username); + }, + handleSelected(username) { + if (!this.multiSelectEnabled) { + return; + } + + const index = this.selectedUsernames.indexOf(username); + if (index > -1) { + this.selectedUsernames.splice(index, 1); + } else { + this.selectedUsernames.push(username); + } + + this.$emit('input', { ...this.value, data: '' }); }, fetchUsersBySearchTerm(search) { return this.$apollo @@ -79,6 +142,7 @@ export default { // TODO: rm when completed https://gitlab.com/gitlab-org/gitlab/-/issues/345756 this.users = Array.isArray(res) ? compact(res) : compact(res.data); + this.allUsers = this.allUsers.concat(this.users); }) .catch(() => createAlert({ @@ -103,18 +167,32 @@ export default { :get-active-token-value="getActiveUser" :default-suggestions="defaultUsers" :preloaded-suggestions="preloadedUsers" + :multi-select-values="selectedUsernames" v-bind="$attrs" @fetch-suggestions="fetchUsers" + @token-selected="handleSelected" v-on="$listeners" > <template #view="{ viewTokenProps: { inputValue, activeTokenValue } }"> - <gl-avatar - v-if="activeTokenValue" - :size="16" - :src="getAvatarUrl(activeTokenValue)" - class="gl-mr-2" - /> - {{ activeTokenValue ? activeTokenValue.name : inputValue }} + <gl-intersperse v-if="multiSelectEnabled" separator=","> + <span + v-for="(username, index) in selectedUsernames" + :key="username" + :class="{ 'gl-ml-2': index > 0 }" + ><gl-avatar :size="16" :src="avatarFor(username)" class="gl-mr-1" />{{ + displayNameFor(username) + }}</span + > + </gl-intersperse> + <template v-else> + <gl-avatar + v-if="activeTokenValue" + :size="16" + :src="getAvatarUrl(activeTokenValue)" + class="gl-mr-2" + /> + {{ activeTokenValue ? activeTokenValue.name : inputValue }} + </template> </template> <template #suggestions-list="{ suggestions }"> <gl-filtered-search-suggestion @@ -122,7 +200,15 @@ export default { :key="user.username" :value="user.username" > - <div class="gl-display-flex"> + <div + class="gl-display-flex gl-align-items-center" + :class="{ 'gl-pl-6': addPadding(user.username) }" + > + <gl-icon + v-if="addCheckIcon(user.username)" + name="check" + class="gl-mr-3 gl-text-secondary gl-flex-shrink-0" + /> <gl-avatar :size="32" :src="getAvatarUrl(user)" /> <div> <div>{{ user.name }}</div> diff --git a/app/assets/javascripts/work_items/components/work_item_labels.vue b/app/assets/javascripts/work_items/components/work_item_labels.vue index 3cdbf816421..7a5d3b1155f 100644 --- a/app/assets/javascripts/work_items/components/work_item_labels.vue +++ b/app/assets/javascripts/work_items/components/work_item_labels.vue @@ -3,7 +3,8 @@ import { GlTokenSelector, GlLabel, GlSkeletonLoader } from '@gitlab/ui'; import { debounce, uniqueId, without } from 'lodash'; import { getIdFromGraphQLId } from '~/graphql_shared/utils'; import Tracking from '~/tracking'; -import labelSearchQuery from '~/sidebar/components/labels/labels_select_widget/graphql/project_labels.query.graphql'; +import groupLabelsQuery from '~/sidebar/components/labels/labels_select_widget/graphql/group_labels.query.graphql'; +import projectLabelsQuery from '~/sidebar/components/labels/labels_select_widget/graphql/project_labels.query.graphql'; import LabelItem from '~/sidebar/components/labels/labels_select_widget/label_item.vue'; import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants'; import { isScopedLabel } from '~/lib/utils/common_utils'; @@ -90,7 +91,9 @@ export default { }, }, searchLabels: { - query: labelSearchQuery, + query() { + return this.isGroup ? groupLabelsQuery : projectLabelsQuery; + }, variables() { return { fullPath: this.fullPath, diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb index 188a8540a58..a0997484c58 100644 --- a/app/controllers/dashboard_controller.rb +++ b/app/controllers/dashboard_controller.rb @@ -14,6 +14,7 @@ class DashboardController < Dashboard::ApplicationController before_action only: :issues do push_frontend_feature_flag(:frontend_caching) + push_frontend_feature_flag(:group_multi_select_tokens) end before_action only: :merge_requests do diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb index edc590e1370..83c4efa5a42 100644 --- a/app/controllers/groups_controller.rb +++ b/app/controllers/groups_controller.rb @@ -37,6 +37,7 @@ class GroupsController < Groups::ApplicationController push_frontend_feature_flag(:frontend_caching, group) push_force_frontend_feature_flag(:work_items, group.work_items_feature_flag_enabled?) push_frontend_feature_flag(:issues_grid_view) + push_frontend_feature_flag(:group_multi_select_tokens, group) end before_action only: :merge_requests do diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb index ed1712ac714..40e1b846268 100644 --- a/app/controllers/projects/issues_controller.rb +++ b/app/controllers/projects/issues_controller.rb @@ -60,6 +60,7 @@ class Projects::IssuesController < Projects::ApplicationController before_action only: [:index, :service_desk] do push_frontend_feature_flag(:or_issuable_queries, project) push_frontend_feature_flag(:frontend_caching, project&.group) + push_frontend_feature_flag(:group_multi_select_tokens, project) end before_action only: :show do diff --git a/app/graphql/types/merge_request_type.rb b/app/graphql/types/merge_request_type.rb index e6625e44508..9dca82f1750 100644 --- a/app/graphql/types/merge_request_type.rb +++ b/app/graphql/types/merge_request_type.rb @@ -106,7 +106,8 @@ module Types null: false, description: 'Status of all mergeability checks of the merge request.', method: :all_mergeability_checks_results, - alpha: { milestone: '16.5' } + alpha: { milestone: '16.5' }, + calls_gitaly: true field :mergeable_discussions_state, GraphQL::Types::Boolean, null: true, calls_gitaly: true, diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index d9726e76c4b..e22739f2dc8 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -1386,7 +1386,7 @@ class MergeRequest < ApplicationRecord end def mergeable_discussions_state? - return true unless project.only_allow_merge_if_all_discussions_are_resolved?(inherit_group_setting: true) + return true unless only_allow_merge_if_all_discussions_are_resolved? unresolved_notes.none?(&:to_be_resolved?) end @@ -1566,8 +1566,16 @@ class MergeRequest < ApplicationRecord access.can_push_to_branch?(target_branch) end + def only_allow_merge_if_pipeline_succeeds? + project.only_allow_merge_if_pipeline_succeeds?(inherit_group_setting: true) + end + + def only_allow_merge_if_all_discussions_are_resolved? + project.only_allow_merge_if_all_discussions_are_resolved?(inherit_group_setting: true) + end + def mergeable_ci_state? - return true unless project.only_allow_merge_if_pipeline_succeeds?(inherit_group_setting: true) + return true unless only_allow_merge_if_pipeline_succeeds? return false unless actual_head_pipeline return true if project.allow_merge_on_skipped_pipeline?(inherit_group_setting: true) && actual_head_pipeline.skipped? diff --git a/app/models/users/phone_number_validation.rb b/app/models/users/phone_number_validation.rb index e033445d76b..27f13845102 100644 --- a/app/models/users/phone_number_validation.rb +++ b/app/models/users/phone_number_validation.rb @@ -33,6 +33,7 @@ module Users validates :telesign_reference_xid, length: { maximum: 255 } scope :for_user, -> (user_id) { where(user_id: user_id) } + scope :by_reference_id, ->(reference_id) { find_by(telesign_reference_xid: reference_id) } def self.related_to_banned_user?(international_dial_code, phone_number) joins(:banned_user).where( diff --git a/app/services/merge_requests/mergeability/check_base_service.rb b/app/services/merge_requests/mergeability/check_base_service.rb index e1c4d751296..b8a275b6c32 100644 --- a/app/services/merge_requests/mergeability/check_base_service.rb +++ b/app/services/merge_requests/mergeability/check_base_service.rb @@ -42,6 +42,11 @@ module MergeRequests .failed(payload: default_payload(args)) end + def inactive(**args) + Gitlab::MergeRequests::Mergeability::CheckResult + .inactive(payload: default_payload(args)) + end + def default_payload(args) args.merge(identifier: self.class.identifier) end diff --git a/app/services/merge_requests/mergeability/check_ci_status_service.rb b/app/services/merge_requests/mergeability/check_ci_status_service.rb index f7fa3259d97..b4e60e964b7 100644 --- a/app/services/merge_requests/mergeability/check_ci_status_service.rb +++ b/app/services/merge_requests/mergeability/check_ci_status_service.rb @@ -7,6 +7,8 @@ module MergeRequests end def execute + return inactive unless merge_request.only_allow_merge_if_pipeline_succeeds? + if merge_request.mergeable_ci_state? success else diff --git a/app/services/merge_requests/mergeability/check_discussions_status_service.rb b/app/services/merge_requests/mergeability/check_discussions_status_service.rb index 34db5f8a944..f9cff5d1e5f 100644 --- a/app/services/merge_requests/mergeability/check_discussions_status_service.rb +++ b/app/services/merge_requests/mergeability/check_discussions_status_service.rb @@ -7,6 +7,8 @@ module MergeRequests end def execute + return inactive unless merge_request.only_allow_merge_if_all_discussions_are_resolved? + if merge_request.mergeable_discussions_state? success else diff --git a/app/services/merge_requests/mergeability/check_rebase_status_service.rb b/app/services/merge_requests/mergeability/check_rebase_status_service.rb index 2163fec8bd6..02cd0587be0 100644 --- a/app/services/merge_requests/mergeability/check_rebase_status_service.rb +++ b/app/services/merge_requests/mergeability/check_rebase_status_service.rb @@ -8,6 +8,8 @@ module MergeRequests end def execute + return inactive unless merge_request.project.ff_merge_must_be_possible? + if merge_request.should_be_rebased? failure(reason: failure_reason) else diff --git a/app/services/merge_requests/mergeability/detailed_merge_status_service.rb b/app/services/merge_requests/mergeability/detailed_merge_status_service.rb index 86c8122604c..92f0fb0429c 100644 --- a/app/services/merge_requests/mergeability/detailed_merge_status_service.rb +++ b/app/services/merge_requests/mergeability/detailed_merge_status_service.rb @@ -18,10 +18,10 @@ module MergeRequests # If everything else is mergeable, but CI is not, the frontend expects two potential states to be returned # See discussion: gitlab.com/gitlab-org/gitlab/-/merge_requests/96778#note_1093063523 - if check_ci_results.success? - :mergeable - else + if check_ci_results.failed? ci_check_failure_reason + else + :mergeable end else check_results.payload[:failure_reason] diff --git a/app/services/merge_requests/mergeability/run_checks_service.rb b/app/services/merge_requests/mergeability/run_checks_service.rb index 5150c03d0a3..92f3e5e951a 100644 --- a/app/services/merge_requests/mergeability/run_checks_service.rb +++ b/app/services/merge_requests/mergeability/run_checks_service.rb @@ -65,7 +65,7 @@ module MergeRequests end def all_results_success? - results.all?(&:success?) + results.none?(&:failed?) end def failure_reason diff --git a/app/views/projects/readme_templates/default.md.tt b/app/views/projects/readme_templates/default.md.tt index 779b87336ea..7432918be21 100644 --- a/app/views/projects/readme_templates/default.md.tt +++ b/app/views/projects/readme_templates/default.md.tt @@ -38,7 +38,7 @@ git push -uf origin <%= params[:default_branch] %> Use the built-in continuous integration in GitLab. - [ ] [Get started with GitLab CI/CD](https://docs.gitlab.com/ee/ci/quick_start/index.html) -- [ ] [Analyze your code for known vulnerabilities with Static Application Security Testing(SAST)](https://docs.gitlab.com/ee/user/application_security/sast/) +- [ ] [Analyze your code for known vulnerabilities with Static Application Security Testing (SAST)](https://docs.gitlab.com/ee/user/application_security/sast/) - [ ] [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/requirements.html) - [ ] [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/ee/user/clusters/agent/) - [ ] [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html) @@ -47,9 +47,10 @@ Use the built-in continuous integration in GitLab. # Editing this README -When you're ready to make this README your own, just edit this file and use the handy template below (or feel free to structure it however you want - this is just a starting point!). Thank you to [makeareadme.com](https://www.makeareadme.com/) for this template. +When you're ready to make this README your own, just edit this file and use the handy template below (or feel free to structure it however you want - this is just a starting point!). Thanks to [makeareadme.com](https://www.makeareadme.com/) for this template. ## Suggestions for a good README + Every project is different, so consider which of these sections apply to yours. The sections used in the template are suggestions for most open source projects. Also keep in mind that while a README can be too long and detailed, too long is better than too short. If you think your README is too long, consider utilizing another form of documentation rather than cutting out information. ## Name |