Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2021-05-13 18:10:32 +00:00
parent e958867b2e
commit 561d1f41b5
80 changed files with 773 additions and 1214 deletions

View File

@ -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') }}

View File

@ -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"

View File

@ -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"

View File

@ -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)"

View File

@ -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)"

View File

@ -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" />

View File

@ -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];

View File

@ -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);

View File

@ -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,

View File

@ -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') },

View File

@ -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>

View File

@ -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 },

View File

@ -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>

View File

@ -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';

View File

@ -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)
}
}
}

View File

@ -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 }) => {

View File

@ -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) {

View File

@ -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,
},
];
},

View File

@ -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>

View File

@ -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');

View File

@ -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

View File

@ -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"

View File

@ -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),
},

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 } }

View File

@ -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)

View File

@ -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.')

View File

@ -0,0 +1,5 @@
---
title: Update projects approval rules Usage Data metrics
merge_request: 61106
author:
type: other

View File

@ -0,0 +1,5 @@
---
title: Remove hyphen from Cloudrail CI template name
merge_request: 61079
author:
type: fixed

View File

@ -0,0 +1,5 @@
---
title: Add semgrep to Secure-Binaries and update support docs
merge_request: 61411
author:
type: added

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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`

View File

@ -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/)

View File

@ -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 -->

View File

@ -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 -->

View File

@ -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 -->

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

View File

@ -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 -->

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.7 KiB

View File

@ -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 -->

View File

@ -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 -->

View File

@ -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 -->

View File

@ -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
![fit](logo.png)
## 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
![fit](logo.png)
- 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?
![fit](logo.png)
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 -->

View File

@ -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) |

View File

@ -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

View File

@ -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:

View File

@ -31474,6 +31474,9 @@ msgstr ""
msgid "Survey Response"
msgstr ""
msgid "Switch Branch"
msgstr ""
msgid "Switch branch/tag"
msgstr ""

View File

@ -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)

View File

@ -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
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/mr_widget_pipeline.vue' do
element :merge_request_pipeline_info_content
element :pipeline_link
view 'app/assets/javascripts/batch_comments/components/publish_button.vue' do
element :submit_review_button
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
end
view 'app/assets/javascripts/vue_merge_request_widget/components/states/squash_before_merge.vue' do
element :squash_checkbox
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
end
view 'app/assets/javascripts/diffs/components/inline_diff_table_row.vue' do
element :new_diff_line_link
end
view 'app/views/projects/merge_requests/_mr_title.html.haml' do
element :edit_button
end
view 'app/assets/javascripts/batch_comments/components/publish_button.vue' do
element :submit_review_button
end
view 'app/assets/javascripts/batch_comments/components/review_bar.vue' do
element :review_bar_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
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/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/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_merged.vue' do
element :cherry_pick_button
element :merged_status_content
element :revert_button
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
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

View File

@ -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">

View File

@ -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,
});
});

View File

@ -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',

View File

@ -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,
});
});

View File

@ -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' },

View File

@ -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();
});
});
});
});

View File

@ -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', () => {

View File

@ -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',

View File

@ -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,
});
});

View File

@ -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"

View File

@ -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' },

View File

@ -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 },

View File

@ -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);

View File

@ -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({

View File

@ -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}"` } });

View File

@ -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"

View File

@ -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),
},

View File

@ -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

View File

@ -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

View File

@ -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