diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-05-13 18:10:32 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-05-13 18:10:32 +0000 |
commit | 561d1f41b5803b90ef4baf0d129e28dde3fc2f25 (patch) | |
tree | eca91620c72ace1e30e339c931f65b3de78a34ba | |
parent | e958867b2e341329243be8db0c262233ae1238c0 (diff) | |
download | gitlab-ce-561d1f41b5803b90ef4baf0d129e28dde3fc2f25.tar.gz |
Add latest changes from gitlab-org/gitlab@master
80 files changed, 769 insertions, 1210 deletions
diff --git a/app/assets/javascripts/batch_comments/components/preview_dropdown.vue b/app/assets/javascripts/batch_comments/components/preview_dropdown.vue index 625cd9858fb..91b3b6a685c 100644 --- a/app/assets/javascripts/batch_comments/components/preview_dropdown.vue +++ b/app/assets/javascripts/batch_comments/components/preview_dropdown.vue @@ -35,7 +35,7 @@ export default { <gl-dropdown :header-text="n__('%d pending comment', '%d pending comments', draftsCount)" dropup - toggle-class="qa-review-preview-toggle" + data-qa-selector="review_preview_dropdown" > <template #button-content> {{ __('Pending comments') }} diff --git a/app/assets/javascripts/diffs/components/commit_item.vue b/app/assets/javascripts/diffs/components/commit_item.vue index 63239728390..820c64a9502 100644 --- a/app/assets/javascripts/diffs/components/commit_item.vue +++ b/app/assets/javascripts/diffs/components/commit_item.vue @@ -138,7 +138,7 @@ export default { /> </div> <div class="commit-detail flex-list"> - <div class="commit-content qa-commit-content"> + <div class="commit-content" data-qa-selector="commit_content"> <a :href="commit.commit_url" class="commit-row-message item-title" diff --git a/app/assets/javascripts/diffs/components/diff_row.vue b/app/assets/javascripts/diffs/components/diff_row.vue index c5770a35b42..d4a1a9e0e46 100644 --- a/app/assets/javascripts/diffs/components/diff_row.vue +++ b/app/assets/javascripts/diffs/components/diff_row.vue @@ -206,6 +206,7 @@ export default { :class="classNameMapCellLeft" data-testid="left-line-number" class="diff-td diff-line-num" + data-qa-selector="new_diff_line_link" > <template v-if="!isLeftConflictMarker"> <span @@ -220,7 +221,7 @@ export default { tabindex="0" :draggable="!line.left.commentsDisabled && glFeatures.dragCommentSelection" type="button" - class="add-diff-note unified-diff-components-diff-note-button note-button js-add-diff-note-button qa-diff-comment" + class="add-diff-note unified-diff-components-diff-note-button note-button js-add-diff-note-button" data-qa-selector="diff_comment_button" :class="{ 'gl-cursor-grab': dragging }" :disabled="line.left.commentsDisabled" @@ -327,7 +328,7 @@ export default { tabindex="0" :draggable="!line.right.commentsDisabled && glFeatures.dragCommentSelection" type="button" - class="add-diff-note unified-diff-components-diff-note-button note-button js-add-diff-note-button qa-diff-comment" + class="add-diff-note unified-diff-components-diff-note-button note-button js-add-diff-note-button" :class="{ 'gl-cursor-grab': dragging }" :disabled="line.right.commentsDisabled" :aria-disabled="line.right.commentsDisabled" diff --git a/app/assets/javascripts/diffs/components/inline_diff_table_row.vue b/app/assets/javascripts/diffs/components/inline_diff_table_row.vue index 25403b1547e..f903fef72b7 100644 --- a/app/assets/javascripts/diffs/components/inline_diff_table_row.vue +++ b/app/assets/javascripts/diffs/components/inline_diff_table_row.vue @@ -177,7 +177,6 @@ export default { <a v-if="line.new_line" ref="lineNumberRefNew" - data-qa-selector="new_diff_line_link" :data-linenumber="line.new_line" :href="line.lineHref" @click="setHighlightedRow(line.lineCode)" diff --git a/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue b/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue index 96946d0fd88..2d33926c8aa 100644 --- a/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue +++ b/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue @@ -193,7 +193,7 @@ export default { v-show="shouldShowCommentButtonLeft" ref="addDiffNoteButtonLeft" type="button" - class="add-diff-note note-button js-add-diff-note-button qa-diff-comment" + class="add-diff-note note-button js-add-diff-note-button" :disabled="line.left.commentsDisabled" :aria-label="addCommentTooltipLeft" @click="handleCommentButton(line.left)" @@ -251,7 +251,7 @@ export default { v-show="shouldShowCommentButtonRight" ref="addDiffNoteButtonRight" type="button" - class="add-diff-note note-button js-add-diff-note-button qa-diff-comment" + class="add-diff-note note-button js-add-diff-note-button" :disabled="line.right.commentsDisabled" :aria-label="addCommentTooltipRight" @click="handleCommentButton(line.right)" diff --git a/app/assets/javascripts/issues_list/components/issues_list_app.vue b/app/assets/javascripts/issues_list/components/issues_list_app.vue index 176b342d8e7..6059beee078 100644 --- a/app/assets/javascripts/issues_list/components/issues_list_app.vue +++ b/app/assets/javascripts/issues_list/components/issues_list_app.vue @@ -38,8 +38,19 @@ import { } from '~/issues_list/utils'; import axios from '~/lib/utils/axios_utils'; import { convertObjectPropsToCamelCase, getParameterByName } from '~/lib/utils/common_utils'; -import { __ } from '~/locale'; -import { DEFAULT_NONE_ANY } from '~/vue_shared/components/filtered_search_bar/constants'; +import { + DEFAULT_NONE_ANY, + OPERATOR_IS_ONLY, + TOKEN_TITLE_ASSIGNEE, + TOKEN_TITLE_AUTHOR, + TOKEN_TITLE_CONFIDENTIAL, + TOKEN_TITLE_EPIC, + TOKEN_TITLE_ITERATION, + TOKEN_TITLE_LABEL, + TOKEN_TITLE_MILESTONE, + TOKEN_TITLE_MY_REACTION, + TOKEN_TITLE_WEIGHT, +} from '~/vue_shared/components/filtered_search_bar/constants'; import AuthorToken from '~/vue_shared/components/filtered_search_bar/tokens/author_token.vue'; import EmojiToken from '~/vue_shared/components/filtered_search_bar/tokens/emoji_token.vue'; import EpicToken from '~/vue_shared/components/filtered_search_bar/tokens/epic_token.vue'; @@ -178,7 +189,7 @@ export default { const tokens = [ { type: 'author_username', - title: __('Author'), + title: TOKEN_TITLE_AUTHOR, icon: 'pencil', token: AuthorToken, dataType: 'user', @@ -188,7 +199,7 @@ export default { }, { type: 'assignee_username', - title: __('Assignee'), + title: TOKEN_TITLE_ASSIGNEE, icon: 'user', token: AuthorToken, dataType: 'user', @@ -198,7 +209,7 @@ export default { }, { type: 'milestone', - title: __('Milestone'), + title: TOKEN_TITLE_MILESTONE, icon: 'clock', token: MilestoneToken, unique: true, @@ -207,7 +218,7 @@ export default { }, { type: 'labels', - title: __('Label'), + title: TOKEN_TITLE_LABEL, icon: 'labels', token: LabelToken, defaultLabels: [], @@ -215,23 +226,23 @@ export default { }, { type: 'my_reaction_emoji', - title: __('My-Reaction'), + title: TOKEN_TITLE_MY_REACTION, icon: 'thumb-up', token: EmojiToken, unique: true, - operators: [{ value: '=', description: __('is') }], + operators: OPERATOR_IS_ONLY, fetchEmojis: this.fetchEmojis, }, { type: 'confidential', - title: __('Confidential'), + title: TOKEN_TITLE_CONFIDENTIAL, icon: 'eye-slash', token: GlFilteredSearchToken, unique: true, - operators: [{ value: '=', description: __('is') }], + operators: OPERATOR_IS_ONLY, options: [ - { icon: 'eye-slash', value: 'yes', title: __('Yes') }, - { icon: 'eye', value: 'no', title: __('No') }, + { icon: 'eye-slash', value: 'yes', title: this.$options.i18n.confidentialYes }, + { icon: 'eye', value: 'no', title: this.$options.i18n.confidentialNo }, ], }, ]; @@ -239,7 +250,7 @@ export default { if (this.projectIterationsPath) { tokens.push({ type: 'iteration', - title: __('Iteration'), + title: TOKEN_TITLE_ITERATION, icon: 'iteration', token: IterationToken, unique: true, @@ -250,7 +261,7 @@ export default { if (this.groupEpicsPath) { tokens.push({ type: 'epic_id', - title: __('Epic'), + title: TOKEN_TITLE_EPIC, icon: 'epic', token: EpicToken, unique: true, @@ -261,7 +272,7 @@ export default { if (this.hasIssueWeightsFeature) { tokens.push({ type: 'weight', - title: __('Weight'), + title: TOKEN_TITLE_WEIGHT, icon: 'weight', token: WeightToken, unique: true, @@ -371,7 +382,7 @@ export default { this.exportCsvPathWithQuery = this.getExportCsvPathWithQuery(); }) .catch(() => { - createFlash({ message: __('An error occurred while loading issues') }); + createFlash({ message: this.$options.i18n.errorFetchingIssues }); }) .finally(() => { this.isLoading = false; @@ -382,10 +393,10 @@ export default { }, getStatus(issue) { if (issue.closedAt && issue.movedToId) { - return __('CLOSED (MOVED)'); + return this.$options.i18n.closedMoved; } if (issue.closedAt) { - return __('CLOSED'); + return this.$options.i18n.closed; } return undefined; }, @@ -474,7 +485,7 @@ export default { <issuable-list :namespace="projectPath" recent-searches-storage-key="issues" - :search-input-placeholder="__('Search or filter results…')" + :search-input-placeholder="$options.i18n.searchPlaceholder" :search-tokens="searchTokens" :initial-filter-value="filterTokens" :sort-options="sortOptions" @@ -525,7 +536,7 @@ export default { :disabled="isBulkEditButtonDisabled" @click="handleBulkUpdateClick" > - {{ __('Edit issues') }} + {{ $options.i18n.editIssues }} </gl-button> <gl-button v-if="showNewIssueLink" :href="newIssuePath" variant="confirm"> {{ $options.i18n.newIssueLabel }} @@ -545,7 +556,7 @@ export default { v-if="issuable.mergeRequestsCount" v-gl-tooltip class="gl-display-none gl-sm-display-block" - :title="__('Related merge requests')" + :title="$options.i18n.relatedMergeRequests" data-testid="issuable-mr" > <gl-icon name="merge-request" /> @@ -555,7 +566,7 @@ export default { v-if="issuable.upvotes" v-gl-tooltip class="gl-display-none gl-sm-display-block" - :title="__('Upvotes')" + :title="$options.i18n.upvotes" data-testid="issuable-upvotes" > <gl-icon name="thumb-up" /> @@ -565,7 +576,7 @@ export default { v-if="issuable.downvotes" v-gl-tooltip class="gl-display-none gl-sm-display-block" - :title="__('Downvotes')" + :title="$options.i18n.downvotes" data-testid="issuable-downvotes" > <gl-icon name="thumb-down" /> diff --git a/app/assets/javascripts/issues_list/constants.js b/app/assets/javascripts/issues_list/constants.js index cb5da81ea5a..5f0bbd2145d 100644 --- a/app/assets/javascripts/issues_list/constants.js +++ b/app/assets/javascripts/issues_list/constants.js @@ -3,6 +3,8 @@ import { FILTER_ANY, FILTER_CURRENT, FILTER_NONE, + OPERATOR_IS, + OPERATOR_IS_NOT, } from '~/vue_shared/components/filtered_search_bar/constants'; // Maps sort order as it appears in the URL query to API `order_by` and `sort` params. @@ -60,6 +62,13 @@ export const availableSortOptionsJira = [ export const i18n = { calendarLabel: __('Subscribe to calendar'), + closed: __('CLOSED'), + closedMoved: __('CLOSED (MOVED)'), + confidentialNo: __('No'), + confidentialYes: __('Yes'), + downvotes: __('Downvotes'), + editIssues: __('Edit issues'), + errorFetchingIssues: __('An error occurred while loading issues'), jiraIntegrationMessage: s__( 'JiraService|%{jiraDocsLinkStart}Enable the Jira integration%{jiraDocsLinkEnd} to view your Jira issues in GitLab.', ), @@ -82,8 +91,11 @@ export const i18n = { noIssuesSignedOutTitle: __('There are no issues to show'), noSearchResultsDescription: __('To widen your search, change or remove filters above'), noSearchResultsTitle: __('Sorry, your filter produced no results'), + relatedMergeRequests: __('Related merge requests'), reorderError: __('An error occurred while reordering issues.'), rssLabel: __('Subscribe to RSS feed'), + searchPlaceholder: __('Search or filter results…'), + upvotes: __('Upvotes'), }; export const JIRA_IMPORT_SUCCESS_ALERT_HIDE_MAP_KEY = 'jira-import-success-alert-hide-map'; @@ -246,10 +258,6 @@ export const urlSortParams = { export const MAX_LIST_SIZE = 10; -export const FILTERED_SEARCH_TERM = 'filtered-search-term'; -export const OPERATOR_IS = '='; -export const OPERATOR_IS_NOT = '!='; - export const NORMAL_FILTER = 'normalFilter'; export const SPECIAL_FILTER = 'specialFilter'; export const SPECIAL_FILTER_VALUES = [FILTER_NONE, FILTER_ANY, FILTER_CURRENT]; diff --git a/app/assets/javascripts/issues_list/utils.js b/app/assets/javascripts/issues_list/utils.js index d212226e139..b6551eb4ac8 100644 --- a/app/assets/javascripts/issues_list/utils.js +++ b/app/assets/javascripts/issues_list/utils.js @@ -4,7 +4,6 @@ import { CREATED_DESC, DUE_DATE_ASC, DUE_DATE_DESC, - FILTERED_SEARCH_TERM, filters, LABEL_PRIORITY_DESC, MILESTONE_DUE_ASC, @@ -23,6 +22,7 @@ import { WEIGHT_DESC, } from '~/issues_list/constants'; import { __ } from '~/locale'; +import { FILTERED_SEARCH_TERM } from '~/vue_shared/components/filtered_search_bar/constants'; export const getSortKey = (sort) => Object.keys(urlSortParams).find((key) => urlSortParams[key].sort === sort); diff --git a/app/assets/javascripts/logs/components/log_advanced_filters.vue b/app/assets/javascripts/logs/components/log_advanced_filters.vue index 9159ca5b9dc..c6d7c9ad1dc 100644 --- a/app/assets/javascripts/logs/components/log_advanced_filters.vue +++ b/app/assets/javascripts/logs/components/log_advanced_filters.vue @@ -1,8 +1,9 @@ <script> import { GlFilteredSearch } from '@gitlab/ui'; import { mapActions, mapState } from 'vuex'; -import { __, s__ } from '~/locale'; +import { s__ } from '~/locale'; import DateTimePicker from '~/vue_shared/components/date_time_picker/date_time_picker.vue'; +import { OPERATOR_IS_ONLY } from '~/vue_shared/components/filtered_search_bar/constants'; import { timeRanges } from '~/vue_shared/constants'; import { TOKEN_TYPE_POD_NAME } from '../constants'; import TokenWithLoadingState from './tokens/token_with_loading_state.vue'; @@ -54,7 +55,7 @@ export default { type: TOKEN_TYPE_POD_NAME, title: s__('Environments|Pod name'), token: TokenWithLoadingState, - operators: [{ value: '=', description: __('is'), default: 'true' }], + operators: OPERATOR_IS_ONLY, unique: true, options: this.podOptions, loading: this.logs.isLoading, 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 b92d9211f91..cc0533391df 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 @@ -5,6 +5,7 @@ import { getParameterByName, urlParamsToObject } from '~/lib/utils/common_utils' import { setUrlParams } from '~/lib/utils/url_utility'; import { s__ } from '~/locale'; import { SEARCH_TOKEN_TYPE, SORT_PARAM } from '~/members/constants'; +import { OPERATOR_IS_ONLY } from '~/vue_shared/components/filtered_search_bar/constants'; import FilteredSearchBar from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue'; export default { @@ -17,7 +18,7 @@ export default { title: s__('Members|2FA'), token: GlFilteredSearchToken, unique: true, - operators: [{ value: '=', description: 'is' }], + operators: OPERATOR_IS_ONLY, options: [ { value: 'enabled', title: s__('Members|Enabled') }, { value: 'disabled', title: s__('Members|Disabled') }, @@ -30,7 +31,7 @@ export default { title: s__('Members|Membership'), token: GlFilteredSearchToken, unique: true, - operators: [{ value: '=', description: 'is' }], + operators: OPERATOR_IS_ONLY, options: [ { value: 'exclude', title: s__('Members|Direct') }, { value: 'only', title: s__('Members|Inherited') }, diff --git a/app/assets/javascripts/notes/components/note_form.vue b/app/assets/javascripts/notes/components/note_form.vue index 5b40f4f86f5..4ce81219f11 100644 --- a/app/assets/javascripts/notes/components/note_form.vue +++ b/app/assets/javascripts/notes/components/note_form.vue @@ -367,21 +367,11 @@ export default { <p v-if="showResolveDiscussionToggle"> <label> <template v-if="discussionResolved"> - <input - v-model="isUnresolving" - type="checkbox" - class="js-unresolve-checkbox" - data-qa-selector="unresolve_review_discussion_checkbox" - /> + <input v-model="isUnresolving" type="checkbox" class="js-unresolve-checkbox" /> {{ __('Unresolve thread') }} </template> <template v-else> - <input - v-model="isResolving" - type="checkbox" - class="js-resolve-checkbox" - data-qa-selector="resolve_review_discussion_checkbox" - /> + <input v-model="isResolving" type="checkbox" class="js-resolve-checkbox" /> {{ __('Resolve thread') }} </template> </label> diff --git a/app/assets/javascripts/packages/list/components/package_search.vue b/app/assets/javascripts/packages/list/components/package_search.vue index 2e183b1b978..869a2c2f641 100644 --- a/app/assets/javascripts/packages/list/components/package_search.vue +++ b/app/assets/javascripts/packages/list/components/package_search.vue @@ -1,6 +1,7 @@ <script> import { mapState, mapActions } from 'vuex'; -import { __, s__ } from '~/locale'; +import { s__ } from '~/locale'; +import { OPERATOR_IS_ONLY } from '~/vue_shared/components/filtered_search_bar/constants'; import RegistrySearch from '~/vue_shared/components/registry/registry_search.vue'; import UrlSync from '~/vue_shared/components/url_sync.vue'; import { sortableFields } from '../utils'; @@ -14,7 +15,7 @@ export default { title: s__('PackageRegistry|Type'), unique: true, token: PackageTypeToken, - operators: [{ value: '=', description: __('is'), default: 'true' }], + operators: OPERATOR_IS_ONLY, }, ], components: { RegistrySearch, UrlSync }, diff --git a/app/assets/javascripts/pipeline_editor/components/file_nav/branch_switcher.vue b/app/assets/javascripts/pipeline_editor/components/file_nav/branch_switcher.vue index af5f77e2d64..1acf3a03e73 100644 --- a/app/assets/javascripts/pipeline_editor/components/file_nav/branch_switcher.vue +++ b/app/assets/javascripts/pipeline_editor/components/file_nav/branch_switcher.vue @@ -1,34 +1,77 @@ <script> -import { GlDropdown, GlDropdownItem, GlDropdownSectionHeader, GlIcon } from '@gitlab/ui'; +import { + GlDropdown, + GlDropdownItem, + GlDropdownSectionHeader, + GlInfiniteScroll, + GlLoadingIcon, + GlSearchBoxByType, +} from '@gitlab/ui'; import { historyPushState } from '~/lib/utils/common_utils'; import { setUrlParams } from '~/lib/utils/url_utility'; import { s__ } from '~/locale'; -import { DEFAULT_FAILURE } from '~/pipeline_editor/constants'; +import { + BRANCH_PAGINATION_LIMIT, + BRANCH_SEARCH_DEBOUNCE, + DEFAULT_FAILURE, +} from '~/pipeline_editor/constants'; import getAvailableBranches from '~/pipeline_editor/graphql/queries/available_branches.graphql'; import getCurrentBranch from '~/pipeline_editor/graphql/queries/client/current_branch.graphql'; export default { i18n: { + dropdownHeader: s__('Switch Branch'), title: s__('Branches'), fetchError: s__('Unable to fetch branch list for this project.'), }, + inputDebounce: BRANCH_SEARCH_DEBOUNCE, components: { GlDropdown, GlDropdownItem, GlDropdownSectionHeader, - GlIcon, + GlInfiniteScroll, + GlLoadingIcon, + GlSearchBoxByType, + }, + inject: ['projectFullPath', 'totalBranches'], + props: { + paginationLimit: { + type: Number, + required: false, + default: BRANCH_PAGINATION_LIMIT, + }, + }, + data() { + return { + branches: [], + page: { + limit: this.paginationLimit, + offset: 0, + searchTerm: '', + }, + }; }, - inject: ['projectFullPath'], apollo: { - branches: { + availableBranches: { query: getAvailableBranches, variables() { return { + limit: this.page.limit, + offset: this.page.offset, projectFullPath: this.projectFullPath, + searchPattern: this.searchPattern, }; }, update(data) { - return data.project?.repository?.branches || []; + return data.project?.repository?.branchNames || []; + }, + result({ data }) { + const newBranches = data.project?.repository?.branchNames || []; + + // check that we're not re-concatenating existing fetch results + if (!this.branches.includes(newBranches[0])) { + this.branches = this.branches.concat(newBranches); + } }, error() { this.$emit('showError', { @@ -42,11 +85,37 @@ export default { }, }, computed: { - hasBranchList() { - return this.branches?.length > 0; + isBranchesLoading() { + return this.$apollo.queries.availableBranches.loading; + }, + showBranchSwitcher() { + return this.branches.length > 0 || this.page.searchTerm.length > 0; + }, + searchPattern() { + if (this.page.searchTerm === '') { + return '*'; + } + + return `*${this.page.searchTerm}*`; }, }, methods: { + // if there is no searchPattern, paginate by {paginationLimit} branches + fetchNextBranches() { + if ( + this.isBranchesLoading || + this.page.searchTerm.length > 0 || + this.branches.length === this.totalBranches + ) { + return; + } + + this.page = { + ...this.page, + limit: this.paginationLimit, + offset: this.page.offset + this.paginationLimit, + }; + }, async selectBranch(newBranch) { if (newBranch === this.currentBranch) { return; @@ -62,24 +131,53 @@ export default { this.$emit('refetchContent'); }, + setSearchTerm(newSearchTerm) { + this.branches = []; + this.page = { + limit: newSearchTerm.trim() === '' ? this.paginationLimit : this.totalBranches, + offset: 0, + searchTerm: newSearchTerm.trim(), + }; + }, }, }; </script> <template> - <gl-dropdown v-if="hasBranchList" class="gl-ml-2" :text="currentBranch" icon="branch"> + <gl-dropdown + v-if="showBranchSwitcher" + class="gl-ml-2" + :header-text="$options.i18n.dropdownHeader" + :text="currentBranch" + icon="branch" + > + <gl-search-box-by-type :debounce="$options.inputDebounce" @input="setSearchTerm" /> <gl-dropdown-section-header> - {{ this.$options.i18n.title }} + {{ $options.i18n.title }} </gl-dropdown-section-header> - <gl-dropdown-item - v-for="branch in branches" - :key="branch.name" - :is-checked="currentBranch === branch.name" - :is-check-item="true" - @click="selectBranch(branch.name)" + + <gl-infinite-scroll + :fetched-items="branches.length" + :total-items="totalBranches" + :max-list-height="250" + @bottomReached="fetchNextBranches" > - <gl-icon name="check" class="gl-visibility-hidden" /> - {{ branch.name }} - </gl-dropdown-item> + <template #items> + <gl-dropdown-item + v-for="branch in branches" + :key="branch" + :is-checked="currentBranch === branch" + :is-check-item="true" + @click="selectBranch(branch)" + > + {{ branch }} + </gl-dropdown-item> + </template> + <template #default> + <gl-dropdown-item v-if="isBranchesLoading" key="loading"> + <gl-loading-icon size="md" /> + </gl-dropdown-item> + </template> + </gl-infinite-scroll> </gl-dropdown> </template> diff --git a/app/assets/javascripts/pipeline_editor/constants.js b/app/assets/javascripts/pipeline_editor/constants.js index dba815368eb..f0a24e0c061 100644 --- a/app/assets/javascripts/pipeline_editor/constants.js +++ b/app/assets/javascripts/pipeline_editor/constants.js @@ -28,3 +28,6 @@ export const COMMIT_ACTION_CREATE = 'CREATE'; export const COMMIT_ACTION_UPDATE = 'UPDATE'; export const DRAWER_EXPANDED_KEY = 'pipeline_editor_drawer_expanded'; + +export const BRANCH_PAGINATION_LIMIT = 20; +export const BRANCH_SEARCH_DEBOUNCE = '500'; diff --git a/app/assets/javascripts/pipeline_editor/graphql/queries/available_branches.graphql b/app/assets/javascripts/pipeline_editor/graphql/queries/available_branches.graphql index f162bb11d47..46e9b108b41 100644 --- a/app/assets/javascripts/pipeline_editor/graphql/queries/available_branches.graphql +++ b/app/assets/javascripts/pipeline_editor/graphql/queries/available_branches.graphql @@ -1,9 +1,12 @@ -query getAvailableBranches($projectFullPath: ID!) { - project(fullPath: $projectFullPath) @client { +query getAvailableBranches( + $limit: Int! + $offset: Int! + $projectFullPath: ID! + $searchPattern: String! +) { + project(fullPath: $projectFullPath) { repository { - branches { - name - } + branchNames(limit: $limit, offset: $offset, searchPattern: $searchPattern) } } } diff --git a/app/assets/javascripts/pipeline_editor/graphql/resolvers.js b/app/assets/javascripts/pipeline_editor/graphql/resolvers.js index 1028770667a..81e75c32846 100644 --- a/app/assets/javascripts/pipeline_editor/graphql/resolvers.js +++ b/app/assets/javascripts/pipeline_editor/graphql/resolvers.js @@ -11,22 +11,6 @@ export const resolvers = { }), }; }, - /* eslint-disable @gitlab/require-i18n-strings */ - project() { - return { - __typename: 'Project', - repository: { - __typename: 'Repository', - branches: [ - { __typename: 'Branch', name: 'main' }, - { __typename: 'Branch', name: 'develop' }, - { __typename: 'Branch', name: 'production' }, - { __typename: 'Branch', name: 'test' }, - ], - }, - }; - }, - /* eslint-enable @gitlab/require-i18n-strings */ }, Mutation: { lintCI: (_, { endpoint, content, dry_run }) => { diff --git a/app/assets/javascripts/pipeline_editor/index.js b/app/assets/javascripts/pipeline_editor/index.js index 361e2b64e0b..66158bdba88 100644 --- a/app/assets/javascripts/pipeline_editor/index.js +++ b/app/assets/javascripts/pipeline_editor/index.js @@ -43,6 +43,7 @@ export const initPipelineEditor = (selector = '#js-pipeline-editor') => { projectPath, projectNamespace, runnerHelpPagePath, + totalBranches, ymlHelpPagePath, } = el?.dataset; @@ -100,6 +101,7 @@ export const initPipelineEditor = (selector = '#js-pipeline-editor') => { projectPath, projectNamespace, runnerHelpPagePath, + totalBranches: parseInt(totalBranches, 10), ymlHelpPagePath, }, render(h) { diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_filtered_search.vue b/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_filtered_search.vue index 492c562ec5c..de3f783ac84 100644 --- a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_filtered_search.vue +++ b/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_filtered_search.vue @@ -1,7 +1,8 @@ <script> import { GlFilteredSearch } from '@gitlab/ui'; import { map } from 'lodash'; -import { __, s__ } from '~/locale'; +import { s__ } from '~/locale'; +import { OPERATOR_IS_ONLY } from '~/vue_shared/components/filtered_search_bar/constants'; import PipelineBranchNameToken from './tokens/pipeline_branch_name_token.vue'; import PipelineStatusToken from './tokens/pipeline_status_token.vue'; import PipelineTagNameToken from './tokens/pipeline_tag_name_token.vue'; @@ -43,7 +44,7 @@ export default { title: s__('Pipeline|Trigger author'), unique: true, token: PipelineTriggerAuthorToken, - operators: [{ value: '=', description: __('is'), default: 'true' }], + operators: OPERATOR_IS_ONLY, projectId: this.projectId, }, { @@ -52,7 +53,7 @@ export default { title: s__('Pipeline|Branch name'), unique: true, token: PipelineBranchNameToken, - operators: [{ value: '=', description: __('is'), default: 'true' }], + operators: OPERATOR_IS_ONLY, projectId: this.projectId, disabled: this.selectedTypes.includes(this.$options.tagType), }, @@ -62,7 +63,7 @@ export default { title: s__('Pipeline|Tag name'), unique: true, token: PipelineTagNameToken, - operators: [{ value: '=', description: __('is'), default: 'true' }], + operators: OPERATOR_IS_ONLY, projectId: this.projectId, disabled: this.selectedTypes.includes(this.$options.branchType), }, @@ -72,7 +73,7 @@ export default { title: s__('Pipeline|Status'), unique: true, token: PipelineStatusToken, - operators: [{ value: '=', description: __('is'), default: 'true' }], + operators: OPERATOR_IS_ONLY, }, ]; }, diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled.vue index 6d68c15cf2d..75831643f6a 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled.vue @@ -154,7 +154,7 @@ export default { <status-icon status="success" /> <div class="media-body"> <h4 class="gl-display-flex"> - <span class="gl-mr-3" data-qa-selector="merge_request_status_content"> + <span class="gl-mr-3"> <span class="js-status-text-before-author" data-testid="beforeStatusText">{{ statusTextBeforeAuthor }}</span> diff --git a/app/assets/javascripts/vue_shared/components/filtered_search_bar/constants.js b/app/assets/javascripts/vue_shared/components/filtered_search_bar/constants.js index 519b461c015..784f7cccf15 100644 --- a/app/assets/javascripts/vue_shared/components/filtered_search_bar/constants.js +++ b/app/assets/javascripts/vue_shared/components/filtered_search_bar/constants.js @@ -1,4 +1,3 @@ -/* eslint-disable @gitlab/require-i18n-strings */ import { __ } from '~/locale'; export const DEBOUNCE_DELAY = 200; @@ -7,6 +6,12 @@ export const FILTER_NONE = 'None'; export const FILTER_ANY = 'Any'; export const FILTER_CURRENT = 'Current'; +export const OPERATOR_IS = '='; +export const OPERATOR_IS_TEXT = __('is'); +export const OPERATOR_IS_NOT = '!='; + +export const OPERATOR_IS_ONLY = [{ value: OPERATOR_IS, description: OPERATOR_IS_TEXT }]; + export const DEFAULT_LABEL_NONE = { value: FILTER_NONE, text: __(FILTER_NONE) }; export const DEFAULT_LABEL_ANY = { value: FILTER_ANY, text: __(FILTER_ANY) }; export const DEFAULT_NONE_ANY = [DEFAULT_LABEL_NONE, DEFAULT_LABEL_ANY]; @@ -15,15 +20,26 @@ export const DEFAULT_ITERATIONS = DEFAULT_NONE_ANY.concat([ { value: FILTER_CURRENT, text: __(FILTER_CURRENT) }, ]); -export const DEFAULT_LABELS = [{ value: 'No label', text: __('No label') }]; +export const DEFAULT_LABELS = [{ value: 'No label', text: __('No label') }]; // eslint-disable-line @gitlab/require-i18n-strings export const DEFAULT_MILESTONES = DEFAULT_NONE_ANY.concat([ - { value: 'Upcoming', text: __('Upcoming') }, - { value: 'Started', text: __('Started') }, + { value: 'Upcoming', text: __('Upcoming') }, // eslint-disable-line @gitlab/require-i18n-strings + { value: 'Started', text: __('Started') }, // eslint-disable-line @gitlab/require-i18n-strings ]); export const SortDirection = { descending: 'descending', ascending: 'ascending', }; -/* eslint-enable @gitlab/require-i18n-strings */ + +export const FILTERED_SEARCH_TERM = 'filtered-search-term'; + +export const TOKEN_TITLE_AUTHOR = __('Author'); +export const TOKEN_TITLE_ASSIGNEE = __('Assignee'); +export const TOKEN_TITLE_MILESTONE = __('Milestone'); +export const TOKEN_TITLE_LABEL = __('Label'); +export const TOKEN_TITLE_MY_REACTION = __('My-Reaction'); +export const TOKEN_TITLE_CONFIDENTIAL = __('Confidential'); +export const TOKEN_TITLE_ITERATION = __('Iteration'); +export const TOKEN_TITLE_EPIC = __('Epic'); +export const TOKEN_TITLE_WEIGHT = __('Weight'); diff --git a/app/assets/javascripts/vue_shared/components/markdown/apply_suggestion.vue b/app/assets/javascripts/vue_shared/components/markdown/apply_suggestion.vue index 90ac20fe748..d6a20984ad1 100644 --- a/app/assets/javascripts/vue_shared/components/markdown/apply_suggestion.vue +++ b/app/assets/javascripts/vue_shared/components/markdown/apply_suggestion.vue @@ -34,7 +34,7 @@ export default { boundary="window" right menu-class="gl-w-full!" - data-qa-selector="apply_suggestion_button" + data-qa-selector="apply_suggestion_dropdown" @shown="$refs.commitMessage.$el.focus()" > <gl-dropdown-form class="gl-px-4! gl-m-0!"> @@ -45,7 +45,7 @@ export default { v-model="message" :placeholder="defaultCommitMessage" submit-on-enter - data-qa-selector="commit_message_textbox" + data-qa-selector="commit_message_field" @submit="onApply" /> <gl-button diff --git a/app/assets/javascripts/vue_shared/components/markdown/suggestion_diff.vue b/app/assets/javascripts/vue_shared/components/markdown/suggestion_diff.vue index bcd8c02e968..9c954fce322 100644 --- a/app/assets/javascripts/vue_shared/components/markdown/suggestion_diff.vue +++ b/app/assets/javascripts/vue_shared/components/markdown/suggestion_diff.vue @@ -70,7 +70,7 @@ export default { <template> <div class="md-suggestion"> <suggestion-diff-header - class="qa-suggestion-diff-header js-suggestion-diff-header" + class="js-suggestion-diff-header" :suggestions-count="suggestionsCount" :can-apply="suggestion.appliable && suggestion.current_user.can_apply && !disabled" :is-applied="suggestion.applied" diff --git a/app/assets/javascripts/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs.vue b/app/assets/javascripts/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs.vue index e2591362611..d05e45e90b3 100644 --- a/app/assets/javascripts/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs.vue +++ b/app/assets/javascripts/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs.vue @@ -4,6 +4,7 @@ import Api from '~/api'; import { updateHistory, setUrlParams } from '~/lib/utils/url_utility'; import { __ } from '~/locale'; import Tracking from '~/tracking'; +import { OPERATOR_IS_ONLY } from '~/vue_shared/components/filtered_search_bar/constants'; import FilteredSearchBar from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue'; import AuthorToken from '~/vue_shared/components/filtered_search_bar/tokens/author_token.vue'; import { initialPaginationState, defaultI18n, defaultPageSize } from './constants'; @@ -105,7 +106,7 @@ export default { unique: true, symbol: '@', token: AuthorToken, - operators: [{ value: '=', description: __('is'), default: 'true' }], + operators: OPERATOR_IS_ONLY, fetchPath: this.projectPath, fetchAuthors: Api.projectUsers.bind(Api), }, @@ -116,7 +117,7 @@ export default { unique: true, symbol: '@', token: AuthorToken, - operators: [{ value: '=', description: __('is'), default: 'true' }], + operators: OPERATOR_IS_ONLY, fetchPath: this.projectPath, fetchAuthors: Api.projectUsers.bind(Api), }, diff --git a/app/helpers/ci/pipeline_editor_helper.rb b/app/helpers/ci/pipeline_editor_helper.rb index c9a41e35af8..8c8ee2d4d0f 100644 --- a/app/helpers/ci/pipeline_editor_helper.rb +++ b/app/helpers/ci/pipeline_editor_helper.rb @@ -27,6 +27,7 @@ module Ci "project-full-path" => project.full_path, "project-namespace" => project.namespace.full_path, "runner-help-page-path" => help_page_path('ci/runners/README'), + "total-branches" => project.repository.branches.length, "yml-help-page-path" => help_page_path('ci/yaml/README') } end diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index 54d5efbbdbc..2e837c8acb1 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -1095,6 +1095,8 @@ module Ci merge_request.modified_paths elsif branch_updated? push_details.modified_paths + elsif external_pull_request? && ::Feature.enabled?(:ci_modified_paths_of_external_prs, project, default_enabled: :yaml) + external_pull_request.modified_paths end end end @@ -1119,6 +1121,10 @@ module Ci merge_request_id.present? end + def external_pull_request? + external_pull_request_id.present? + end + def detached_merge_request_pipeline? merge_request? && target_sha.nil? end diff --git a/app/models/external_pull_request.rb b/app/models/external_pull_request.rb index 1487a6387f0..3fc166203e7 100644 --- a/app/models/external_pull_request.rb +++ b/app/models/external_pull_request.rb @@ -72,6 +72,10 @@ class ExternalPullRequest < ApplicationRecord end end + def modified_paths + project.repository.diff_stats(target_sha, source_sha).paths + end + private def actual_source_branch_sha diff --git a/app/views/projects/merge_requests/_description.html.haml b/app/views/projects/merge_requests/_description.html.haml index c20479662dd..1dd4cc6495c 100644 --- a/app/views/projects/merge_requests/_description.html.haml +++ b/app/views/projects/merge_requests/_description.html.haml @@ -1,6 +1,6 @@ %div - if @merge_request.description.present? - .description.qa-description{ class: can?(current_user, :update_merge_request, @merge_request) ? 'js-task-list-container' : '' } + .description{ class: can?(current_user, :update_merge_request, @merge_request) ? 'js-task-list-container' : '' , data: { qa_selector: 'description_content' } } .md = markdown_field(@merge_request, :description) %textarea.hidden.js-task-list-field{ data: { value: @merge_request.description } } diff --git a/app/views/projects/merge_requests/_mr_box.html.haml b/app/views/projects/merge_requests/_mr_box.html.haml index c38cf62b36c..916b841e350 100644 --- a/app/views/projects/merge_requests/_mr_box.html.haml +++ b/app/views/projects/merge_requests/_mr_box.html.haml @@ -1,3 +1,3 @@ .detail-page-description.py-2 - %h2.title.qa-title.mb-0 + %h2.title.mb-0{ data: { qa_selector: 'title_content' } } = markdown_field(@merge_request, :title) diff --git a/app/views/shared/_commit_message_container.html.haml b/app/views/shared/_commit_message_container.html.haml index 47ecc75af1f..904854c3fb7 100644 --- a/app/views/shared/_commit_message_container.html.haml +++ b/app/views/shared/_commit_message_container.html.haml @@ -7,11 +7,13 @@ .commit-message-container .max-width-marker = text_area_tag 'commit_message', - (params[:commit_message] || local_assigns[:text] || local_assigns[:placeholder]), - class: 'form-control gl-form-input js-commit-message', placeholder: local_assigns[:placeholder], - data: descriptions, - required: true, rows: (local_assigns[:rows] || 3), - id: "commit_message-#{nonce}" + (params[:commit_message] || local_assigns[:text] || local_assigns[:placeholder]), + class: 'form-control gl-form-input js-commit-message', + placeholder: local_assigns[:placeholder], + data: descriptions, + 'data-qa-selector': 'commit_message_field', + required: true, rows: (local_assigns[:rows] || 3), + id: "commit_message-#{nonce}" - if local_assigns[:hint] %p.hint = _('Try to keep the first line under 52 characters and the others under 72.') diff --git a/changelogs/unreleased/321817-update-usage-ping-metrics-definitions-for-group-source-code.yml b/changelogs/unreleased/321817-update-usage-ping-metrics-definitions-for-group-source-code.yml new file mode 100644 index 00000000000..24bd713c01f --- /dev/null +++ b/changelogs/unreleased/321817-update-usage-ping-metrics-definitions-for-group-source-code.yml @@ -0,0 +1,5 @@ +--- +title: Update projects approval rules Usage Data metrics +merge_request: 61106 +author: +type: other diff --git a/changelogs/unreleased/rename-cloudrail-template.yml b/changelogs/unreleased/rename-cloudrail-template.yml new file mode 100644 index 00000000000..2220dcd691b --- /dev/null +++ b/changelogs/unreleased/rename-cloudrail-template.yml @@ -0,0 +1,5 @@ +--- +title: Remove hyphen from Cloudrail CI template name +merge_request: 61079 +author: +type: fixed diff --git a/changelogs/unreleased/semgrep-offline-support.yml b/changelogs/unreleased/semgrep-offline-support.yml new file mode 100644 index 00000000000..e95f12938ed --- /dev/null +++ b/changelogs/unreleased/semgrep-offline-support.yml @@ -0,0 +1,5 @@ +--- +title: Add semgrep to Secure-Binaries and update support docs +merge_request: 61411 +author: +type: added diff --git a/config/feature_flags/development/ci_modified_paths_of_external_prs.yml b/config/feature_flags/development/ci_modified_paths_of_external_prs.yml new file mode 100644 index 00000000000..70d5e0ce076 --- /dev/null +++ b/config/feature_flags/development/ci_modified_paths_of_external_prs.yml @@ -0,0 +1,8 @@ +--- +name: ci_modified_paths_of_external_prs +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/60736 +rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/330605 +milestone: '13.12' +type: development +group: group::pipeline authoring +default_enabled: false diff --git a/config/metrics/counts_28d/20210216183618_approval_project_rules_with_more_approvers_than_required.yml b/config/metrics/counts_28d/20210216183618_approval_project_rules_with_more_approvers_than_required.yml deleted file mode 100644 index 85ea922568e..00000000000 --- a/config/metrics/counts_28d/20210216183618_approval_project_rules_with_more_approvers_than_required.yml +++ /dev/null @@ -1,16 +0,0 @@ ---- -key_path: usage_activity_by_stage_monthly.create.approval_project_rules_with_more_approvers_than_required -description: '' -product_section: '' -product_stage: '' -product_group: '' -product_category: '' -value_type: number -status: data_available -time_frame: 28d -data_source: -distribution: -- ce -tier: -- free -skip_validation: true diff --git a/config/metrics/counts_28d/20210216183620_approval_project_rules_with_less_approvers_than_required.yml b/config/metrics/counts_28d/20210216183620_approval_project_rules_with_less_approvers_than_required.yml deleted file mode 100644 index 36a3dccbc95..00000000000 --- a/config/metrics/counts_28d/20210216183620_approval_project_rules_with_less_approvers_than_required.yml +++ /dev/null @@ -1,16 +0,0 @@ ---- -key_path: usage_activity_by_stage_monthly.create.approval_project_rules_with_less_approvers_than_required -description: '' -product_section: '' -product_stage: '' -product_group: '' -product_category: '' -value_type: number -status: data_available -time_frame: 28d -data_source: -distribution: -- ce -tier: -- free -skip_validation: true diff --git a/config/metrics/counts_28d/20210216183622_approval_project_rules_with_exact_required_approvers.yml b/config/metrics/counts_28d/20210216183622_approval_project_rules_with_exact_required_approvers.yml deleted file mode 100644 index a4f7695c505..00000000000 --- a/config/metrics/counts_28d/20210216183622_approval_project_rules_with_exact_required_approvers.yml +++ /dev/null @@ -1,16 +0,0 @@ ---- -key_path: usage_activity_by_stage_monthly.create.approval_project_rules_with_exact_required_approvers -description: '' -product_section: '' -product_stage: '' -product_group: '' -product_category: '' -value_type: number -status: data_available -time_frame: 28d -data_source: -distribution: -- ce -tier: -- free -skip_validation: true diff --git a/config/metrics/counts_all/20210216183339_merge_requests_with_overridden_project_rules.yml b/config/metrics/counts_all/20210216183339_merge_requests_with_overridden_project_rules.yml deleted file mode 100644 index a2f3c2a6002..00000000000 --- a/config/metrics/counts_all/20210216183339_merge_requests_with_overridden_project_rules.yml +++ /dev/null @@ -1,16 +0,0 @@ ---- -key_path: usage_activity_by_stage.create.merge_requests_with_overridden_project_rules -description: '' -product_section: '' -product_stage: '' -product_group: '' -product_category: '' -value_type: number -status: data_available -time_frame: all -data_source: -distribution: -- ce -tier: -- free -skip_validation: true diff --git a/config/metrics/counts_all/20210216183352_approval_project_rules_with_more_approvers_than_required.yml b/config/metrics/counts_all/20210216183352_approval_project_rules_with_more_approvers_than_required.yml deleted file mode 100644 index 4afb690ddc4..00000000000 --- a/config/metrics/counts_all/20210216183352_approval_project_rules_with_more_approvers_than_required.yml +++ /dev/null @@ -1,16 +0,0 @@ ---- -key_path: usage_activity_by_stage.create.approval_project_rules_with_more_approvers_than_required -description: '' -product_section: '' -product_stage: '' -product_group: '' -product_category: '' -value_type: number -status: data_available -time_frame: all -data_source: -distribution: -- ce -tier: -- free -skip_validation: true diff --git a/config/metrics/counts_all/20210216183354_approval_project_rules_with_less_approvers_than_required.yml b/config/metrics/counts_all/20210216183354_approval_project_rules_with_less_approvers_than_required.yml deleted file mode 100644 index 3ef906e10da..00000000000 --- a/config/metrics/counts_all/20210216183354_approval_project_rules_with_less_approvers_than_required.yml +++ /dev/null @@ -1,16 +0,0 @@ ---- -key_path: usage_activity_by_stage.create.approval_project_rules_with_less_approvers_than_required -description: '' -product_section: '' -product_stage: '' -product_group: '' -product_category: '' -value_type: number -status: data_available -time_frame: all -data_source: -distribution: -- ce -tier: -- free -skip_validation: true diff --git a/config/metrics/counts_all/20210216183355_approval_project_rules_with_exact_required_approvers.yml b/config/metrics/counts_all/20210216183355_approval_project_rules_with_exact_required_approvers.yml deleted file mode 100644 index 1397b1b57e2..00000000000 --- a/config/metrics/counts_all/20210216183355_approval_project_rules_with_exact_required_approvers.yml +++ /dev/null @@ -1,16 +0,0 @@ ---- -key_path: usage_activity_by_stage.create.approval_project_rules_with_exact_required_approvers -description: '' -product_section: '' -product_stage: '' -product_group: '' -product_category: '' -value_type: number -status: data_available -time_frame: all -data_source: -distribution: -- ce -tier: -- free -skip_validation: true diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md index 7a414f4a257..9d033ba559a 100644 --- a/doc/ci/yaml/README.md +++ b/doc/ci/yaml/README.md @@ -3606,8 +3606,8 @@ third party ports for other languages like JavaScript, Python, Ruby, and so on. ##### `artifacts:reports:codequality` -> - Introduced in [GitLab Starter](https://about.gitlab.com/pricing/) 11.5. -> - Made [available in all tiers](https://gitlab.com/gitlab-org/gitlab/-/issues/212499) in GitLab 13.2. +> - Introduced in GitLab 11.5. +> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/212499) to GitLab Free in 13.2. > - Requires GitLab Runner 11.5 and above. The `codequality` report collects [Code Quality issues](../../user/project/merge_requests/code_quality.md) diff --git a/doc/development/usage_ping/dictionary.md b/doc/development/usage_ping/dictionary.md index 094d5cce21b..2f521031311 100644 --- a/doc/development/usage_ping/dictionary.md +++ b/doc/development/usage_ping/dictionary.md @@ -15266,39 +15266,39 @@ Tiers: `premium`, `ultimate` ### `usage_activity_by_stage.create.approval_project_rules_with_exact_required_approvers` -Missing description +Number of approval rules with the exact number of required approvers. -[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/counts_all/20210216183355_approval_project_rules_with_exact_required_approvers.yml) +[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_all/20210216183355_approval_project_rules_with_exact_required_approvers.yml) -Group: `` +Group: `group::source code` Status: `data_available` -Tiers: `free` +Tiers: `premium`, `ultimate` ### `usage_activity_by_stage.create.approval_project_rules_with_less_approvers_than_required` -Missing description +Number of approval rules with fewer approvers than required. -[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/counts_all/20210216183354_approval_project_rules_with_less_approvers_than_required.yml) +[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_all/20210216183354_approval_project_rules_with_less_approvers_than_required.yml) -Group: `` +Group: `group::source code` Status: `data_available` -Tiers: `free` +Tiers: `premium`, `ultimate` ### `usage_activity_by_stage.create.approval_project_rules_with_more_approvers_than_required` -Missing description +Number of approval rules with more approvers than required. -[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/counts_all/20210216183352_approval_project_rules_with_more_approvers_than_required.yml) +[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_all/20210216183352_approval_project_rules_with_more_approvers_than_required.yml) -Group: `` +Group: `group::source code` Status: `data_available` -Tiers: `free` +Tiers: `premium`, `ultimate` ### `usage_activity_by_stage.create.approval_project_rules_with_target_branch` @@ -15374,15 +15374,15 @@ Tiers: `premium`, `ultimate` ### `usage_activity_by_stage.create.merge_requests_with_overridden_project_rules` -Missing description +Number of merge requests that have overridden rules created at the project level. -[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/counts_all/20210216183339_merge_requests_with_overridden_project_rules.yml) +[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_all/20210216183339_merge_requests_with_overridden_project_rules.yml) -Group: `` +Group: `group::source code` Status: `data_available` -Tiers: `free` +Tiers: `premium`, `ultimate` ### `usage_activity_by_stage.create.merge_requests_with_required_codeowners` @@ -17212,39 +17212,39 @@ Tiers: `premium`, `ultimate` ### `usage_activity_by_stage_monthly.create.approval_project_rules_with_exact_required_approvers` -Missing description +Number of approval rules with the exact number of required approvers. -[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/counts_28d/20210216183622_approval_project_rules_with_exact_required_approvers.yml) +[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_28d/20210216183622_approval_project_rules_with_exact_required_approvers.yml) -Group: `` +Group: `group::source code` Status: `data_available` -Tiers: `free` +Tiers: `premium`, `ultimate` ### `usage_activity_by_stage_monthly.create.approval_project_rules_with_less_approvers_than_required` -Missing description +Number of approval rules with fewer approvers than required. -[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/counts_28d/20210216183620_approval_project_rules_with_less_approvers_than_required.yml) +[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_28d/20210216183620_approval_project_rules_with_less_approvers_than_required.yml) -Group: `` +Group: `group::source code` Status: `data_available` -Tiers: `free` +Tiers: `premium`, `ultimate` ### `usage_activity_by_stage_monthly.create.approval_project_rules_with_more_approvers_than_required` -Missing description +Number of approval rules with more approvers than required. -[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/counts_28d/20210216183618_approval_project_rules_with_more_approvers_than_required.yml) +[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_28d/20210216183618_approval_project_rules_with_more_approvers_than_required.yml) -Group: `` +Group: `group::source code` Status: `data_available` -Tiers: `free` +Tiers: `premium`, `ultimate` ### `usage_activity_by_stage_monthly.create.approval_project_rules_with_target_branch` diff --git a/doc/topics/git/index.md b/doc/topics/git/index.md index f676329e41b..21775044301 100644 --- a/doc/topics/git/index.md +++ b/doc/topics/git/index.md @@ -48,12 +48,27 @@ The following resources can help you get started with Git: The following are resources on version control concepts: -- [Git concepts](../../university/training/user_training.md#git-concepts) - [Why Git is Worth the Learning Curve](https://about.gitlab.com/blog/2017/05/17/learning-curve-is-the-biggest-challenge-developers-face-with-git/) - [The future of SaaS hosted Git repository pricing](https://about.gitlab.com/blog/2016/05/11/git-repository-pricing/) - [Git website on version control](https://git-scm.com/book/en/v2/Getting-Started-About-Version-Control) - [GitLab University presentation about Version Control](https://docs.google.com/presentation/d/16sX7hUrCZyOFbpvnrAFrg6tVO5_yT98IgdAqOmXwBho/edit?usp=sharing) +### Work with Git on the command line + +You can do many Git tasks from the command line: + +- [Bisect](bisect.md). +- [Cherry pick](cherry_picking.md). +- [Feature branching](feature_branching.md). +- [Getting started with Git](getting_started.md). +- [Git add](git_add.md). +- [Git log](git_log.md). +- [Git stash](stash.md). +- [Merge conflicts](merge_conflicts.md). +- [Rollback commits](rollback_commits.md). +- [Subtree](subtree.md). +- [Unstage](unstage.md). + ## Git tips The following resources may help you become more efficient at using Git: @@ -100,5 +115,5 @@ The following relate to Git Large File Storage: - [Migrate an existing Git repository with Git LFS](lfs/migrate_to_git_lfs.md) - [Removing objects from LFS](lfs/index.md#removing-objects-from-lfs) - [GitLab Git LFS user documentation](lfs/index.md) -- [GitLab Git LFS admin documentation](../../administration/lfs/index.md) +- [GitLab Git LFS administrator documentation](../../administration/lfs/index.md) - [Towards a production quality open source Git LFS server](https://about.gitlab.com/blog/2015/08/13/towards-a-production-quality-open-source-git-lfs-server/) diff --git a/doc/topics/git/merge_requests.md b/doc/topics/git/merge_requests.md index a4a3108ebd1..751bf8195d0 100644 --- a/doc/topics/git/merge_requests.md +++ b/doc/topics/git/merge_requests.md @@ -1,40 +1,8 @@ --- -stage: none -group: unassigned -info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments -comments: false +redirect_to: '../../user/project/merge_requests/index.md' --- -# Code review and collaboration with Merge Requests +This document was moved to [another location](../../user/project/merge_requests/index.md). -- When you want feedback create a merge request -- Target is the default branch (usually master) -- Assign or mention the person you would like to review -- Add `[Draft]` to the title if it's a work in progress -- When accepting, always delete the branch -- Anyone can comment, not just the assignee -- Push corrections to the same branch - -## Merge requests - -**Create your first merge request** - -1. Use the blue button in the activity feed -1. View the diff (changes) and leave a comment -1. Push a new commit to the same branch -1. Review the changes again and notice the update - -## Feedback and Collaboration - -- Merge requests are a time for feedback and collaboration -- Giving feedback is hard -- Be as kind as possible -- Receiving feedback is hard -- Be as receptive as possible -- Feedback is about the best code, not the person. You are not your code - -Review the Thoughtbot code-review guide for suggestions to follow when reviewing merge requests: -[https://github.com/thoughtbot/guides/tree/master/code-review](https://github.com/thoughtbot/guides/tree/master/code-review) - -See GitLab merge requests for examples: -[https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests) +<!-- This redirect file can be deleted after <2021-08-13>. --> +<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page --> diff --git a/doc/university/README.md b/doc/university/README.md index c815842480c..bf2e7c91918 100644 --- a/doc/university/README.md +++ b/doc/university/README.md @@ -1,8 +1,8 @@ --- -redirect_to: 'index.md' +redirect_to: '../topics/index.md' --- -This document was moved to [another location](index.md). +This document was moved to [another location](../topics/index.md). <!-- This redirect file can be deleted after 2021-05-11. --> <!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page --> diff --git a/doc/university/index.md b/doc/university/index.md index e7461e1b68b..60d012485de 100644 --- a/doc/university/index.md +++ b/doc/university/index.md @@ -1,223 +1,8 @@ --- -stage: none -group: unassigned -info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments -comments: false -type: index +redirect_to: '../topics/index.md' --- -# GitLab University +This document was removed. See our [topics](../topics/index.md) for similar content. -GitLab University is a great place to start when learning about version control with Git and GitLab, as well as other GitLab features. - -If you're looking for a GitLab subscription for _your university_, see our [GitLab for Education](https://about.gitlab.com/solutions/education/) page. - -WARNING: -Some of the content in GitLab University may be out of date and we plan to -[evaluate](https://gitlab.com/gitlab-org/gitlab/-/issues/20403) it. - -The GitLab University curriculum is composed of GitLab videos, screencasts, presentations, projects and external GitLab content hosted on other services and has been organized into the following sections: - -1. [GitLab Beginner](#1-gitlab-beginner). -1. [GitLab Intermediate](#2-gitlab-intermediate). -1. [GitLab Advanced](#3-gitlab-advanced). -1. [External Articles](#4-external-articles). -1. [Resources for GitLab Team Members](#5-resources-for-gitlab-team-members). - -## 1. GitLab Beginner - -### 1.1. Version Control and Git - -<!-- vale gitlab.Spelling = NO --> - -1. [Version Control Systems](https://docs.google.com/presentation/d/16sX7hUrCZyOFbpvnrAFrg6tVO5_yT98IgdAqOmXwBho/edit#slide=id.g72f2e4906_2_29) -1. [Katacoda: Learn Git Version Control using Interactive Browser-Based Scenarios](https://www.katacoda.com/courses/git) - -<!-- vale gitlab.Spelling = YES --> - -### 1.2. GitLab Basics - -1. [An Overview of GitLab.com - Video](https://www.youtube.com/watch?v=WaiL5DGEMR4) -1. [Why Use Git and GitLab - Slides](https://docs.google.com/a/gitlab.com/presentation/d/1RcZhFmn5VPvoFu6UMxhMOy7lAsToeBZRjLRn0LIdaNc/edit?usp=drive_web) -1. [GitLab Basics - Article](../gitlab-basics/index.md) -1. [Git and GitLab Basics - Video](https://www.youtube.com/watch?v=03wb9FvO4Ak&index=5&list=PLFGfElNsQthbQu_IWlNOxul0TbS_2JH-e) -1. [Git and GitLab Basics - Online Course](https://courses.platzi.com/classes/57-git-gitlab/2475-part-233-2/) -1. [Comparison of GitLab Versions](https://about.gitlab.com/features/#compare) - -### 1.3. Your GitLab Account - -1. [Create a GitLab Account - Online Course](https://courses.platzi.com/classes/57-git-gitlab/2434-create-an-account-on-gitlab/) -1. [Create and Add your SSH key to GitLab - Video](https://www.youtube.com/watch?v=54mxyLo3Mqk) - -### 1.4. GitLab Projects - -1. [Repositories, Projects and Groups - Video](https://www.youtube.com/watch?v=4TWfh1aKHHw&index=1&list=PLFGfElNsQthbQu_IWlNOxul0TbS_2JH-e) -1. [Creating a Project in GitLab - Video](https://www.youtube.com/watch?v=7p0hrpNaJ14) -1. [How to Create Files and Directories](https://about.gitlab.com/blog/2016/02/10/feature-highlight-create-files-and-directories-from-files-page/) -1. [GitLab To-Do List](https://about.gitlab.com/blog/2016/03/02/gitlab-todos-feature-highlight/) -1. [GitLab Draft Flag](https://about.gitlab.com/blog/2016/01/08/feature-highlight-wip/) - -### 1.5. Migrating from other Source Control - -<!-- vale gitlab.Spelling = NO --> - -1. [Migrating from Bitbucket/Stash](../user/project/import/bitbucket.md) -1. [Migrating from GitHub](../user/project/import/github.md) -1. [Migrating from SVN](../user/project/import/svn.md) -1. [Migrating from Fogbugz](../user/project/import/fogbugz.md) - -<!-- vale gitlab.Spelling = YES --> -### 1.6. The GitLab team - -1. [About GitLab](https://about.gitlab.com/company/) -1. [GitLab Direction](https://about.gitlab.com/direction/) -1. [GitLab Master Plan](https://about.gitlab.com/blog/2016/09/13/gitlab-master-plan/) -1. [Making GitLab Great for Everyone - Video](https://www.youtube.com/watch?v=GGC40y4vMx0) - Response to "Dear GitHub" letter -1. [Using Innersourcing to Improve Collaboration](https://about.gitlab.com/blog/2014/09/05/innersourcing-using-the-open-source-workflow-to-improve-collaboration-within-an-organization/) -1. [The Software Development Market and GitLab - Video](https://www.youtube.com/watch?v=sXlhgPK1NTY&list=PLFGfElNsQthbQu_IWlNOxul0TbS_2JH-e&index=6) - [Slides](https://docs.google.com/presentation/d/1vCU-NbZWz8NTNK8Vu3y4zGMAHb5DpC8PE5mHtw1PWfI/edit) -1. [GitLab Resources](https://about.gitlab.com/resources/) - -### 1.7 Community and Support - -1. [Getting Help](https://about.gitlab.com/get-help/) - - Proposing Features and Reporting and Tracking bugs for GitLab - - The GitLab IRC channel, Gitter Chat Room, Community Forum, and Mailing List - - Getting Technical Support - - Being part of our Great Community and Contributing to GitLab -1. [Getting Started with the GitLab Development Kit (GDK)](https://about.gitlab.com/blog/2016/06/08/getting-started-with-gitlab-development-kit/) -1. [GitLab Professional Services](https://about.gitlab.com/services/) - -### 1.8 GitLab Training Material - -1. [Git and GitLab Workshop - Slides](https://docs.google.com/presentation/d/1JzTYD8ij9slejV2-TO-NzjCvlvj6mVn9BORePXNJoMI/edit?usp=drive_web) - -## 2. GitLab Intermediate - -### 2.1 GitLab Pages - -1. [Using any Static Site Generator with GitLab Pages](https://about.gitlab.com/blog/2016/06/17/ssg-overview-gitlab-pages-part-3-examples-ci/) -1. [Securing GitLab Pages with SSL](https://about.gitlab.com/blog/2016/06/24/secure-gitlab-pages-with-startssl/) -1. [GitLab Pages Documentation](../user/project/pages/index.md) - -### 2.2. GitLab Issues - -1. [Markdown in GitLab](../user/markdown.md) -1. [Issues and Merge Requests - Video](https://www.youtube.com/watch?v=raXvuwet78M) -1. [Due Dates and Milestones for GitLab Issues](https://about.gitlab.com/blog/2016/08/05/feature-highlight-set-dates-for-issues/) -1. [How to Use GitLab Labels](https://about.gitlab.com/blog/2016/08/17/using-gitlab-labels/) -1. [Applying GitLab Labels Automatically](https://about.gitlab.com/blog/2016/08/19/applying-gitlab-labels-automatically/) -1. [GitLab Issue Board - Product Page](https://about.gitlab.com/stages-devops-lifecycle/issueboard/) -1. [An Overview of GitLab Issue Board](https://about.gitlab.com/blog/2016/08/22/announcing-the-gitlab-issue-board/) -1. [Designing GitLab Issue Board](https://about.gitlab.com/blog/2016/08/31/designing-issue-boards/) -1. [From Idea to Production with GitLab - Video](https://www.youtube.com/watch?v=25pHyknRgEo&index=14&list=PLFGfElNsQthbQu_IWlNOxul0TbS_2JH-e) - -### 2.3. Continuous Integration - -1. [Operating Systems, Servers, VMs, Containers and Unix - Video](https://www.youtube.com/watch?v=V61kL6IC-zY&index=8&list=PLFGfElNsQthbQu_IWlNOxul0TbS_2JH-e) -1. [GitLab CI/CD - Product Page](https://about.gitlab.com/stages-devops-lifecycle/continuous-integration/) -1. [Getting started with GitLab and GitLab CI](https://about.gitlab.com/blog/2015/12/14/getting-started-with-gitlab-and-gitlab-ci/) -1. [GitLab Container Registry](https://about.gitlab.com/blog/2016/05/23/gitlab-container-registry/) -1. [GitLab and Docker - Video](https://www.youtube.com/watch?v=ugOrCcbdHko&index=12&list=PLFGfElNsQthbQu_IWlNOxul0TbS_2JH-e) -1. [How we scale GitLab with built in Docker](https://about.gitlab.com/blog/2016/06/21/how-we-scale-gitlab-by-having-docker-built-in/) -1. [Continuous Integration, Delivery, and Deployment with GitLab](https://about.gitlab.com/blog/2016/08/05/continuous-integration-delivery-and-deployment-with-gitlab/) -1. [Deployments and Environments](https://about.gitlab.com/blog/2021/02/05/ci-deployment-and-environments/) -1. [Sequential, Parallel or Custom Pipelines](https://about.gitlab.com/blog/2016/07/29/the-basics-of-gitlab-ci/) -1. [Setting up GitLab Runner For Continuous Integration](https://about.gitlab.com/blog/2016/03/01/gitlab-runner-with-docker/) -1. [Setting up GitLab Runner on DigitalOcean](https://about.gitlab.com/blog/2016/04/19/how-to-set-up-gitlab-runner-on-digitalocean/) -1. [Setting up GitLab CI for iOS projects](https://about.gitlab.com/blog/2016/03/10/setting-up-gitlab-ci-for-ios-projects/) -1. [IBM: Continuous Delivery vs Continuous Deployment - Video](https://www.youtube.com/watch?v=igwFj8PPSnw) -1. [Amazon: Transition to Continuous Delivery - Video](https://www.youtube.com/watch?v=esEFaY0FDKc) -1. [TechBeacon: Doing continuous delivery? Focus first on reducing release cycle times](https://techbeacon.com/devops/doing-continuous-delivery-focus-first-reducing-release-cycle-times) -1. See **[Integrations](#39-integrations)** for integrations with other CI services. - -### 2.4. Workflow - -1. [GitLab Flow - Video](https://youtu.be/enMumwvLAug?list=PLFGfElNsQthZnwMUFi6rqkyUZkI00OxIV) -1. [GitLab Flow vs Forking in GitLab - Video](https://www.youtube.com/watch?v=UGotqAUACZA) -1. [GitLab Flow Overview](https://about.gitlab.com/topics/version-control/what-is-gitlab-flow/) -1. [Always Start with an Issue](https://about.gitlab.com/blog/2016/03/03/start-with-an-issue/) -1. [GitLab Flow Documentation](../topics/gitlab_flow.md) - -### 2.5. GitLab Comparisons - -1. [GitLab Compared to Other Tools](https://about.gitlab.com/devops-tools/) -1. [Comparing GitLab Terminology](https://about.gitlab.com/blog/2016/01/27/comparing-terms-gitlab-github-bitbucket/) -1. [GitLab Compared to Atlassian (Recording 2016-03-03)](https://youtu.be/Nbzp1t45ERo) -1. [GitLab Position FAQ](https://about.gitlab.com/handbook/positioning-faq/) -1. [Customer review of GitLab with points on why they prefer GitLab](https://www.enovate.co.uk/blog/2015/11/25/gitlab-review) - -## 3. GitLab Advanced - -### 3.1. DevOps - -1. [XebiaLabs: DevOps Terminology](https://digital.ai/glossary) -1. [XebiaLabs: Periodic Table of DevOps Tools](https://digital.ai/periodic-table-of-devops-tools) -1. [Puppet Labs: State of DevOps 2016 - Book](https://puppet.com/resources/report/2016-state-devops-report/) - -### 3.2. Installing GitLab with Omnibus - -1. [What is Omnibus - Video](https://www.youtube.com/watch?v=XTmpKudd-Oo) -1. [How to Install GitLab with Omnibus - Video](https://www.youtube.com/watch?v=Q69YaOjqNhg) -1. [Installing GitLab - Online Course](https://courses.platzi.com/classes/57-git-gitlab/2476-part-0/) -1. [Using a Non-Packaged PostgreSQL Database](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/README.md#using-a-non-packaged-postgresql-database-management-server) -1. [Installing GitLab on Microsoft Azure](https://about.gitlab.com/blog/2016/07/13/how-to-setup-a-gitlab-instance-on-microsoft-azure/) -1. [Installing GitLab on Digital Ocean](https://about.gitlab.com/blog/2016/04/27/getting-started-with-gitlab-and-digitalocean/) - -### 3.3. Permissions - -1. [How to Manage Permissions in GitLab EE - Video](https://www.youtube.com/watch?v=DjUoIrkiNuM) - -### 3.4. Large Files - -1. [Big files in Git (Git LFS) - Video](https://www.youtube.com/watch?v=DawznUxYDe4) - -### 3.5. LDAP and Active Directory - -1. [How to Manage LDAP, Active Directory in GitLab - Video](https://www.youtube.com/watch?v=HPMjM-14qa8) - -### 3.6 Custom Languages - -1. [How to add Syntax Highlighting Support for Custom Languages to GitLab - Video](https://youtu.be/6WxTMqatrrA) - -### 3.7. Scalability and High Availability - -1. [Scalability and High Availability - Video](https://www.youtube.com/watch?v=cXRMJJb6sp4&list=PLFGfElNsQthbQu_IWlNOxul0TbS_2JH-e&index=2) -1. [High Availability - Video](https://www.youtube.com/watch?v=36KS808u6bE&index=15&list=PLFGfElNsQthbQu_IWlNOxul0TbS_2JH-e) -1. [High Availability Documentation](https://about.gitlab.com/solutions/reference-architectures/) - -### 3.8 Value Stream Analytics - -1. [GitLab Value Stream Analytics Overview (as of 2016)](https://about.gitlab.com/blog/2016/09/21/cycle-analytics-feature-highlight/) -1. [GitLab Value Stream Analytics - Product Page](https://about.gitlab.com/stages-devops-lifecycle/value-stream-analytics/) - -### 3.9. Integrations - -<!-- vale gitlab.Spelling = NO --> - -1. [How to Integrate Jira and Jenkins with GitLab - Video](https://gitlabmeetings.webex.com/gitlabmeetings/ldr.php?RCID=44b548147a67ab4d8a62274047146415) -1. [How to Integrate Jira with GitLab](../integration/jira/index.md) -1. [How to Integrate Jenkins with GitLab](../integration/jenkins.md) -1. [How to Integrate Bamboo with GitLab](../user/project/integrations/bamboo.md) -1. [How to Integrate Slack with GitLab](../user/project/integrations/slack.md) -1. [How to Integrate Convox with GitLab](https://about.gitlab.com/blog/2016/06/09/continuous-delivery-with-gitlab-and-convox/) -1. [Getting Started with GitLab and Shippable CI](https://about.gitlab.com/blog/2016/05/05/getting-started-gitlab-and-shippable/) - -<!-- vale gitlab.Spelling = YES --> - -## 4. External Articles - -1. [2011 Wall Street Journal article - Software is Eating the World](https://www.wsj.com/articles/SB10001424053111903480904576512250915629460) -1. [2014 Blog post by Chris Dixon - Software eats software development](https://cdixon.org/2014/04/13/software-eats-software-development/) -1. [2015 Venture Beat article - Actually, Open Source is Eating the World](https://venturebeat.com/2015/12/06/its-actually-open-source-software-thats-eating-the-world/) - -## 5. Resources for GitLab Team Members - -NOTE: -Some content can only be accessed by GitLab team members. - -1. [Sales Path](https://about.gitlab.com/handbook/sales/onboarding/) -1. [User Training](training/user_training.md) -1. [GitLab Flow Training](training/gitlab_flow.md) -1. [Training Topics](training/index.md) -1. [GitLab architecture](../development/architecture.md) -1. [Client Assessment of GitLab versus GitHub](https://docs.google.com/a/gitlab.com/spreadsheets/d/18cRF9Y5I6I7Z_ab6qhBEW55YpEMyU4PitZYjomVHM-M/edit?usp=sharing) +<!-- This redirect file can be deleted after <2021-08-13>. --> +<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page --> diff --git a/doc/university/training/gitlab_flow/production_branch.png b/doc/university/training/gitlab_flow/production_branch.png Binary files differdeleted file mode 100644 index 956761d7eb8..00000000000 --- a/doc/university/training/gitlab_flow/production_branch.png +++ /dev/null diff --git a/doc/university/training/gitlab_flow/release_branches.png b/doc/university/training/gitlab_flow/release_branches.png Binary files differdeleted file mode 100644 index dcb5f97dff0..00000000000 --- a/doc/university/training/gitlab_flow/release_branches.png +++ /dev/null diff --git a/doc/university/training/index.md b/doc/university/training/index.md index 7aabd6b2757..02709314708 100644 --- a/doc/university/training/index.md +++ b/doc/university/training/index.md @@ -1,45 +1,8 @@ --- -stage: none -group: unassigned -info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments -comments: false -type: index +redirect_to: '../../topics/index.md' --- -# GitLab Training Material +This document was moved to [another location](../../topics/index.md). -<!-- vale gitlab.Spelling = NO --> -All GitLab training material is stored in Markdown format. Slides are -generated using [Deckset](https://www.deckset.com/). -<!-- vale gitlab.Spelling = YES --> - -All training material is open to public contribution. - -This section contains the following topics: - -- [Bisect](topics/bisect.md). -- [Cherry pick](topics/cherry_picking.md). -- [Code review and collaboration with Merge Requests](topics/merge_requests.md). -- [Configure your environment](topics/env_setup.md). -- [Explore GitLab](../../gitlab-basics/index.md). -- [Feature branching](topics/feature_branching.md). -- [Getting started](topics/getting_started.md). -- [GitLab flow](gitlab_flow.md). -- [GitLab Git workshop](user_training.md). -- [Git add](topics/git_add.md). -- [Git introduction](topics/git_intro.md). -- [Git log](topics/git_log.md). -- [Git stash](topics/stash.md). -- [Merge conflicts](topics/merge_conflicts.md). -- [Rollback commits](topics/rollback_commits.md). -- [Subtree](topics/subtree.md). -- [Unstage](topics/unstage.md). - -## Additional Resources - -1. [GitLab Documentation](https://docs.gitlab.com) -1. [GUI Clients](https://git-scm.com/downloads/guis) -1. [Pro Git book](https://git-scm.com/book/en/v2) -1. <!-- vale gitlab.Spelling = NO --> [Platzi Course](https://courses.platzi.com/courses/git-gitlab/) <!-- vale gitlab.Spelling = NO --> -1. [Code School tutorial](http://try.github.io/) -1. Contact us at `subscribers@gitlab.com` +<!-- This redirect file can be deleted after <2021-08-13>. --> +<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page --> diff --git a/doc/university/training/logo.png b/doc/university/training/logo.png Binary files differdeleted file mode 100644 index c80f65c053e..00000000000 --- a/doc/university/training/logo.png +++ /dev/null diff --git a/doc/university/training/topics/env_setup.md b/doc/university/training/topics/env_setup.md index bd487731783..2fd0a6762e2 100644 --- a/doc/university/training/topics/env_setup.md +++ b/doc/university/training/topics/env_setup.md @@ -1,73 +1,8 @@ --- -stage: none -group: unassigned -info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments -comments: false +redirect_to: '../../../topics/index.md' --- -# Configure your environment +This document was removed. See our [topics](../../../topics/index.md) for similar content. -## Install - -- **Windows** - Install 'Git for Windows' from [Git for Windows](https://gitforwindows.org). -- **Mac** - - Type '`git`' in the Terminal application. - - If it's not installed, it prompts you to install it. - -- **GNU/Linux** - Enter `which git` in the Terminal application and press <kbd>Enter</kbd> to - determine if Git is installed on your system. - - - If the output of that command gives you the path to the Git executable, similar to - `/usr/bin/git`, then Git is already installed on your system. - - If the output of the command displays "command not found" error, Git isn't installed on your system. - - GitLab recommends installing Git with the default package manager of your distribution. - The following commands install Git on various GNU/Linux distributions using their - default package managers. After you run the command corresponding to your distribution - and complete the installation process, Git should be available on your system: - - - **Arch Linux and its derivatives** - `sudo pacman -S git` - - **Fedora, RHEL, and CentOS** - For the `yum` package manager run `sudo yum install git-all`, - and for the `dnf` package manager run `sudo dnf install git`. - - **Debian/Ubuntu and their derivatives** - `sudo apt-get install git` - - **Gentoo** - `sudo emerge --ask --verbose dev-vcs/git` - - **openSUSE** - `sudo zypper install git` -- **FreeBSD** - `sudo pkg install git` -- **OpenBSD** - `doas pkg_add git` - -## Configure Git - -One-time configuration of the Git client - -```shell -git config --global user.name "Your Name" -git config --global user.email you@example.com -``` - -## Configure SSH Key - -```shell -ssh-keygen -t rsa -b 4096 -C "you@computer-name" -``` - -```shell -# You will be prompted for the following information. Press enter to accept the defaults. Defaults appear in parentheses. -Generating public/private rsa key pair. -Enter file in which to save the key (/Users/you/.ssh/id_rsa): -Enter passphrase (empty for no passphrase): -Enter same passphrase again: -Your identification has been saved in /Users/you/.ssh/id_rsa. -Your public key has been saved in /Users/you/.ssh/id_rsa.pub. -The key fingerprint is: -39:fc:ce:94:f4:09:13:95:64:9a:65:c1:de:05:4d:01 you@computer-name -``` - -Copy your public key and add it to your GitLab profile - -```shell -cat ~/.ssh/id_rsa.pub -``` - -```shell -ssh-rsa AAAAB3NzaC1yc2EAAAADAQEL17Ufacg8cDhlQMS5NhV8z3GHZdhCrZbl4gz you@example.com -``` +<!-- This redirect file can be deleted after <2021-08-13>. --> +<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page --> diff --git a/doc/university/training/topics/git_intro.md b/doc/university/training/topics/git_intro.md index 416d421956c..2fd0a6762e2 100644 --- a/doc/university/training/topics/git_intro.md +++ b/doc/university/training/topics/git_intro.md @@ -1,27 +1,8 @@ --- -stage: none -group: unassigned -info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments -comments: false +redirect_to: '../../../topics/index.md' --- -# Git introduction +This document was removed. See our [topics](../../../topics/index.md) for similar content. -## Intro - -<https://git-scm.com/about> - -- Distributed version control - - Does not rely on connection to a central server - - Many copies of the complete history -- Powerful branching and merging -- Adapts to nearly any workflow -- Fast, reliable and stable file format - -## Help - -Use the tools at your disposal when you get stuck. - -- Use '`git help <command>`' command -- Use Google -- Read documentation at <https://git-scm.com> +<!-- This redirect file can be deleted after <2021-08-13>. --> +<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page --> diff --git a/doc/university/training/topics/merge_requests.md b/doc/university/training/topics/merge_requests.md index c064bd78036..80ead103fdd 100644 --- a/doc/university/training/topics/merge_requests.md +++ b/doc/university/training/topics/merge_requests.md @@ -1,8 +1,8 @@ --- -redirect_to: '../../../topics/git/merge_requests.md' +redirect_to: '../../../user/project/merge_requests/index.md' --- -This document was moved to [another location](../../../topics/git/merge_requests.md). +This document was moved to [another location](../../../user/project/merge_requests/index.md). <!-- This redirect file can be deleted after <2021-08-13>. --> <!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page --> diff --git a/doc/university/training/user_training.md b/doc/university/training/user_training.md index e9cca233d6f..fa870b151b2 100644 --- a/doc/university/training/user_training.md +++ b/doc/university/training/user_training.md @@ -1,346 +1,8 @@ --- -stage: none -group: unassigned -info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments -comments: false -type: reference +redirect_to: '../../topics/index.md' --- -# GitLab Git Workshop +This document was removed. See our [topics](../../topics/index.md) for similar content. -## Agenda - -1. Brief history of Git. -1. GitLab walkthrough. -1. Configure your environment. -1. Workshop. - -## Git introduction - -<https://git-scm.com/about> - -- Distributed version control. - - Does not rely on connection to a central server. - - Many copies of the complete history. -- Powerful branching and merging. -- Adapts to nearly any workflow. -- Fast, reliable and stable file format. - -## Help - -Use the tools at your disposal when you get stuck. - -- Use '`git help <command>`' command. -- Use Google. -- Read documentation at <https://git-scm.com>. - -## GitLab Walkthrough - - - -## Configure your environment - -- Windows: Install 'Git for Windows' - -> <https://gitforwindows.org> - -- Mac: Type '`git`' in the Terminal application. - -> If it's not installed, it prompts you to install it. - -- Debian: '`sudo apt-get install git-all`' or Red Hat '`sudo yum install git-all`' - -## Git Workshop - -### Overview - -1. Configure Git. -1. Configure SSH Key. -1. Create a project. -1. Committing. -1. Feature branching. -1. Merge requests. -1. Feedback and Collaboration. - -## Configure Git - -One-time configuration of the Git client: - -```shell -git config --global user.name "Your Name" -git config --global user.email you@example.com -``` - -## Configure SSH Key - -```shell -ssh-keygen -t rsa -b 4096 -C "you@computer-name" -``` - -```shell -# You will be prompted for the following information. Press enter to accept the defaults. Defaults appear in parentheses. -Generating public/private rsa key pair. -Enter file in which to save the key (/Users/you/.ssh/id_rsa): -Enter passphrase (empty for no passphrase): -Enter same passphrase again: -Your identification has been saved in /Users/you/.ssh/id_rsa. -Your public key has been saved in /Users/you/.ssh/id_rsa.pub. -The key fingerprint is: -39:fc:ce:94:f4:09:13:95:64:9a:65:c1:de:05:4d:01 you@computer-name -``` - -Copy your public key and add it to your GitLab profile: - -```shell -cat ~/.ssh/id_rsa.pub -``` - -```shell -ssh-rsa AAAAB3NzaC1yc2EAAAADAQEL17Ufacg8cDhlQMS5NhV8z3GHZdhCrZbl4gz you@example.com -``` - -## Create a project - -- Create a project in your user namespace. - - Choose to import from **Any Repository by URL** and use <https://gitlab.com/gitlab-org/training-examples.git>. -- Create a '`development`' or '`workspace`' directory in your home directory. -- Clone the '`training-examples`' project. - -## Commands (project) - -```shell -mkdir ~/development -cd ~/development - --or- - -mkdir ~/workspace -cd ~/workspace - -git clone git@gitlab.example.com:<username>/training-examples.git -cd training-examples -``` - -## Git concepts - -### Untracked files - -New files that Git has not been told to track previously. - -### Working area - -Files that have been modified but are not committed. - -### Staging area - -Modified files that have been marked to go in the next commit. - -## Committing - -1. Edit '`edit_this_file.rb`' in '`training-examples`'. -1. See it listed as a changed file (working area). -1. View the differences. -1. Stage the file. -1. Commit. -1. Push the commit to the remote. -1. View the Git log. - -## Commands (committing) - -```shell -# Edit `edit_this_file.rb` -git status -git diff -git add <file> -git commit -m 'My change' -git push origin master -git log -``` - -## Feature branching - -- Efficient parallel workflow for teams. -- Develop each feature in a branch. -- Keeps changes isolated. -- Consider a 1-to-1 link to issues. -- Push branches to the server frequently. - - Hint: This is a cheap backup for your work-in-progress code. - -## Feature branching steps - -1. Create a new feature branch called 'squash_some_bugs'. -1. Edit '`bugs.rb`' and remove all the bugs. -1. Commit. -1. Push. - -## Commands (feature branching) - -```shell -git checkout -b squash_some_bugs -# Edit `bugs.rb` -git status -git add bugs.rb -git commit -m 'Fix some buggy code' -git push origin squash_some_bugs -``` - -## Merge requests - -- When you want feedback create a merge request. -- Target is the 'default' branch (usually master). -- Assign or mention the person you would like to review. -- Add `[Draft]` to the title if it's a work in progress. -- When accepting, always delete the branch. -- Anyone can comment, not just the assignee. -- Push corrections to the same branch. - -## Merge requests steps - -Create your first merge request: - -1. Use the blue button in the activity feed. -1. View the diff (changes) and leave a comment. -1. Push a new commit to the same branch. -1. Review the changes again and notice the update. - -## Feedback and Collaboration - -- Merge requests are a time for feedback and collaboration. -- Giving feedback is hard. -- Be as kind as possible. -- Receiving feedback is hard. -- Be as receptive as possible. -- Feedback is about the best code, not the person. You are not your code. - -## Feedback and Collaboration resources - -<!-- vale gitlab.Spelling = NO --> - -Review the Thoughtbot code-review guide for suggestions to follow when reviewing merge requests: -<https://github.com/thoughtbot/guides/tree/master/code-review>. - -<!-- vale gitlab.Spelling = YES --> - -See GitLab merge requests for examples: <https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests>. - -## Explore GitLab projects - - - -- Dashboard -- User Preferences -- README, Changelog, License shortcuts -- Issues -- Milestones and Labels -- Manage project members -- Project settings - -## Tags - -- Useful for marking deployments and releases. -- Annotated tags are an unchangeable part of Git history. -- Soft/lightweight tags can be set and removed at any time. -- Many projects combine an annotated release tag with a stable branch. -- Consider setting deployment/release tags automatically. - -## Tags steps - -1. Create a lightweight tag. -1. Create an annotated tag. -1. Push the tags to the remote repository. - -Additional resources: <https://git-scm.com/book/en/v2/Git-Basics-Tagging>. - -## Commands (tags) - -```shell -git checkout master - -# Lightweight tag -git tag my_lightweight_tag - -# Annotated tag -git tag -a v1.0 -m 'Version 1.0' -git tag - -git push origin --tags -``` - -## Merge conflicts - -- Happen often. -- Learning to fix conflicts is hard. -- Practice makes perfect. -- Force push after fixing conflicts. Be careful! - -## Merge conflicts steps - -1. Checkout a new branch and edit `conflicts.rb`. Add 'Line4' and 'Line5'. -1. Commit and push. -1. Checkout master and edit `conflicts.rb`. Add 'Line6' and 'Line7' below 'Line3'. -1. Commit and push to master. -1. Create a merge request. - -## Merge conflicts commands - -After creating a merge request you should notice that conflicts exist. Resolve -the conflicts locally by rebasing. - -```shell -git rebase master - -# Fix conflicts by editing the files. - -git add conflicts.rb -git commit -m 'Fix conflicts' -git rebase --continue -git push origin <branch> -f -``` - -## Rebase with squash - -You may end up with a commit log that looks like this: - -```plaintext -Fix issue #13 -Test -Fix -Fix again -Test -Test again -Does this work? -``` - -Squash these in to meaningful commits using an interactive rebase. - -## Rebase with squash commands - -Squash the commits on the same branch we used for the merge conflicts step. - -```shell -git rebase -i master -``` - -In the editor, leave the first commit as `pick` and set others to `fixup`. - -## Questions? - - - -Thank you for your hard work! - -## Additional Resources - -See [additional resources](index.md#additional-resources). - -<!-- ## Troubleshooting - -Include any troubleshooting steps that you can foresee. If you know beforehand what issues -one might have when setting this up, or when something is changed, or on upgrading, it's -important to describe those, too. Think of things that may go wrong and include them here. -This is important to minimize requests for support, and to avoid doc comments with -questions that you know someone might ask. - -Each scenario can be a third-level heading, e.g. `### Getting error message X`. -If you have none to add when creating a doc, leave this section in place -but commented out to help encourage others to add to it in the future. --> +<!-- This redirect file can be deleted after <2021-08-13>. --> +<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page --> diff --git a/doc/user/application_security/sast/index.md b/doc/user/application_security/sast/index.md index b0e5877ae84..23e2621a732 100644 --- a/doc/user/application_security/sast/index.md +++ b/doc/user/application_security/sast/index.md @@ -653,6 +653,7 @@ registry.gitlab.com/gitlab-org/security-products/analyzers/nodejs-scan:2 registry.gitlab.com/gitlab-org/security-products/analyzers/phpcs-security-audit:2 registry.gitlab.com/gitlab-org/security-products/analyzers/pmd-apex:2 registry.gitlab.com/gitlab-org/security-products/analyzers/security-code-scan:2 +registry.gitlab.com/gitlab-org/security-products/analyzers/semgrep:2 registry.gitlab.com/gitlab-org/security-products/analyzers/sobelow:2 registry.gitlab.com/gitlab-org/security-products/analyzers/spotbugs:2 ``` @@ -682,7 +683,7 @@ Support for custom certificate authorities was introduced in the following versi | `phpcs-security-audit` | [v2.8.2](https://gitlab.com/gitlab-org/security-products/analyzers/phpcs-security-audit/-/releases/v2.8.2) | | `pmd-apex` | [v2.1.0](https://gitlab.com/gitlab-org/security-products/analyzers/pmd-apex/-/releases/v2.1.0) | | `security-code-scan` | [v2.7.3](https://gitlab.com/gitlab-org/security-products/analyzers/security-code-scan/-/releases/v2.7.3) | -| `semgrep` | [v0.0.1](https://gitlab.com/gitlab-org/security-products/analyzers/security-code-scan/-/releases/v0.0.1) | +| `semgrep` | [v0.0.1](https://gitlab.com/gitlab-org/security-products/analyzers/semgrep/-/releases/v0.0.1) | | `sobelow` | [v2.2.0](https://gitlab.com/gitlab-org/security-products/analyzers/sobelow/-/releases/v2.2.0) | | `spotbugs` | [v2.7.1](https://gitlab.com/gitlab-org/security-products/analyzers/spotbugs/-/releases/v2.7.1) | diff --git a/lib/gitlab/ci/templates/Indeni.Cloudrail.gitlab-ci-.yml b/lib/gitlab/ci/templates/Indeni.Cloudrail.gitlab-ci.yml index c7fb1321055..7f33d048c1e 100644 --- a/lib/gitlab/ci/templates/Indeni.Cloudrail.gitlab-ci-.yml +++ b/lib/gitlab/ci/templates/Indeni.Cloudrail.gitlab-ci.yml @@ -29,12 +29,8 @@ default: before_script: - cd ${CI_PROJECT_DIR}/my_folder_with_terraform_content -stages: - - init_and_plan - - cloudrail - init_and_plan: - stage: init_and_plan + stage: build image: registry.gitlab.com/gitlab-org/terraform-images/releases/0.13 rules: - if: $SAST_DISABLED @@ -52,7 +48,7 @@ init_and_plan: - ./**/.terraform cloudrail_scan: - stage: cloudrail + stage: test image: indeni/cloudrail-cli:1.2.44 rules: - if: $SAST_DISABLED diff --git a/lib/gitlab/ci/templates/Security/Secure-Binaries.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/Secure-Binaries.gitlab-ci.yml index fddfc0deb28..ac975fbbeab 100644 --- a/lib/gitlab/ci/templates/Security/Secure-Binaries.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Security/Secure-Binaries.gitlab-ci.yml @@ -13,7 +13,7 @@ variables: SECURE_BINARIES_ANALYZERS: >- - bandit, brakeman, gosec, spotbugs, flawfinder, phpcs-security-audit, security-code-scan, nodejs-scan, eslint, secrets, sobelow, pmd-apex, kubesec, + bandit, brakeman, gosec, spotbugs, flawfinder, phpcs-security-audit, security-code-scan, nodejs-scan, eslint, secrets, sobelow, pmd-apex, kubesec, semgrep, bundler-audit, retire.js, gemnasium, gemnasium-maven, gemnasium-python, klar, clair-vulnerabilities-db, license-finder, @@ -134,6 +134,13 @@ secrets: variables: SECURE_BINARIES_ANALYZER_VERSION: "3" +semgrep: + extends: .download_images + only: + variables: + - $SECURE_BINARIES_DOWNLOAD_IMAGES == "true" && + $SECURE_BINARIES_ANALYZERS =~ /\bsemgrep\b/ + sobelow: extends: .download_images only: diff --git a/locale/gitlab.pot b/locale/gitlab.pot index d9d4f89eca6..a8648d64be0 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -31474,6 +31474,9 @@ msgstr "" msgid "Survey Response" msgstr "" +msgid "Switch Branch" +msgstr "" + msgid "Switch branch/tag" msgstr "" diff --git a/qa/qa/page/file/shared/commit_message.rb b/qa/qa/page/file/shared/commit_message.rb index 906f5f3581a..4c25e8a480b 100644 --- a/qa/qa/page/file/shared/commit_message.rb +++ b/qa/qa/page/file/shared/commit_message.rb @@ -11,7 +11,7 @@ module QA super base.view 'app/views/shared/_commit_message_container.html.haml' do - element :commit_message, "text_area_tag 'commit_message'" # rubocop:disable QA/ElementWithPattern + element :commit_message_field end base.view 'app/views/projects/commits/_commit.html.haml' do @@ -20,7 +20,7 @@ module QA end def add_commit_message(message) - fill_in 'commit_message', with: message + fill_element(:commit_message_field, message) end def has_commit_message?(text) diff --git a/qa/qa/page/merge_request/show.rb b/qa/qa/page/merge_request/show.rb index 7ae2b5605dc..3da001786c5 100644 --- a/qa/qa/page/merge_request/show.rb +++ b/qa/qa/page/merge_request/show.rb @@ -7,50 +7,16 @@ module QA include Page::Component::Note include Page::Component::Issuable::Sidebar - view 'app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue' do - element :download_dropdown - element :download_email_patches_menu_item - element :download_plain_diff_menu_item - element :open_in_web_ide_button - end - - view 'app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.vue' do - element :merge_request_pipeline_info_content - element :pipeline_link - end - - view 'app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue' do - element :merge_button - element :fast_forward_message_content - element :merge_moment_dropdown - element :merge_immediately_menu_item - end - - view 'app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled.vue' do - element :merge_request_status_content - end - - view 'app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue' do - element :merged_status_content - end - - view 'app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_failed_to_merge.vue' do - element :merge_request_error_content - end - - view 'app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue' do - element :mr_rebase_button - element :no_fast_forward_message_content + view 'app/assets/javascripts/batch_comments/components/preview_dropdown.vue' do + element :review_preview_dropdown end - view 'app/assets/javascripts/vue_merge_request_widget/components/states/squash_before_merge.vue' do - element :squash_checkbox + view 'app/assets/javascripts/batch_comments/components/publish_button.vue' do + element :submit_review_button end - view 'app/views/projects/merge_requests/show.html.haml' do - element :notes_tab - element :commits_tab - element :diffs_tab + view 'app/assets/javascripts/batch_comments/components/review_bar.vue' do + element :review_bar_content end view 'app/assets/javascripts/diffs/components/compare_dropdown_layout.vue' do @@ -70,33 +36,60 @@ module QA view 'app/assets/javascripts/diffs/components/diff_row.vue' do element :diff_comment_button + element :new_diff_line_link end - view 'app/assets/javascripts/diffs/components/inline_diff_table_row.vue' do - element :new_diff_line_link + view 'app/assets/javascripts/notes/components/note_form.vue' do + element :start_review_button + element :comment_now_button end - view 'app/views/projects/merge_requests/_mr_title.html.haml' do - element :edit_button + view 'app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue' do + element :download_dropdown + element :download_email_patches_menu_item + element :download_plain_diff_menu_item + element :open_in_web_ide_button end - view 'app/assets/javascripts/batch_comments/components/publish_button.vue' do - element :submit_review_button + view 'app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.vue' do + element :merge_request_pipeline_info_content + element :pipeline_link end - view 'app/assets/javascripts/batch_comments/components/review_bar.vue' do - element :review_bar_content + view 'app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_failed_to_merge.vue' do + element :merge_request_error_content end - view 'app/assets/javascripts/notes/components/note_form.vue' do - element :unresolve_review_discussion_checkbox - element :resolve_review_discussion_checkbox - element :start_review_button - element :comment_now_button + view 'app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue' do + element :cherry_pick_button + element :merged_status_content + element :revert_button end - view 'app/assets/javascripts/batch_comments/components/preview_dropdown.vue' do - element :review_preview_toggle + view 'app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue' do + element :mr_rebase_button + element :no_fast_forward_message_content + end + + view 'app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue' do + element :merge_button + element :fast_forward_message_content + element :merge_moment_dropdown + element :merge_immediately_menu_item + end + + view 'app/assets/javascripts/vue_merge_request_widget/components/states/squash_before_merge.vue' do + element :squash_checkbox + end + + view 'app/assets/javascripts/vue_shared/components/markdown/apply_suggestion.vue' do + element :apply_suggestion_dropdown + element :commit_message_field + element :commit_with_custom_message_button + end + + view 'app/assets/javascripts/vue_shared/components/markdown/header.vue' do + element :suggestion_button end view 'app/assets/javascripts/vue_shared/components/markdown/suggestion_diff_header.vue' do @@ -104,19 +97,22 @@ module QA element :add_suggestion_batch_button end - view 'app/assets/javascripts/vue_shared/components/markdown/header.vue' do - element :suggestion_button + view 'app/views/projects/merge_requests/_description.html.haml' do + element :description_content end - view 'app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue' do - element :revert_button - element :cherry_pick_button + view 'app/views/projects/merge_requests/_mr_box.html.haml' do + element :title_content end - view 'app/assets/javascripts/vue_shared/components/markdown/apply_suggestion.vue' do - element :apply_suggestion_button - element :commit_message_textbox - element :commit_with_custom_message_button + view 'app/views/projects/merge_requests/_mr_title.html.haml' do + element :edit_button + end + + view 'app/views/projects/merge_requests/show.html.haml' do + element :notes_tab + element :commits_tab + element :diffs_tab end def start_review @@ -131,21 +127,13 @@ module QA click_element(:target_version_dropdown) end - def comment_now - click_element(:comment_now_button) - - # After clicking the button, wait for it to disappear - # before moving on to the next part of the test - has_no_element?(:comment_now_button) - end - def version_dropdown_content find_element(:dropdown_content).text end def submit_pending_reviews within_element(:review_bar_content) do - click_element(:review_preview_toggle) + click_element(:review_preview_dropdown) click_element(:submit_review_button) # After clicking the button, wait for it to disappear @@ -154,22 +142,6 @@ module QA end end - def discard_pending_reviews - within_element(:review_bar_content) do - click_element(:discard_review) - end - click_element(:modal_delete_pending_comments) - end - - def resolve_review_discussion - scroll_to_element(:start_review_button) - check_element(:resolve_review_discussion_checkbox) - end - - def unresolve_review_discussion - check_element(:unresolve_review_discussion_checkbox) - end - def add_comment_to_diff(text) wait_until(sleep_interval: 5) do has_css?('a[data-linenumber="1"]') @@ -230,11 +202,11 @@ module QA end def has_title?(title) - has_element?(:title, text: title) + has_element?(:title_content, text: title) end def has_description?(description) - has_element?(:description, text: description) + has_element?(:description_content, text: description) end def mark_to_squash @@ -253,11 +225,6 @@ module QA raise "Merge did not appear to be successful" unless merged? end - def merge_immediately! - click_element(:merge_moment_dropdown) - click_element(:merge_immediately_menu_item) - end - def merge_when_pipeline_succeeds! wait_until_ready_to_merge @@ -281,10 +248,6 @@ module QA has_element?(:merge_button, disabled: false) end - def merge_request_status - find_element(:merge_request_status_content).text - end - # Waits up 60 seconds and raises an error if unable to merge def wait_until_ready_to_merge has_element?(:merge_button) @@ -363,8 +326,8 @@ module QA end def apply_suggestion_with_message(message) - click_element(:apply_suggestion_button) - fill_element(:commit_message_textbox, message) + click_element(:apply_suggestion_dropdown) + fill_element(:commit_message_field, message) click_element(:commit_with_custom_message_button) end diff --git a/spec/features/markdown/copy_as_gfm_spec.rb b/spec/features/markdown/copy_as_gfm_spec.rb index c9dc764f93b..c700f878df6 100644 --- a/spec/features/markdown/copy_as_gfm_spec.rb +++ b/spec/features/markdown/copy_as_gfm_spec.rb @@ -426,8 +426,8 @@ RSpec.describe 'Copy as GFM', :js do html = <<~HTML <div class="md-suggestion"> - <div class="md-suggestion-header border-bottom-0 mt-2 qa-suggestion-diff-header js-suggestion-diff-header"> - <div class="qa-suggestion-diff-header js-suggestion-diff-header font-weight-bold"> + <div class="md-suggestion-header border-bottom-0 mt-2 js-suggestion-diff-header"> + <div class="js-suggestion-diff-header font-weight-bold"> Suggested change <a href="/gitlab/help/user/discussions/index.md#suggest-changes" aria-label="Help" class="js-help-btn"> <svg aria-hidden="true" class="s16 ic-question-o link-highlight"> diff --git a/spec/frontend/diffs/components/inline_diff_table_row_spec.js b/spec/frontend/diffs/components/inline_diff_table_row_spec.js index 66b63a7a1d0..9c3e00cd6cf 100644 --- a/spec/frontend/diffs/components/inline_diff_table_row_spec.js +++ b/spec/frontend/diffs/components/inline_diff_table_row_spec.js @@ -216,14 +216,14 @@ describe('InlineDiffTableRow', () => { const TEST_LINE_NUMBER = 1; describe.each` - lineProps | findLineNumber | expectedHref | expectedClickArg | expectedQaSelector - ${{ line_code: TEST_LINE_CODE, old_line: TEST_LINE_NUMBER }} | ${findLineNumberOld} | ${`#${TEST_LINE_CODE}`} | ${TEST_LINE_CODE} | ${undefined} - ${{ line_code: undefined, old_line: TEST_LINE_NUMBER }} | ${findLineNumberOld} | ${'#'} | ${undefined} | ${undefined} - ${{ line_code: undefined, left: { line_code: TEST_LINE_CODE }, old_line: TEST_LINE_NUMBER }} | ${findLineNumberOld} | ${'#'} | ${TEST_LINE_CODE} | ${undefined} - ${{ line_code: undefined, right: { line_code: TEST_LINE_CODE }, new_line: TEST_LINE_NUMBER }} | ${findLineNumberNew} | ${'#'} | ${TEST_LINE_CODE} | ${'new_diff_line_link'} + lineProps | findLineNumber | expectedHref | expectedClickArg + ${{ line_code: TEST_LINE_CODE, old_line: TEST_LINE_NUMBER }} | ${findLineNumberOld} | ${`#${TEST_LINE_CODE}`} | ${TEST_LINE_CODE} + ${{ line_code: undefined, old_line: TEST_LINE_NUMBER }} | ${findLineNumberOld} | ${'#'} | ${undefined} + ${{ line_code: undefined, left: { line_code: TEST_LINE_CODE }, old_line: TEST_LINE_NUMBER }} | ${findLineNumberOld} | ${'#'} | ${TEST_LINE_CODE} + ${{ line_code: undefined, right: { line_code: TEST_LINE_CODE }, new_line: TEST_LINE_NUMBER }} | ${findLineNumberNew} | ${'#'} | ${TEST_LINE_CODE} `( 'with line ($lineProps)', - ({ lineProps, findLineNumber, expectedHref, expectedClickArg, expectedQaSelector }) => { + ({ lineProps, findLineNumber, expectedHref, expectedClickArg }) => { beforeEach(() => { jest.spyOn(store, 'dispatch').mockImplementation(); createComponent({ @@ -236,7 +236,6 @@ describe('InlineDiffTableRow', () => { expect(findLineNumber().attributes()).toEqual({ href: expectedHref, 'data-linenumber': TEST_LINE_NUMBER.toString(), - 'data-qa-selector': expectedQaSelector, }); }); diff --git a/spec/frontend/issues_list/mock_data.js b/spec/frontend/issues_list/mock_data.js index d6a23c4dcff..5892a65e434 100644 --- a/spec/frontend/issues_list/mock_data.js +++ b/spec/frontend/issues_list/mock_data.js @@ -1,4 +1,7 @@ -import { OPERATOR_IS, OPERATOR_IS_NOT } from '~/issues_list/constants'; +import { + OPERATOR_IS, + OPERATOR_IS_NOT, +} from '~/vue_shared/components/filtered_search_bar/constants'; export const locationSearch = [ '?search=find+issues', diff --git a/spec/frontend/logs/components/log_advanced_filters_spec.js b/spec/frontend/logs/components/log_advanced_filters_spec.js index 111542ff33e..4e4052eb4d8 100644 --- a/spec/frontend/logs/components/log_advanced_filters_spec.js +++ b/spec/frontend/logs/components/log_advanced_filters_spec.js @@ -4,6 +4,7 @@ import { convertToFixedRange } from '~/lib/utils/datetime_range'; import LogAdvancedFilters from '~/logs/components/log_advanced_filters.vue'; import { TOKEN_TYPE_POD_NAME } from '~/logs/constants'; import { createStore } from '~/logs/stores'; +import { OPERATOR_IS_ONLY } from '~/vue_shared/components/filtered_search_bar/constants'; import { defaultTimeRange } from '~/vue_shared/constants'; import { mockPods, mockSearch } from '../mock_data'; @@ -77,7 +78,7 @@ describe('LogAdvancedFilters', () => { expect(getSearchToken(TOKEN_TYPE_POD_NAME)).toMatchObject({ title: 'Pod name', unique: true, - operators: [expect.objectContaining({ value: '=' })], + operators: OPERATOR_IS_ONLY, }); }); 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 1bb9c429a2f..5e04e20801a 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 @@ -3,6 +3,7 @@ import { shallowMount, createLocalVue } from '@vue/test-utils'; import Vuex from 'vuex'; import MembersFilteredSearchBar from '~/members/components/filter_sort/members_filtered_search_bar.vue'; import { MEMBER_TYPES } from '~/members/constants'; +import { OPERATOR_IS_ONLY } from '~/vue_shared/components/filtered_search_bar/constants'; import FilteredSearchBar from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue'; const localVue = createLocalVue(); @@ -65,7 +66,7 @@ describe('MembersFilteredSearchBar', () => { title: '2FA', token: GlFilteredSearchToken, unique: true, - operators: [{ value: '=', description: 'is' }], + operators: OPERATOR_IS_ONLY, options: [ { value: 'enabled', title: 'Enabled' }, { value: 'disabled', title: 'Disabled' }, @@ -99,7 +100,7 @@ describe('MembersFilteredSearchBar', () => { title: 'Membership', token: GlFilteredSearchToken, unique: true, - operators: [{ value: '=', description: 'is' }], + operators: OPERATOR_IS_ONLY, options: [ { value: 'exclude', title: 'Direct' }, { value: 'only', title: 'Inherited' }, diff --git a/spec/frontend/pipeline_editor/components/file-nav/branch_switcher_spec.js b/spec/frontend/pipeline_editor/components/file-nav/branch_switcher_spec.js index 42885bddcaa..d6763a7de41 100644 --- a/spec/frontend/pipeline_editor/components/file-nav/branch_switcher_spec.js +++ b/spec/frontend/pipeline_editor/components/file-nav/branch_switcher_spec.js @@ -1,11 +1,28 @@ -import { GlDropdown, GlDropdownItem, GlIcon } from '@gitlab/ui'; -import { shallowMount, createLocalVue } from '@vue/test-utils'; +import { + GlDropdown, + GlDropdownItem, + GlInfiniteScroll, + GlLoadingIcon, + GlSearchBoxByType, +} from '@gitlab/ui'; +import { createLocalVue, mount, shallowMount } from '@vue/test-utils'; import VueApollo from 'vue-apollo'; import createMockApollo from 'helpers/mock_apollo_helper'; import waitForPromises from 'helpers/wait_for_promises'; import BranchSwitcher from '~/pipeline_editor/components/file_nav/branch_switcher.vue'; import { DEFAULT_FAILURE } from '~/pipeline_editor/constants'; -import { mockDefaultBranch, mockProjectBranches, mockProjectFullPath } from '../../mock_data'; +import getAvailableBranches from '~/pipeline_editor/graphql/queries/available_branches.graphql'; +import { + mockBranchPaginationLimit, + mockDefaultBranch, + mockEmptySearchBranches, + mockProjectBranches, + mockProjectFullPath, + mockSearchBranches, + mockTotalBranches, + mockTotalBranchResults, + mockTotalSearchResults, +} from '../../mock_data'; const localVue = createLocalVue(); localVue.use(VueApollo); @@ -15,30 +32,64 @@ describe('Pipeline editor branch switcher', () => { let mockApollo; let mockAvailableBranchQuery; - const createComponentWithApollo = () => { - const resolvers = { - Query: { - project: mockAvailableBranchQuery, + const createComponent = ( + { isQueryLoading, mountFn, options } = { + isQueryLoading: false, + mountFn: shallowMount, + options: {}, + }, + ) => { + wrapper = mountFn(BranchSwitcher, { + propsData: { + paginationLimit: mockBranchPaginationLimit, }, - }; - - mockApollo = createMockApollo([], resolvers); - wrapper = shallowMount(BranchSwitcher, { - localVue, - apolloProvider: mockApollo, provide: { projectFullPath: mockProjectFullPath, + totalBranches: mockTotalBranches, + }, + mocks: { + $apollo: { + queries: { + availableBranches: { + loading: isQueryLoading, + }, + }, + }, }, data() { return { + branches: ['main'], currentBranch: mockDefaultBranch, }; }, + ...options, + }); + }; + + const createComponentWithApollo = (mountFn = shallowMount) => { + const handlers = [[getAvailableBranches, mockAvailableBranchQuery]]; + mockApollo = createMockApollo(handlers); + + createComponent({ + mountFn, + options: { + localVue, + apolloProvider: mockApollo, + mocks: {}, + data() { + return { + currentBranch: mockDefaultBranch, + }; + }, + }, }); }; const findDropdown = () => wrapper.findComponent(GlDropdown); const findDropdownItems = () => wrapper.findAll(GlDropdownItem); + const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon); + const findSearchBox = () => wrapper.findComponent(GlSearchBoxByType); + const findInfiniteScroll = () => wrapper.findComponent(GlInfiniteScroll); beforeEach(() => { mockAvailableBranchQuery = jest.fn(); @@ -48,7 +99,7 @@ describe('Pipeline editor branch switcher', () => { wrapper.destroy(); }); - describe('while querying', () => { + describe('when querying for the first time', () => { beforeEach(() => { createComponentWithApollo(); }); @@ -61,41 +112,31 @@ describe('Pipeline editor branch switcher', () => { describe('after querying', () => { beforeEach(async () => { mockAvailableBranchQuery.mockResolvedValue(mockProjectBranches); - createComponentWithApollo(); + createComponentWithApollo(mount); await waitForPromises(); }); - it('query is called with correct variables', async () => { - expect(mockAvailableBranchQuery).toHaveBeenCalledTimes(1); - expect(mockAvailableBranchQuery).toHaveBeenCalledWith( - expect.anything(), - { - fullPath: mockProjectFullPath, - }, - expect.anything(), - expect.anything(), - ); + it('renders search box', () => { + expect(findSearchBox().exists()).toBe(true); }); it('renders list of branches', () => { expect(findDropdown().exists()).toBe(true); - expect(findDropdownItems()).toHaveLength(mockProjectBranches.repository.branches.length); + expect(findDropdownItems()).toHaveLength(mockTotalBranchResults); }); - it('renders current branch at the top of the list with a check mark', () => { - const firstDropdownItem = findDropdownItems().at(0); - const icon = firstDropdownItem.findComponent(GlIcon); + it('renders current branch with a check mark', () => { + const defaultBranchInDropdown = findDropdownItems().at(0); - expect(firstDropdownItem.text()).toBe(mockDefaultBranch); - expect(icon.exists()).toBe(true); - expect(icon.props('name')).toBe('check'); + expect(defaultBranchInDropdown.text()).toBe(mockDefaultBranch); + expect(defaultBranchInDropdown.props('isChecked')).toBe(true); }); it('does not render check mark for other branches', () => { - const secondDropdownItem = findDropdownItems().at(1); - const icon = secondDropdownItem.findComponent(GlIcon); + const nonDefaultBranch = findDropdownItems().at(1); - expect(icon.classes()).toContain('gl-visibility-hidden'); + expect(nonDefaultBranch.text()).not.toBe(mockDefaultBranch); + expect(nonDefaultBranch.props('isChecked')).toBe(false); }); }); @@ -125,7 +166,7 @@ describe('Pipeline editor branch switcher', () => { beforeEach(async () => { jest.spyOn(window.history, 'pushState').mockImplementation(() => {}); mockAvailableBranchQuery.mockResolvedValue(mockProjectBranches); - createComponentWithApollo(); + createComponentWithApollo(mount); await waitForPromises(); }); @@ -168,4 +209,138 @@ describe('Pipeline editor branch switcher', () => { expect(wrapper.emitted('refetchContent')).toBeUndefined(); }); }); + + describe('when searching', () => { + beforeEach(async () => { + mockAvailableBranchQuery.mockResolvedValue(mockProjectBranches); + createComponentWithApollo(mount); + await waitForPromises(); + + mockAvailableBranchQuery.mockResolvedValue(mockSearchBranches); + }); + + describe('with a search term', () => { + it('calls query with correct variables', async () => { + findSearchBox().vm.$emit('input', 'te'); + await waitForPromises(); + + expect(mockAvailableBranchQuery).toHaveBeenCalledWith({ + limit: mockTotalBranches, // fetch all branches + offset: 0, + projectFullPath: mockProjectFullPath, + searchPattern: '*te*', + }); + }); + + it('fetches new list of branches', async () => { + expect(findDropdownItems()).toHaveLength(mockTotalBranchResults); + + findSearchBox().vm.$emit('input', 'te'); + await waitForPromises(); + + expect(findDropdownItems()).toHaveLength(mockTotalSearchResults); + }); + + it('does not hide dropdown when search result is empty', async () => { + mockAvailableBranchQuery.mockResolvedValue(mockEmptySearchBranches); + findSearchBox().vm.$emit('input', 'aaaaa'); + await waitForPromises(); + + expect(findDropdown().exists()).toBe(true); + expect(findDropdownItems()).toHaveLength(0); + }); + }); + + describe('without a search term', () => { + beforeEach(async () => { + findSearchBox().vm.$emit('input', 'te'); + await waitForPromises(); + + mockAvailableBranchQuery.mockResolvedValue(mockProjectBranches); + }); + + it('calls query with correct variables', async () => { + findSearchBox().vm.$emit('input', ''); + await waitForPromises(); + + expect(mockAvailableBranchQuery).toHaveBeenCalledWith({ + limit: mockBranchPaginationLimit, // only fetch first n branches first + offset: 0, + projectFullPath: mockProjectFullPath, + searchPattern: '*', + }); + }); + + it('fetches new list of branches', async () => { + expect(findDropdownItems()).toHaveLength(mockTotalSearchResults); + + findSearchBox().vm.$emit('input', ''); + await waitForPromises(); + + expect(findDropdownItems()).toHaveLength(mockTotalBranchResults); + }); + }); + }); + + describe('loading icon', () => { + test.each` + isQueryLoading | isRendered + ${true} | ${true} + ${false} | ${false} + `('checks if query is loading before rendering', ({ isQueryLoading, isRendered }) => { + createComponent({ isQueryLoading, mountFn: mount }); + + expect(findLoadingIcon().exists()).toBe(isRendered); + }); + }); + + describe('when scrolling to the bottom of the list', () => { + beforeEach(async () => { + mockAvailableBranchQuery.mockResolvedValue(mockProjectBranches); + createComponentWithApollo(); + await waitForPromises(); + }); + + afterEach(() => { + mockAvailableBranchQuery.mockClear(); + }); + + describe('when search term is empty', () => { + it('fetches more branches', async () => { + expect(mockAvailableBranchQuery).toHaveBeenCalledTimes(1); + + findInfiniteScroll().vm.$emit('bottomReached'); + await waitForPromises(); + + expect(mockAvailableBranchQuery).toHaveBeenCalledTimes(2); + }); + + it('calls the query with the correct variables', async () => { + findInfiniteScroll().vm.$emit('bottomReached'); + await waitForPromises(); + + expect(mockAvailableBranchQuery).toHaveBeenCalledWith({ + limit: mockBranchPaginationLimit, + offset: mockBranchPaginationLimit, // offset changed + projectFullPath: mockProjectFullPath, + searchPattern: '*', + }); + }); + }); + + describe('when search term exists', () => { + it('does not fetch more branches', async () => { + findSearchBox().vm.$emit('input', 'te'); + await waitForPromises(); + + expect(mockAvailableBranchQuery).toHaveBeenCalledTimes(2); + mockAvailableBranchQuery.mockClear(); + + findInfiniteScroll().vm.$emit('bottomReached'); + await waitForPromises(); + + expect(mockAvailableBranchQuery).not.toHaveBeenCalled(); + }); + }); + }); }); diff --git a/spec/frontend/pipeline_editor/graphql/resolvers_spec.js b/spec/frontend/pipeline_editor/graphql/resolvers_spec.js index f0932fc55d3..d39c0d80296 100644 --- a/spec/frontend/pipeline_editor/graphql/resolvers_spec.js +++ b/spec/frontend/pipeline_editor/graphql/resolvers_spec.js @@ -9,7 +9,6 @@ import { mockDefaultBranch, mockLintResponse, mockProjectFullPath, - mockProjectBranches, } from '../mock_data'; jest.mock('~/api', () => { @@ -47,23 +46,6 @@ describe('~/pipeline_editor/graphql/resolvers', () => { await expect(result.rawData).resolves.toBe(mockCiYml); }); }); - - describe('project', () => { - it('resolves project data with type names', async () => { - const result = await resolvers.Query.project(); - - // eslint-disable-next-line no-underscore-dangle - expect(result.__typename).toBe('Project'); - }); - - it('resolves project with available list of branches', async () => { - const result = await resolvers.Query.project(); - - expect(result.repository.branches).toHaveLength( - mockProjectBranches.repository.branches.length, - ); - }); - }); }); describe('Mutation', () => { diff --git a/spec/frontend/pipeline_editor/mock_data.js b/spec/frontend/pipeline_editor/mock_data.js index d13ac2780ca..e08fce3ceb9 100644 --- a/spec/frontend/pipeline_editor/mock_data.js +++ b/spec/frontend/pipeline_editor/mock_data.js @@ -139,18 +139,54 @@ export const mergeUnwrappedCiConfig = (mergedConfig) => { }; export const mockProjectBranches = { - __typename: 'Project', - repository: { - __typename: 'Repository', - branches: [ - { __typename: 'Branch', name: 'main' }, - { __typename: 'Branch', name: 'develop' }, - { __typename: 'Branch', name: 'production' }, - { __typename: 'Branch', name: 'test' }, - ], + data: { + project: { + repository: { + branchNames: [ + 'main', + 'develop', + 'production', + 'test', + 'better-feature', + 'feature-abc', + 'update-ci', + 'mock-feature', + 'test-merge-request', + 'staging', + ], + }, + }, }, }; +export const mockTotalBranchResults = + mockProjectBranches.data.project.repository.branchNames.length; + +export const mockSearchBranches = { + data: { + project: { + repository: { + branchNames: ['test', 'better-feature', 'update-ci', 'test-merge-request'], + }, + }, + }, +}; + +export const mockTotalSearchResults = mockSearchBranches.data.project.repository.branchNames.length; + +export const mockEmptySearchBranches = { + data: { + project: { + repository: { + branchNames: [], + }, + }, + }, +}; + +export const mockBranchPaginationLimit = 10; +export const mockTotalBranches = 20; // must be greater than mockBranchPaginationLimit to test pagination + export const mockProjectPipeline = { pipeline: { commitPath: '/-/commit/aabbccdd', diff --git a/spec/frontend/pipelines/components/pipelines_filtered_search_spec.js b/spec/frontend/pipelines/components/pipelines_filtered_search_spec.js index d2a3b134845..b0dbba37b94 100644 --- a/spec/frontend/pipelines/components/pipelines_filtered_search_spec.js +++ b/spec/frontend/pipelines/components/pipelines_filtered_search_spec.js @@ -4,6 +4,7 @@ import MockAdapter from 'axios-mock-adapter'; import Api from '~/api'; import axios from '~/lib/utils/axios_utils'; import PipelinesFilteredSearch from '~/pipelines/components/pipelines_list/pipelines_filtered_search.vue'; +import { OPERATOR_IS_ONLY } from '~/vue_shared/components/filtered_search_bar/constants'; import { users, mockSearch, branches, tags } from '../mock_data'; describe('Pipelines filtered search', () => { @@ -57,7 +58,7 @@ describe('Pipelines filtered search', () => { title: 'Trigger author', unique: true, projectId: '21', - operators: [expect.objectContaining({ value: '=' })], + operators: OPERATOR_IS_ONLY, }); expect(findBranchToken()).toMatchObject({ @@ -66,7 +67,7 @@ describe('Pipelines filtered search', () => { title: 'Branch name', unique: true, projectId: '21', - operators: [expect.objectContaining({ value: '=' })], + operators: OPERATOR_IS_ONLY, }); expect(findStatusToken()).toMatchObject({ @@ -74,7 +75,7 @@ describe('Pipelines filtered search', () => { icon: 'status', title: 'Status', unique: true, - operators: [expect.objectContaining({ value: '=' })], + operators: OPERATOR_IS_ONLY, }); expect(findTagToken()).toMatchObject({ @@ -82,7 +83,7 @@ describe('Pipelines filtered search', () => { icon: 'tag', title: 'Tag name', unique: true, - operators: [expect.objectContaining({ value: '=' })], + operators: OPERATOR_IS_ONLY, }); }); diff --git a/spec/frontend/vue_mr_widget/components/states/__snapshots__/mr_widget_auto_merge_enabled_spec.js.snap b/spec/frontend/vue_mr_widget/components/states/__snapshots__/mr_widget_auto_merge_enabled_spec.js.snap index 0b6e4912d06..2b8e39ce9ad 100644 --- a/spec/frontend/vue_mr_widget/components/states/__snapshots__/mr_widget_auto_merge_enabled_spec.js.snap +++ b/spec/frontend/vue_mr_widget/components/states/__snapshots__/mr_widget_auto_merge_enabled_spec.js.snap @@ -16,7 +16,6 @@ exports[`MRWidgetAutoMergeEnabled when graphql is disabled template should have > <span class="gl-mr-3" - data-qa-selector="merge_request_status_content" > <span class="js-status-text-before-author" @@ -108,7 +107,6 @@ exports[`MRWidgetAutoMergeEnabled when graphql is enabled template should have c > <span class="gl-mr-3" - data-qa-selector="merge_request_status_content" > <span class="js-status-text-before-author" diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/mock_data.js b/spec/frontend/vue_shared/components/filtered_search_bar/mock_data.js index 3b5d0dba195..23e4deab9c1 100644 --- a/spec/frontend/vue_shared/components/filtered_search_bar/mock_data.js +++ b/spec/frontend/vue_shared/components/filtered_search_bar/mock_data.js @@ -1,6 +1,7 @@ import { GlFilteredSearchToken } from '@gitlab/ui'; import { mockLabels } from 'jest/vue_shared/components/sidebar/labels_select_vue/mock_data'; import Api from '~/api'; +import { OPERATOR_IS_ONLY } from '~/vue_shared/components/filtered_search_bar/constants'; import AuthorToken from '~/vue_shared/components/filtered_search_bar/tokens/author_token.vue'; import BranchToken from '~/vue_shared/components/filtered_search_bar/tokens/branch_token.vue'; import EmojiToken from '~/vue_shared/components/filtered_search_bar/tokens/emoji_token.vue'; @@ -84,7 +85,7 @@ export const mockBranchToken = { title: 'Source Branch', unique: true, token: BranchToken, - operators: [{ value: '=', description: 'is', default: 'true' }], + operators: OPERATOR_IS_ONLY, fetchBranches: Api.branches.bind(Api), }; @@ -95,7 +96,7 @@ export const mockAuthorToken = { unique: false, symbol: '@', token: AuthorToken, - operators: [{ value: '=', description: 'is', default: 'true' }], + operators: OPERATOR_IS_ONLY, fetchPath: 'gitlab-org/gitlab-test', fetchAuthors: Api.projectUsers.bind(Api), }; @@ -116,7 +117,7 @@ export const mockLabelToken = { unique: false, symbol: '~', token: LabelToken, - operators: [{ value: '=', description: 'is', default: 'true' }], + operators: OPERATOR_IS_ONLY, fetchLabels: () => Promise.resolve(mockLabels), }; @@ -127,7 +128,7 @@ export const mockMilestoneToken = { unique: true, symbol: '%', token: MilestoneToken, - operators: [{ value: '=', description: 'is', default: 'true' }], + operators: OPERATOR_IS_ONLY, fetchMilestones: () => Promise.resolve({ data: mockMilestones }), }; @@ -138,7 +139,7 @@ export const mockEpicToken = { unique: true, symbol: '&', token: EpicToken, - operators: [{ value: '=', description: 'is', default: 'true' }], + operators: OPERATOR_IS_ONLY, idProperty: 'iid', fetchEpics: () => Promise.resolve({ data: mockEpics }), }; @@ -149,7 +150,7 @@ export const mockReactionEmojiToken = { title: 'My-Reaction', unique: true, token: EmojiToken, - operators: [{ value: '=', description: 'is', default: 'true' }], + operators: OPERATOR_IS_ONLY, fetchEmojis: () => Promise.resolve(mockEmojis), }; @@ -159,7 +160,7 @@ export const mockMembershipToken = { title: 'Membership', token: GlFilteredSearchToken, unique: true, - operators: [{ value: '=', description: 'is' }], + operators: OPERATOR_IS_ONLY, options: [ { value: 'exclude', title: 'Direct' }, { value: 'only', title: 'Inherited' }, diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/author_token_spec.js b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/author_token_spec.js index 765e576914c..3b50927dcc6 100644 --- a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/author_token_spec.js +++ b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/author_token_spec.js @@ -11,8 +11,8 @@ import { deprecatedCreateFlash as createFlash } from '~/flash'; import axios from '~/lib/utils/axios_utils'; import { - DEFAULT_LABEL_NONE, DEFAULT_LABEL_ANY, + DEFAULT_NONE_ANY, } from '~/vue_shared/components/filtered_search_bar/constants'; import AuthorToken from '~/vue_shared/components/filtered_search_bar/tokens/author_token.vue'; @@ -159,7 +159,7 @@ describe('AuthorToken', () => { }); it('renders provided defaultAuthors as suggestions', async () => { - const defaultAuthors = [DEFAULT_LABEL_NONE, DEFAULT_LABEL_ANY]; + const defaultAuthors = DEFAULT_NONE_ANY; wrapper = createComponent({ active: true, config: { ...mockAuthorToken, defaultAuthors }, diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/branch_token_spec.js b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/branch_token_spec.js index 28741fe0ab4..331c9c2c14d 100644 --- a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/branch_token_spec.js +++ b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/branch_token_spec.js @@ -10,10 +10,7 @@ import waitForPromises from 'helpers/wait_for_promises'; import createFlash from '~/flash'; import axios from '~/lib/utils/axios_utils'; -import { - DEFAULT_LABEL_NONE, - DEFAULT_LABEL_ANY, -} from '~/vue_shared/components/filtered_search_bar/constants'; +import { DEFAULT_NONE_ANY } from '~/vue_shared/components/filtered_search_bar/constants'; import BranchToken from '~/vue_shared/components/filtered_search_bar/tokens/branch_token.vue'; import { mockBranches, mockBranchToken } from '../mock_data'; @@ -137,7 +134,7 @@ describe('BranchToken', () => { }); describe('template', () => { - const defaultBranches = [DEFAULT_LABEL_NONE, DEFAULT_LABEL_ANY]; + const defaultBranches = DEFAULT_NONE_ANY; async function showSuggestions() { const tokenSegments = wrapper.findAll(GlFilteredSearchTokenSegment); const suggestionsSegment = tokenSegments.at(2); diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/emoji_token_spec.js b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/emoji_token_spec.js index 231f2f01428..fb48aea8e4f 100644 --- a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/emoji_token_spec.js +++ b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/emoji_token_spec.js @@ -13,6 +13,7 @@ import axios from '~/lib/utils/axios_utils'; import { DEFAULT_LABEL_NONE, DEFAULT_LABEL_ANY, + DEFAULT_NONE_ANY, } from '~/vue_shared/components/filtered_search_bar/constants'; import EmojiToken from '~/vue_shared/components/filtered_search_bar/tokens/emoji_token.vue'; @@ -137,7 +138,7 @@ describe('EmojiToken', () => { }); describe('template', () => { - const defaultEmojis = [DEFAULT_LABEL_NONE, DEFAULT_LABEL_ANY]; + const defaultEmojis = DEFAULT_NONE_ANY; beforeEach(async () => { wrapper = createComponent({ diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/label_token_spec.js b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/label_token_spec.js index 8528c062426..57514a0c499 100644 --- a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/label_token_spec.js +++ b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/label_token_spec.js @@ -16,8 +16,7 @@ import axios from '~/lib/utils/axios_utils'; import { DEFAULT_LABELS, - DEFAULT_LABEL_NONE, - DEFAULT_LABEL_ANY, + DEFAULT_NONE_ANY, } from '~/vue_shared/components/filtered_search_bar/constants'; import LabelToken from '~/vue_shared/components/filtered_search_bar/tokens/label_token.vue'; @@ -176,7 +175,7 @@ describe('LabelToken', () => { }); describe('template', () => { - const defaultLabels = [DEFAULT_LABEL_NONE, DEFAULT_LABEL_ANY]; + const defaultLabels = DEFAULT_NONE_ANY; beforeEach(async () => { wrapper = createComponent({ value: { data: `"${mockRegularLabel.title}"` } }); diff --git a/spec/frontend/vue_shared/components/markdown/__snapshots__/suggestion_diff_spec.js.snap b/spec/frontend/vue_shared/components/markdown/__snapshots__/suggestion_diff_spec.js.snap index c454166e30b..3b49536799c 100644 --- a/spec/frontend/vue_shared/components/markdown/__snapshots__/suggestion_diff_spec.js.snap +++ b/spec/frontend/vue_shared/components/markdown/__snapshots__/suggestion_diff_spec.js.snap @@ -6,7 +6,7 @@ exports[`Suggestion Diff component matches snapshot 1`] = ` > <suggestion-diff-header-stub batchsuggestionscount="1" - class="qa-suggestion-diff-header js-suggestion-diff-header" + class="js-suggestion-diff-header" defaultcommitmessage="Apply suggestion" helppagepath="path_to_docs" isapplyingbatch="true" diff --git a/spec/frontend/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs_spec.js b/spec/frontend/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs_spec.js index 74e9cbcbb53..acf97713885 100644 --- a/spec/frontend/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs_spec.js +++ b/spec/frontend/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs_spec.js @@ -1,6 +1,7 @@ import { GlAlert, GlBadge, GlPagination, GlTabs, GlTab } from '@gitlab/ui'; import { mount } from '@vue/test-utils'; import Tracking from '~/tracking'; +import { OPERATOR_IS_ONLY } from '~/vue_shared/components/filtered_search_bar/constants'; import FilteredSearchBar from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue'; import AuthorToken from '~/vue_shared/components/filtered_search_bar/tokens/author_token.vue'; import PageWrapper from '~/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs.vue'; @@ -291,7 +292,7 @@ describe('AlertManagementEmptyState', () => { unique: true, symbol: '@', token: AuthorToken, - operators: [{ value: '=', description: 'is', default: 'true' }], + operators: OPERATOR_IS_ONLY, fetchPath: '/link', fetchAuthors: expect.any(Function), }, @@ -302,7 +303,7 @@ describe('AlertManagementEmptyState', () => { unique: true, symbol: '@', token: AuthorToken, - operators: [{ value: '=', description: 'is', default: 'true' }], + operators: OPERATOR_IS_ONLY, fetchPath: '/link', fetchAuthors: expect.any(Function), }, diff --git a/spec/helpers/ci/pipeline_editor_helper_spec.rb b/spec/helpers/ci/pipeline_editor_helper_spec.rb index aacfc3b91c6..2287718db5a 100644 --- a/spec/helpers/ci/pipeline_editor_helper_spec.rb +++ b/spec/helpers/ci/pipeline_editor_helper_spec.rb @@ -55,6 +55,7 @@ RSpec.describe Ci::PipelineEditorHelper do "project-full-path" => project.full_path, "project-namespace" => project.namespace.full_path, "runner-help-page-path" => help_page_path('ci/runners/README'), + "total-branches" => project.repository.branches.length, "yml-help-page-path" => help_page_path('ci/yaml/README') }) end @@ -81,6 +82,7 @@ RSpec.describe Ci::PipelineEditorHelper do "project-full-path" => project.full_path, "project-namespace" => project.namespace.full_path, "runner-help-page-path" => help_page_path('ci/runners/README'), + "total-branches" => 0, "yml-help-page-path" => help_page_path('ci/yaml/README') }) end diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index 7b58acafd93..ef8f3103879 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -1948,6 +1948,30 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do expect(pipeline.modified_paths).to match(merge_request.modified_paths) end end + + context 'when source is an external pull request' do + let(:pipeline) do + create(:ci_pipeline, source: :external_pull_request_event, external_pull_request: external_pull_request) + end + + let(:external_pull_request) do + create(:external_pull_request, project: project, target_sha: '281d3a7', source_sha: '498214d') + end + + it 'returns external pull request modified paths' do + expect(pipeline.modified_paths).to match(external_pull_request.modified_paths) + end + + context 'when the FF ci_modified_paths_of_external_prs is disabled' do + before do + stub_feature_flags(ci_modified_paths_of_external_prs: false) + end + + it 'returns nil' do + expect(pipeline.modified_paths).to be_nil + end + end + end end describe '#all_worktree_paths' do diff --git a/spec/models/external_pull_request_spec.rb b/spec/models/external_pull_request_spec.rb index e0822fc177a..bac2c369d7d 100644 --- a/spec/models/external_pull_request_spec.rb +++ b/spec/models/external_pull_request_spec.rb @@ -3,7 +3,8 @@ require 'spec_helper' RSpec.describe ExternalPullRequest do - let(:project) { create(:project) } + let_it_be(:project) { create(:project, :repository) } + let(:source_branch) { 'the-branch' } let(:status) { :open } @@ -217,4 +218,18 @@ RSpec.describe ExternalPullRequest do expect(pull_request).not_to be_from_fork end end + + describe '#modified_paths' do + let(:pull_request) do + build(:external_pull_request, project: project, target_sha: '281d3a7', source_sha: '498214d') + end + + subject(:modified_paths) { pull_request.modified_paths } + + it 'returns modified paths' do + expect(modified_paths).to eq ['bar/branch-test.txt', + 'files/js/commit.coffee', + 'with space/README.md'] + end + end end |