Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
d97b2fedc8
commit
173bd0618f
|
|
@ -1 +1 @@
|
|||
13.14.0
|
||||
13.15.0
|
||||
|
|
|
|||
|
|
@ -1,7 +1,15 @@
|
|||
<script>
|
||||
import { mapActions, mapGetters, mapState } from 'vuex';
|
||||
import { GlTooltipDirective, GlIcon, GlSafeHtmlDirective as SafeHtml } from '@gitlab/ui';
|
||||
import { CONTEXT_LINE_CLASS_NAME, PARALLEL_DIFF_VIEW_TYPE } from '../constants';
|
||||
import {
|
||||
CONTEXT_LINE_CLASS_NAME,
|
||||
PARALLEL_DIFF_VIEW_TYPE,
|
||||
CONFLICT_MARKER_OUR,
|
||||
CONFLICT_MARKER_THEIR,
|
||||
CONFLICT_OUR,
|
||||
CONFLICT_THEIR,
|
||||
CONFLICT_MARKER,
|
||||
} from '../constants';
|
||||
import DiffGutterAvatars from './diff_gutter_avatars.vue';
|
||||
import * as utils from './diff_row_utils';
|
||||
|
||||
|
|
@ -71,6 +79,12 @@ export default {
|
|||
addCommentTooltipRight() {
|
||||
return utils.addCommentTooltip(this.line.right);
|
||||
},
|
||||
emptyCellRightClassMap() {
|
||||
return { conflict_their: this.line.left?.type === CONFLICT_OUR };
|
||||
},
|
||||
emptyCellLeftClassMap() {
|
||||
return { conflict_our: this.line.right?.type === CONFLICT_THEIR };
|
||||
},
|
||||
shouldRenderCommentButton() {
|
||||
return (
|
||||
this.isLoggedIn &&
|
||||
|
|
@ -80,6 +94,9 @@ export default {
|
|||
!this.line.hasDiscussionsRight
|
||||
);
|
||||
},
|
||||
isLeftConflictMarker() {
|
||||
return [CONFLICT_MARKER_OUR, CONFLICT_MARKER_THEIR].includes(this.line.left?.type);
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.scrollToLineIfNeededParallel(this.line);
|
||||
|
|
@ -107,37 +124,50 @@ export default {
|
|||
handleCommentButton(line) {
|
||||
this.showCommentForm({ lineCode: line.line_code, fileHash: this.fileHash });
|
||||
},
|
||||
conflictText(line) {
|
||||
return line.type === CONFLICT_MARKER_THEIR
|
||||
? this.$options.THEIR_CHANGES
|
||||
: this.$options.OUR_CHANGES;
|
||||
},
|
||||
},
|
||||
OUR_CHANGES: 'HEAD//our changes',
|
||||
THEIR_CHANGES: 'origin//their changes',
|
||||
CONFLICT_MARKER,
|
||||
CONFLICT_MARKER_THEIR,
|
||||
CONFLICT_OUR,
|
||||
CONFLICT_THEIR,
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="classNameMap" class="diff-grid-row diff-tr line_holder">
|
||||
<div class="diff-grid-left left-side">
|
||||
<template v-if="line.left">
|
||||
<template v-if="line.left && line.left.type !== $options.CONFLICT_MARKER">
|
||||
<div
|
||||
:class="classNameMapCellLeft"
|
||||
data-testid="leftLineNumber"
|
||||
class="diff-td diff-line-num old_line"
|
||||
>
|
||||
<span
|
||||
v-if="shouldRenderCommentButton"
|
||||
v-gl-tooltip
|
||||
data-testid="leftCommentButton"
|
||||
class="add-diff-note tooltip-wrapper"
|
||||
:title="addCommentTooltipLeft"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
class="add-diff-note note-button js-add-diff-note-button qa-diff-comment"
|
||||
:disabled="line.left.commentsDisabled"
|
||||
@click="handleCommentButton(line.left)"
|
||||
<template v-if="!isLeftConflictMarker">
|
||||
<span
|
||||
v-if="shouldRenderCommentButton"
|
||||
v-gl-tooltip
|
||||
data-testid="leftCommentButton"
|
||||
class="add-diff-note tooltip-wrapper"
|
||||
:title="addCommentTooltipLeft"
|
||||
>
|
||||
<gl-icon :size="12" name="comment" />
|
||||
</button>
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
class="add-diff-note note-button js-add-diff-note-button qa-diff-comment"
|
||||
:disabled="line.left.commentsDisabled"
|
||||
@click="handleCommentButton(line.left)"
|
||||
>
|
||||
<gl-icon :size="12" name="comment" />
|
||||
</button>
|
||||
</span>
|
||||
</template>
|
||||
<a
|
||||
v-if="line.left.old_line"
|
||||
v-if="line.left.old_line && line.left.type !== $options.CONFLICT_THEIR"
|
||||
:data-linenumber="line.left.old_line"
|
||||
:href="line.lineHrefOld"
|
||||
@click="setHighlightedRow(line.lineCode)"
|
||||
|
|
@ -159,7 +189,7 @@ export default {
|
|||
</div>
|
||||
<div v-if="inline" :class="classNameMapCellLeft" class="diff-td diff-line-num old_line">
|
||||
<a
|
||||
v-if="line.left.new_line"
|
||||
v-if="line.left.new_line && line.left.type !== $options.CONFLICT_OUR"
|
||||
:data-linenumber="line.left.new_line"
|
||||
:href="line.lineHrefOld"
|
||||
@click="setHighlightedRow(line.lineCode)"
|
||||
|
|
@ -170,39 +200,59 @@ export default {
|
|||
<div
|
||||
:id="line.left.line_code"
|
||||
:key="line.left.line_code"
|
||||
v-safe-html="line.left.rich_text"
|
||||
:class="parallelViewLeftLineType"
|
||||
class="diff-td line_content with-coverage parallel left-side"
|
||||
data-testid="leftContent"
|
||||
@mousedown="handleParallelLineMouseDown"
|
||||
></div>
|
||||
>
|
||||
<strong v-if="isLeftConflictMarker">{{ conflictText(line.left) }}</strong>
|
||||
<span v-else v-safe-html="line.left.rich_text"></span>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div data-testid="leftEmptyCell" class="diff-td diff-line-num old_line empty-cell"></div>
|
||||
<div v-if="inline" class="diff-td diff-line-num old_line empty-cell"></div>
|
||||
<div class="diff-td line-coverage left-side empty-cell"></div>
|
||||
<div class="diff-td line_content with-coverage parallel left-side empty-cell"></div>
|
||||
<template v-else-if="!inline || (line.left && line.left.type === $options.CONFLICT_MARKER)">
|
||||
<div
|
||||
data-testid="leftEmptyCell"
|
||||
class="diff-td diff-line-num old_line empty-cell"
|
||||
:class="emptyCellLeftClassMap"
|
||||
>
|
||||
|
||||
</div>
|
||||
<div
|
||||
v-if="inline"
|
||||
class="diff-td diff-line-num old_line empty-cell"
|
||||
:class="emptyCellLeftClassMap"
|
||||
></div>
|
||||
<div
|
||||
class="diff-td line-coverage left-side empty-cell"
|
||||
:class="emptyCellLeftClassMap"
|
||||
></div>
|
||||
<div
|
||||
class="diff-td line_content with-coverage parallel left-side empty-cell"
|
||||
:class="emptyCellLeftClassMap"
|
||||
></div>
|
||||
</template>
|
||||
</div>
|
||||
<div v-if="!inline" class="diff-grid-right right-side">
|
||||
<template v-if="line.right">
|
||||
<div :class="classNameMapCellRight" class="diff-td diff-line-num new_line">
|
||||
<span
|
||||
v-if="shouldRenderCommentButton"
|
||||
v-gl-tooltip
|
||||
data-testid="rightCommentButton"
|
||||
class="add-diff-note tooltip-wrapper"
|
||||
:title="addCommentTooltipRight"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
class="add-diff-note note-button js-add-diff-note-button qa-diff-comment"
|
||||
:disabled="line.right.commentsDisabled"
|
||||
@click="handleCommentButton(line.right)"
|
||||
<template v-if="line.right.type !== $options.CONFLICT_MARKER_THEIR">
|
||||
<span
|
||||
v-if="shouldRenderCommentButton"
|
||||
v-gl-tooltip
|
||||
data-testid="rightCommentButton"
|
||||
class="add-diff-note tooltip-wrapper"
|
||||
:title="addCommentTooltipRight"
|
||||
>
|
||||
<gl-icon :size="12" name="comment" />
|
||||
</button>
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
class="add-diff-note note-button js-add-diff-note-button qa-diff-comment"
|
||||
:disabled="line.right.commentsDisabled"
|
||||
@click="handleCommentButton(line.right)"
|
||||
>
|
||||
<gl-icon :size="12" name="comment" />
|
||||
</button>
|
||||
</span>
|
||||
</template>
|
||||
<a
|
||||
v-if="line.right.new_line"
|
||||
:data-linenumber="line.right.new_line"
|
||||
|
|
@ -233,22 +283,35 @@ export default {
|
|||
<div
|
||||
:id="line.right.line_code"
|
||||
:key="line.right.rich_text"
|
||||
v-safe-html="line.right.rich_text"
|
||||
:class="[
|
||||
line.right.type,
|
||||
{
|
||||
hll: isHighlighted,
|
||||
},
|
||||
]"
|
||||
:class="[line.right.type, { hll: isHighlighted }]"
|
||||
class="diff-td line_content with-coverage parallel right-side"
|
||||
@mousedown="handleParallelLineMouseDown"
|
||||
></div>
|
||||
>
|
||||
<strong v-if="line.right.type === $options.CONFLICT_MARKER_THEIR">{{
|
||||
conflictText(line.right)
|
||||
}}</strong>
|
||||
<span v-else v-safe-html="line.right.rich_text"></span>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div data-testid="rightEmptyCell" class="diff-td diff-line-num old_line empty-cell"></div>
|
||||
<div class="diff-td diff-line-num old_line empty-cell"></div>
|
||||
<div class="diff-td line-coverage right-side empty-cell"></div>
|
||||
<div class="diff-td line_content with-coverage parallel right-side empty-cell"></div>
|
||||
<div
|
||||
data-testid="rightEmptyCell"
|
||||
class="diff-td diff-line-num old_line empty-cell"
|
||||
:class="emptyCellRightClassMap"
|
||||
></div>
|
||||
<div
|
||||
v-if="inline"
|
||||
class="diff-td diff-line-num old_line empty-cell"
|
||||
:class="emptyCellRightClassMap"
|
||||
></div>
|
||||
<div
|
||||
class="diff-td line-coverage right-side empty-cell"
|
||||
:class="emptyCellRightClassMap"
|
||||
></div>
|
||||
<div
|
||||
class="diff-td line_content with-coverage parallel right-side empty-cell"
|
||||
:class="emptyCellRightClassMap"
|
||||
></div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -109,3 +109,9 @@ export const EVT_PERF_MARK_FILE_TREE_END = 'mr:diffs:perf:fileTreeEnd';
|
|||
export const EVT_PERF_MARK_DIFF_FILES_START = 'mr:diffs:perf:filesStart';
|
||||
export const EVT_PERF_MARK_FIRST_DIFF_FILE_SHOWN = 'mr:diffs:perf:firstFileShown';
|
||||
export const EVT_PERF_MARK_DIFF_FILES_END = 'mr:diffs:perf:filesEnd';
|
||||
|
||||
export const CONFLICT_OUR = 'conflict_our';
|
||||
export const CONFLICT_THEIR = 'conflict_their';
|
||||
export const CONFLICT_MARKER = 'conflict_marker';
|
||||
export const CONFLICT_MARKER_OUR = 'conflict_marker_our';
|
||||
export const CONFLICT_MARKER_THEIR = 'conflict_marker_their';
|
||||
|
|
|
|||
|
|
@ -15,6 +15,11 @@ import {
|
|||
INLINE_DIFF_LINES_KEY,
|
||||
SHOW_WHITESPACE,
|
||||
NO_SHOW_WHITESPACE,
|
||||
CONFLICT_OUR,
|
||||
CONFLICT_THEIR,
|
||||
CONFLICT_MARKER,
|
||||
CONFLICT_MARKER_OUR,
|
||||
CONFLICT_MARKER_THEIR,
|
||||
} from '../constants';
|
||||
import { prepareRawDiffFile } from '../utils/diff_file';
|
||||
|
||||
|
|
@ -22,6 +27,11 @@ export const isAdded = line => ['new', 'new-nonewline'].includes(line.type);
|
|||
export const isRemoved = line => ['old', 'old-nonewline'].includes(line.type);
|
||||
export const isUnchanged = line => !line.type;
|
||||
export const isMeta = line => ['match', 'new-nonewline', 'old-nonewline'].includes(line.type);
|
||||
export const isConflictMarker = line =>
|
||||
[CONFLICT_MARKER_OUR, CONFLICT_MARKER_THEIR].includes(line.type);
|
||||
export const isConflictSeperator = line => line.type === CONFLICT_MARKER;
|
||||
export const isConflictOur = line => line.type === CONFLICT_OUR;
|
||||
export const isConflictTheir = line => line.type === CONFLICT_THEIR;
|
||||
|
||||
/**
|
||||
* Pass in the inline diff lines array which gets converted
|
||||
|
|
@ -42,12 +52,13 @@ export const isMeta = line => ['match', 'new-nonewline', 'old-nonewline'].includ
|
|||
|
||||
export const parallelizeDiffLines = (diffLines, inline) => {
|
||||
let freeRightIndex = null;
|
||||
let conflictStartIndex = -1;
|
||||
const lines = [];
|
||||
|
||||
for (let i = 0, diffLinesLength = diffLines.length, index = 0; i < diffLinesLength; i += 1) {
|
||||
const line = diffLines[i];
|
||||
|
||||
if (isRemoved(line) || inline) {
|
||||
if (isRemoved(line) || isConflictOur(line) || inline) {
|
||||
lines.push({
|
||||
[LINE_POSITION_LEFT]: line,
|
||||
[LINE_POSITION_RIGHT]: null,
|
||||
|
|
@ -58,7 +69,7 @@ export const parallelizeDiffLines = (diffLines, inline) => {
|
|||
freeRightIndex = index;
|
||||
}
|
||||
index += 1;
|
||||
} else if (isAdded(line)) {
|
||||
} else if (isAdded(line) || isConflictTheir(line)) {
|
||||
if (freeRightIndex !== null) {
|
||||
// If an old line came before this without a line on the right, this
|
||||
// line can be put to the right of it.
|
||||
|
|
@ -77,15 +88,28 @@ export const parallelizeDiffLines = (diffLines, inline) => {
|
|||
freeRightIndex = null;
|
||||
index += 1;
|
||||
}
|
||||
} else if (isMeta(line) || isUnchanged(line)) {
|
||||
// line in the right panel is the same as in the left one
|
||||
lines.push({
|
||||
[LINE_POSITION_LEFT]: line,
|
||||
[LINE_POSITION_RIGHT]: line,
|
||||
});
|
||||
} else if (
|
||||
isMeta(line) ||
|
||||
isUnchanged(line) ||
|
||||
isConflictMarker(line) ||
|
||||
(isConflictSeperator(line) && inline)
|
||||
) {
|
||||
if (conflictStartIndex <= 0) {
|
||||
// line in the right panel is the same as in the left one
|
||||
lines.push({
|
||||
[LINE_POSITION_LEFT]: line,
|
||||
[LINE_POSITION_RIGHT]: !inline && line,
|
||||
});
|
||||
|
||||
freeRightIndex = null;
|
||||
index += 1;
|
||||
if (!inline && isConflictMarker(line)) {
|
||||
conflictStartIndex = index;
|
||||
}
|
||||
freeRightIndex = null;
|
||||
index += 1;
|
||||
} else {
|
||||
lines[conflictStartIndex][LINE_POSITION_RIGHT] = line;
|
||||
conflictStartIndex = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
@import '../framework/variables';
|
||||
@import './conflict_colors';
|
||||
|
||||
@mixin diff-background($background, $idiff, $border) {
|
||||
background: $background;
|
||||
|
|
@ -51,3 +52,44 @@
|
|||
color: darken($color, 15%);
|
||||
}
|
||||
}
|
||||
|
||||
@mixin conflict-colors($theme) {
|
||||
.diff-line-num {
|
||||
&.conflict_marker_our,
|
||||
&.conflict_our {
|
||||
background-color: map-get($conflict-colors, #{$theme}-header-head-neutral);
|
||||
border-color: map-get($conflict-colors, #{$theme}-header-head-neutral);
|
||||
}
|
||||
|
||||
&.conflict_marker_their,
|
||||
&.conflict_their {
|
||||
background-color: map-get($conflict-colors, #{$theme}-header-origin-neutral);
|
||||
border-color: map-get($conflict-colors, #{$theme}-header-origin-neutral);
|
||||
}
|
||||
}
|
||||
|
||||
.line_holder {
|
||||
.line_content,
|
||||
.line-coverage {
|
||||
&.conflict_marker_our {
|
||||
background-color: map-get($conflict-colors, #{$theme}-header-head-neutral);
|
||||
border-color: map-get($conflict-colors, #{$theme}-header-head-neutral);
|
||||
}
|
||||
|
||||
&.conflict_marker_their {
|
||||
background-color: map-get($conflict-colors, #{$theme}-header-origin-neutral);
|
||||
border-color: map-get($conflict-colors, #{$theme}-header-origin-neutral);
|
||||
}
|
||||
|
||||
&.conflict_our {
|
||||
background-color: map-get($conflict-colors, #{$theme}-line-head-neutral);
|
||||
border-color: map-get($conflict-colors, #{$theme}-line-head-neutral);
|
||||
}
|
||||
|
||||
&.conflict_their {
|
||||
background-color: map-get($conflict-colors, #{$theme}-line-origin-neutral);
|
||||
border-color: map-get($conflict-colors, #{$theme}-line-origin-neutral);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,119 @@
|
|||
// Disabled to use the color map for creating color schemes
|
||||
// scss-lint:disable ColorVariable
|
||||
$conflict-colors: (
|
||||
white-header-head-neutral : #e1fad7,
|
||||
white-line-head-neutral : #effdec,
|
||||
white-button-head-neutral : #9adb84,
|
||||
|
||||
white-header-head-chosen : #baf0a8,
|
||||
white-line-head-chosen : #e1fad7,
|
||||
white-button-head-chosen : #52c22d,
|
||||
|
||||
white-header-origin-neutral : #e0f0ff,
|
||||
white-line-origin-neutral : #f2f9ff,
|
||||
white-button-origin-neutral : #87c2fa,
|
||||
|
||||
white-header-origin-chosen : #add8ff,
|
||||
white-line-origin-chosen : #e0f0ff,
|
||||
white-button-origin-chosen : #268ced,
|
||||
|
||||
white-header-not-chosen : #f0f0f0,
|
||||
white-line-not-chosen : $gray-light,
|
||||
|
||||
dark-header-head-neutral : rgba(#3f3, 0.2),
|
||||
dark-line-head-neutral : rgba(#3f3, 0.1),
|
||||
dark-button-head-neutral : #40874f,
|
||||
|
||||
dark-header-head-chosen : rgba(#3f3, 0.33),
|
||||
dark-line-head-chosen : rgba(#3f3, 0.2),
|
||||
dark-button-head-chosen : #258537,
|
||||
|
||||
dark-header-origin-neutral : rgba(#2878c9, 0.4),
|
||||
dark-line-origin-neutral : rgba(#2878c9, 0.3),
|
||||
dark-button-origin-neutral : #2a5c8c,
|
||||
|
||||
dark-header-origin-chosen : rgba(#2878c9, 0.6),
|
||||
dark-line-origin-chosen : rgba(#2878c9, 0.4),
|
||||
dark-button-origin-chosen : #1d6cbf,
|
||||
|
||||
dark-header-not-chosen : rgba(#fff, 0.25),
|
||||
dark-line-not-chosen : rgba(#fff, 0.1),
|
||||
|
||||
monokai-header-head-neutral : rgba(#a6e22e, 0.25),
|
||||
monokai-line-head-neutral : rgba(#a6e22e, 0.1),
|
||||
monokai-button-head-neutral : #376b20,
|
||||
|
||||
monokai-header-head-chosen : rgba(#a6e22e, 0.4),
|
||||
monokai-line-head-chosen : rgba(#a6e22e, 0.25),
|
||||
monokai-button-head-chosen : #39800d,
|
||||
|
||||
monokai-header-origin-neutral : rgba(#60d9f1, 0.35),
|
||||
monokai-line-origin-neutral : rgba(#60d9f1, 0.15),
|
||||
monokai-button-origin-neutral : #38848c,
|
||||
|
||||
monokai-header-origin-chosen : rgba(#60d9f1, 0.5),
|
||||
monokai-line-origin-chosen : rgba(#60d9f1, 0.35),
|
||||
monokai-button-origin-chosen : #3ea4b2,
|
||||
|
||||
monokai-header-not-chosen : rgba(#76715d, 0.24),
|
||||
monokai-line-not-chosen : rgba(#76715d, 0.1),
|
||||
|
||||
solarized-light-header-head-neutral : rgba(#859900, 0.37),
|
||||
solarized-light-line-head-neutral : rgba(#859900, 0.2),
|
||||
solarized-light-button-head-neutral : #afb262,
|
||||
|
||||
solarized-light-header-head-chosen : rgba(#859900, 0.5),
|
||||
solarized-light-line-head-chosen : rgba(#859900, 0.37),
|
||||
solarized-light-button-head-chosen : #94993d,
|
||||
|
||||
solarized-light-header-origin-neutral : rgba(#2878c9, 0.37),
|
||||
solarized-light-line-origin-neutral : rgba(#2878c9, 0.15),
|
||||
solarized-light-button-origin-neutral : #60a1bf,
|
||||
|
||||
solarized-light-header-origin-chosen : rgba(#2878c9, 0.6),
|
||||
solarized-light-line-origin-chosen : rgba(#2878c9, 0.37),
|
||||
solarized-light-button-origin-chosen : #2482b2,
|
||||
|
||||
solarized-light-header-not-chosen : rgba(#839496, 0.37),
|
||||
solarized-light-line-not-chosen : rgba(#839496, 0.2),
|
||||
|
||||
solarized-dark-header-head-neutral : rgba(#859900, 0.35),
|
||||
solarized-dark-line-head-neutral : rgba(#859900, 0.15),
|
||||
solarized-dark-button-head-neutral : #376b20,
|
||||
|
||||
solarized-dark-header-head-chosen : rgba(#859900, 0.5),
|
||||
solarized-dark-line-head-chosen : rgba(#859900, 0.35),
|
||||
solarized-dark-button-head-chosen : #39800d,
|
||||
|
||||
solarized-dark-header-origin-neutral : rgba(#2878c9, 0.35),
|
||||
solarized-dark-line-origin-neutral : rgba(#2878c9, 0.15),
|
||||
solarized-dark-button-origin-neutral : #086799,
|
||||
|
||||
solarized-dark-header-origin-chosen : rgba(#2878c9, 0.6),
|
||||
solarized-dark-line-origin-chosen : rgba(#2878c9, 0.35),
|
||||
solarized-dark-button-origin-chosen : #0082cc,
|
||||
|
||||
solarized_dark_header_not_chosen : rgba(#839496, 0.25),
|
||||
solarized_dark_line_not_chosen : rgba(#839496, 0.15),
|
||||
|
||||
none_header_head_neutral : $gray-normal,
|
||||
none_line_head_neutral : $gray-normal,
|
||||
none_button_head_neutral : $gray-normal,
|
||||
|
||||
none_header_head_chosen : $gray-darker,
|
||||
none_line_head_chosen : $gray-darker,
|
||||
none_button_head_chosen : $gray-darker,
|
||||
|
||||
none_header_origin_neutral : $gray-normal,
|
||||
none_line_origin_neutral : $gray-normal,
|
||||
none_button_origin_neutral : $gray-normal,
|
||||
|
||||
none_header_origin_chosen : $gray-darker,
|
||||
none_line_origin_chosen : $gray-darker,
|
||||
none_button_origin_chosen : $gray-darker,
|
||||
|
||||
none_header_not_chosen : $gray-light,
|
||||
none_line_not_chosen : $gray-light
|
||||
|
||||
);
|
||||
// scss-lint:enable ColorVariable
|
||||
|
|
@ -198,6 +198,8 @@ $dark-il: #de935f;
|
|||
}
|
||||
}
|
||||
|
||||
@include conflict-colors('dark');
|
||||
|
||||
// highlight line via anchor
|
||||
pre .hll {
|
||||
background-color: $dark-pre-hll-bg !important;
|
||||
|
|
|
|||
|
|
@ -198,6 +198,8 @@ $monokai-gi: #a6e22e;
|
|||
}
|
||||
}
|
||||
|
||||
@include conflict-colors('monokai');
|
||||
|
||||
// highlight line via anchor
|
||||
pre .hll {
|
||||
background-color: $monokai-hll !important;
|
||||
|
|
|
|||
|
|
@ -202,6 +202,8 @@ $solarized-dark-il: #2aa198;
|
|||
}
|
||||
}
|
||||
|
||||
@include conflict-colors('solarized-dark');
|
||||
|
||||
// highlight line via anchor
|
||||
pre .hll {
|
||||
background-color: $solarized-dark-hll-bg !important;
|
||||
|
|
|
|||
|
|
@ -210,6 +210,8 @@ $solarized-light-il: #2aa198;
|
|||
}
|
||||
}
|
||||
|
||||
@include conflict-colors('solarized-light');
|
||||
|
||||
// highlight line via anchor
|
||||
pre .hll {
|
||||
background-color: $solarized-light-hll-bg !important;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
.code.white {
|
||||
@import '../white_base';
|
||||
|
||||
@include conflict-colors('white');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,6 +81,17 @@ $white-gc-bg: #eaf2f5;
|
|||
.line-numbers,
|
||||
.diff-line-num {
|
||||
background-color: $gray-light;
|
||||
|
||||
&.conflict_marker,
|
||||
&.conflict_our {
|
||||
background-color: map-get($conflict-colors, 'white-header-head-neutral');
|
||||
border-color: map-get($conflict-colors, 'white-header-head-neutral');
|
||||
}
|
||||
|
||||
&.conflict_their {
|
||||
background-color: map-get($conflict-colors, 'white-header-origin-neutral');
|
||||
border-color: map-get($conflict-colors, 'white-header-origin-neutral');
|
||||
}
|
||||
}
|
||||
|
||||
.diff-line-num,
|
||||
|
|
@ -115,7 +126,7 @@ pre.code,
|
|||
|
||||
.diff-grid-left:hover,
|
||||
.diff-grid-right:hover {
|
||||
.diff-line-num:not(.empty-cell) {
|
||||
.diff-line-num:not(.empty-cell):not(.conflict_marker_their):not(.conflict_marker_our) {
|
||||
@include line-number-hover($white-over-bg);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,183 +1,65 @@
|
|||
@import 'mixins_and_variables_and_functions';
|
||||
// Disabled to use the color map for creating color schemes
|
||||
// scss-lint:disable ColorVariable
|
||||
$colors: (
|
||||
white-header-head-neutral : #e1fad7,
|
||||
white-line-head-neutral : #effdec,
|
||||
white-button-head-neutral : #9adb84,
|
||||
|
||||
white-header-head-chosen : #baf0a8,
|
||||
white-line-head-chosen : #e1fad7,
|
||||
white-button-head-chosen : #52c22d,
|
||||
|
||||
white-header-origin-neutral : #e0f0ff,
|
||||
white-line-origin-neutral : #f2f9ff,
|
||||
white-button-origin-neutral : #87c2fa,
|
||||
|
||||
white-header-origin-chosen : #add8ff,
|
||||
white-line-origin-chosen : #e0f0ff,
|
||||
white-button-origin-chosen : #268ced,
|
||||
|
||||
white-header-not-chosen : #f0f0f0,
|
||||
white-line-not-chosen : $gray-light,
|
||||
|
||||
dark-header-head-neutral : rgba(#3f3, 0.2),
|
||||
dark-line-head-neutral : rgba(#3f3, 0.1),
|
||||
dark-button-head-neutral : #40874f,
|
||||
|
||||
dark-header-head-chosen : rgba(#3f3, 0.33),
|
||||
dark-line-head-chosen : rgba(#3f3, 0.2),
|
||||
dark-button-head-chosen : #258537,
|
||||
|
||||
dark-header-origin-neutral : rgba(#2878c9, 0.4),
|
||||
dark-line-origin-neutral : rgba(#2878c9, 0.3),
|
||||
dark-button-origin-neutral : #2a5c8c,
|
||||
|
||||
dark-header-origin-chosen : rgba(#2878c9, 0.6),
|
||||
dark-line-origin-chosen : rgba(#2878c9, 0.4),
|
||||
dark-button-origin-chosen : #1d6cbf,
|
||||
|
||||
dark-header-not-chosen : rgba(#fff, 0.25),
|
||||
dark-line-not-chosen : rgba(#fff, 0.1),
|
||||
|
||||
monokai-header-head-neutral : rgba(#a6e22e, 0.25),
|
||||
monokai-line-head-neutral : rgba(#a6e22e, 0.1),
|
||||
monokai-button-head-neutral : #376b20,
|
||||
|
||||
monokai-header-head-chosen : rgba(#a6e22e, 0.4),
|
||||
monokai-line-head-chosen : rgba(#a6e22e, 0.25),
|
||||
monokai-button-head-chosen : #39800d,
|
||||
|
||||
monokai-header-origin-neutral : rgba(#60d9f1, 0.35),
|
||||
monokai-line-origin-neutral : rgba(#60d9f1, 0.15),
|
||||
monokai-button-origin-neutral : #38848c,
|
||||
|
||||
monokai-header-origin-chosen : rgba(#60d9f1, 0.5),
|
||||
monokai-line-origin-chosen : rgba(#60d9f1, 0.35),
|
||||
monokai-button-origin-chosen : #3ea4b2,
|
||||
|
||||
monokai-header-not-chosen : rgba(#76715d, 0.24),
|
||||
monokai-line-not-chosen : rgba(#76715d, 0.1),
|
||||
|
||||
solarized-light-header-head-neutral : rgba(#859900, 0.37),
|
||||
solarized-light-line-head-neutral : rgba(#859900, 0.2),
|
||||
solarized-light-button-head-neutral : #afb262,
|
||||
|
||||
solarized-light-header-head-chosen : rgba(#859900, 0.5),
|
||||
solarized-light-line-head-chosen : rgba(#859900, 0.37),
|
||||
solarized-light-button-head-chosen : #94993d,
|
||||
|
||||
solarized-light-header-origin-neutral : rgba(#2878c9, 0.37),
|
||||
solarized-light-line-origin-neutral : rgba(#2878c9, 0.15),
|
||||
solarized-light-button-origin-neutral : #60a1bf,
|
||||
|
||||
solarized-light-header-origin-chosen : rgba(#2878c9, 0.6),
|
||||
solarized-light-line-origin-chosen : rgba(#2878c9, 0.37),
|
||||
solarized-light-button-origin-chosen : #2482b2,
|
||||
|
||||
solarized-light-header-not-chosen : rgba(#839496, 0.37),
|
||||
solarized-light-line-not-chosen : rgba(#839496, 0.2),
|
||||
|
||||
solarized-dark-header-head-neutral : rgba(#859900, 0.35),
|
||||
solarized-dark-line-head-neutral : rgba(#859900, 0.15),
|
||||
solarized-dark-button-head-neutral : #376b20,
|
||||
|
||||
solarized-dark-header-head-chosen : rgba(#859900, 0.5),
|
||||
solarized-dark-line-head-chosen : rgba(#859900, 0.35),
|
||||
solarized-dark-button-head-chosen : #39800d,
|
||||
|
||||
solarized-dark-header-origin-neutral : rgba(#2878c9, 0.35),
|
||||
solarized-dark-line-origin-neutral : rgba(#2878c9, 0.15),
|
||||
solarized-dark-button-origin-neutral : #086799,
|
||||
|
||||
solarized-dark-header-origin-chosen : rgba(#2878c9, 0.6),
|
||||
solarized-dark-line-origin-chosen : rgba(#2878c9, 0.35),
|
||||
solarized-dark-button-origin-chosen : #0082cc,
|
||||
|
||||
solarized_dark_header_not_chosen : rgba(#839496, 0.25),
|
||||
solarized_dark_line_not_chosen : rgba(#839496, 0.15),
|
||||
|
||||
none_header_head_neutral : $gray-normal,
|
||||
none_line_head_neutral : $gray-normal,
|
||||
none_button_head_neutral : $gray-normal,
|
||||
|
||||
none_header_head_chosen : $gray-darker,
|
||||
none_line_head_chosen : $gray-darker,
|
||||
none_button_head_chosen : $gray-darker,
|
||||
|
||||
none_header_origin_neutral : $gray-normal,
|
||||
none_line_origin_neutral : $gray-normal,
|
||||
none_button_origin_neutral : $gray-normal,
|
||||
|
||||
none_header_origin_chosen : $gray-darker,
|
||||
none_line_origin_chosen : $gray-darker,
|
||||
none_button_origin_chosen : $gray-darker,
|
||||
|
||||
none_header_not_chosen : $gray-light,
|
||||
none_line_not_chosen : $gray-light
|
||||
|
||||
);
|
||||
// scss-lint:enable ColorVariable
|
||||
@import '../highlight/conflict_colors';
|
||||
|
||||
@mixin color-scheme($color) {
|
||||
.header.line_content,
|
||||
.diff-line-num {
|
||||
&.origin {
|
||||
background-color: map-get($colors, #{$color}-header-origin-neutral);
|
||||
border-color: map-get($colors, #{$color}-header-origin-neutral);
|
||||
background-color: map-get($conflict-colors, #{$color}-header-origin-neutral);
|
||||
border-color: map-get($conflict-colors, #{$color}-header-origin-neutral);
|
||||
|
||||
button {
|
||||
background-color: map-get($colors, #{$color}-button-origin-neutral);
|
||||
border-color: darken(map-get($colors, #{$color}-button-origin-neutral), 15);
|
||||
background-color: map-get($conflict-colors, #{$color}-button-origin-neutral);
|
||||
border-color: darken(map-get($conflict-colors, #{$color}-button-origin-neutral), 15);
|
||||
}
|
||||
|
||||
&.selected {
|
||||
background-color: map-get($colors, #{$color}-header-origin-chosen);
|
||||
border-color: map-get($colors, #{$color}-header-origin-chosen);
|
||||
background-color: map-get($conflict-colors, #{$color}-header-origin-chosen);
|
||||
border-color: map-get($conflict-colors, #{$color}-header-origin-chosen);
|
||||
|
||||
button {
|
||||
background-color: map-get($colors, #{$color}-button-origin-chosen);
|
||||
border-color: darken(map-get($colors, #{$color}-button-origin-chosen), 15);
|
||||
background-color: map-get($conflict-colors, #{$color}-button-origin-chosen);
|
||||
border-color: darken(map-get($conflict-colors, #{$color}-button-origin-chosen), 15);
|
||||
}
|
||||
}
|
||||
|
||||
&.unselected {
|
||||
background-color: map-get($colors, #{$color}-header-not-chosen);
|
||||
border-color: map-get($colors, #{$color}-header-not-chosen);
|
||||
background-color: map-get($conflict-colors, #{$color}-header-not-chosen);
|
||||
border-color: map-get($conflict-colors, #{$color}-header-not-chosen);
|
||||
|
||||
button {
|
||||
background-color: lighten(map-get($colors, #{$color}-button-origin-neutral), 15);
|
||||
border-color: map-get($colors, #{$color}-button-origin-neutral);
|
||||
background-color: lighten(map-get($conflict-colors, #{$color}-button-origin-neutral), 15);
|
||||
border-color: map-get($conflict-colors, #{$color}-button-origin-neutral);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.head {
|
||||
background-color: map-get($colors, #{$color}-header-head-neutral);
|
||||
border-color: map-get($colors, #{$color}-header-head-neutral);
|
||||
background-color: map-get($conflict-colors, #{$color}-header-head-neutral);
|
||||
border-color: map-get($conflict-colors, #{$color}-header-head-neutral);
|
||||
|
||||
button {
|
||||
background-color: map-get($colors, #{$color}-button-head-neutral);
|
||||
border-color: darken(map-get($colors, #{$color}-button-head-neutral), 15);
|
||||
background-color: map-get($conflict-colors, #{$color}-button-head-neutral);
|
||||
border-color: darken(map-get($conflict-colors, #{$color}-button-head-neutral), 15);
|
||||
}
|
||||
|
||||
&.selected {
|
||||
background-color: map-get($colors, #{$color}-header-head-chosen);
|
||||
border-color: map-get($colors, #{$color}-header-head-chosen);
|
||||
background-color: map-get($conflict-colors, #{$color}-header-head-chosen);
|
||||
border-color: map-get($conflict-colors, #{$color}-header-head-chosen);
|
||||
|
||||
button {
|
||||
background-color: map-get($colors, #{$color}-button-head-chosen);
|
||||
border-color: darken(map-get($colors, #{$color}-button-head-chosen), 15);
|
||||
background-color: map-get($conflict-colors, #{$color}-button-head-chosen);
|
||||
border-color: darken(map-get($conflict-colors, #{$color}-button-head-chosen), 15);
|
||||
}
|
||||
}
|
||||
|
||||
&.unselected {
|
||||
background-color: map-get($colors, #{$color}-header-not-chosen);
|
||||
border-color: map-get($colors, #{$color}-header-not-chosen);
|
||||
background-color: map-get($conflict-colors, #{$color}-header-not-chosen);
|
||||
border-color: map-get($conflict-colors, #{$color}-header-not-chosen);
|
||||
|
||||
button {
|
||||
background-color: lighten(map-get($colors, #{$color}-button-head-neutral), 15);
|
||||
border-color: map-get($colors, #{$color}-button-head-neutral);
|
||||
background-color: lighten(map-get($conflict-colors, #{$color}-button-head-neutral), 15);
|
||||
border-color: map-get($conflict-colors, #{$color}-button-head-neutral);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -185,26 +67,26 @@ $colors: (
|
|||
|
||||
.line_content {
|
||||
&.origin {
|
||||
background-color: map-get($colors, #{$color}-line-origin-neutral);
|
||||
background-color: map-get($conflict-colors, #{$color}-line-origin-neutral);
|
||||
|
||||
&.selected {
|
||||
background-color: map-get($colors, #{$color}-line-origin-chosen);
|
||||
background-color: map-get($conflict-colors, #{$color}-line-origin-chosen);
|
||||
}
|
||||
|
||||
&.unselected {
|
||||
background-color: map-get($colors, #{$color}-line-not-chosen);
|
||||
background-color: map-get($conflict-colors, #{$color}-line-not-chosen);
|
||||
}
|
||||
}
|
||||
|
||||
&.head {
|
||||
background-color: map-get($colors, #{$color}-line-head-neutral);
|
||||
background-color: map-get($conflict-colors, #{$color}-line-head-neutral);
|
||||
|
||||
&.selected {
|
||||
background-color: map-get($colors, #{$color}-line-head-chosen);
|
||||
background-color: map-get($conflict-colors, #{$color}-line-head-chosen);
|
||||
}
|
||||
|
||||
&.unselected {
|
||||
background-color: map-get($colors, #{$color}-line-not-chosen);
|
||||
background-color: map-get($conflict-colors, #{$color}-line-not-chosen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
name: ci_pipeline_open_merge_requests
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38673
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/292727
|
||||
milestone: '13.7'
|
||||
group: group::memory
|
||||
type: development
|
||||
default_enabled: false
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
name: value_stream_analytics_extended_form
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/50229
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/294190
|
||||
milestone: '13.7'
|
||||
type: development
|
||||
group: group::optimize
|
||||
default_enabled: false
|
||||
|
|
@ -943,6 +943,16 @@ standby nodes.
|
|||
gitlab-ctl repmgr standby follow NEW_MASTER
|
||||
```
|
||||
|
||||
#### Geo secondary site considerations
|
||||
|
||||
When a Geo secondary site is replicating from a primary site that uses `repmgr` and `PgBouncer`, [replicating through PgBouncer is not supported](https://github.com/pgbouncer/pgbouncer/issues/382#issuecomment-517911529) and the secondary must replicate directly from the leader node in the `repmgr` cluster. Therefore, when there is a failover in the `repmgr` cluster, you will need to manually re-point your secondary site to replicate from the new leader with:
|
||||
|
||||
```shell
|
||||
sudo gitlab-ctl replicate-geo-database --host=<new_leader_ip> --replication-slot=<slot_name>
|
||||
```
|
||||
|
||||
Otherwise, the replication will not happen anymore, even if the original node gets re-added as a follower node. This will re-sync your secondary site database and may take a long time depending on the amount of data to sync.
|
||||
|
||||
### Restore procedure
|
||||
|
||||
If a node fails, it can be removed from the cluster, or added back as a standby
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ highly-available GitLab deployment. If you do not have the expertise or need to
|
|||
maintain a highly-available environment, you can have a simpler and less
|
||||
costly-to-operate environment by using the
|
||||
[2,000-user reference architecture](2k_users.md).
|
||||
If you have fewer than 3,000 users and still want a highly-available GitLab deployment,
|
||||
you should still use this reference architecture but scale down the node sizes.
|
||||
|
||||
> - **Supported users (approximate):** 3,000
|
||||
> - **High Availability:** Yes
|
||||
|
|
|
|||
|
|
@ -132,6 +132,10 @@ Pipelines can be manually executed, with predefined or manually-specified [varia
|
|||
You might do this if the results of a pipeline (for example, a code build) are required outside the normal
|
||||
operation of the pipeline.
|
||||
|
||||
[In GitLab 13.7 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/30101),
|
||||
the variables fields are pre-filled with any global variables defined in the
|
||||
`.gitlab-ci.yml` file.
|
||||
|
||||
To execute a pipeline manually:
|
||||
|
||||
1. Navigate to your project's **CI/CD > Pipelines**.
|
||||
|
|
|
|||
|
|
@ -378,6 +378,18 @@ You can also enable a feature flag for a given gate:
|
|||
Feature.enable(:feature_flag_name, Project.find_by_full_path("root/my-project"))
|
||||
```
|
||||
|
||||
### Removing a feature flag locally (in development)
|
||||
|
||||
When manually enabling or disabling a feature flag from the Rails console, its default value gets overwritten.
|
||||
This can cause confusion when changing the flag's `default_enabled` attribute.
|
||||
|
||||
To reset the feature flag to the default status, you can remove it in the rails console (`rails c`)
|
||||
as follows:
|
||||
|
||||
```ruby
|
||||
Feature.remove(:feature_flag_name)
|
||||
```
|
||||
|
||||
## Feature flags in tests
|
||||
|
||||
Introducing a feature flag into the codebase creates an additional code path that should be tested.
|
||||
|
|
|
|||
|
|
@ -132,6 +132,13 @@ A more detailed Composer CI/CD file is also available as a `.gitlab-ci.yml` temp
|
|||
WARNING:
|
||||
Do not save unless you want to overwrite the existing CI/CD file.
|
||||
|
||||
## Publishing packages with the same name or version
|
||||
|
||||
When you publish:
|
||||
|
||||
- The same package with different data, it overwrites the existing package.
|
||||
- The same package with the same data, a `404 Bad request` error occurs.
|
||||
|
||||
## Install a Composer package
|
||||
|
||||
Install a package from the Package Registry so you can use it as a dependency.
|
||||
|
|
|
|||
|
|
@ -465,3 +465,26 @@ If you get this error, your package name may not meet the
|
|||
|
||||
Ensure the name meets the convention exactly, including the case.
|
||||
Then try to publish again.
|
||||
|
||||
### `npm publish` returns `npm ERR! 500 Internal Server Error - PUT`
|
||||
|
||||
This is a [known issue](https://gitlab.com/gitlab-org/gitlab/-/issues/238950) in GitLab
|
||||
13.3.x and later. The error in the logs will appear as:
|
||||
|
||||
```plaintext
|
||||
>NoMethodError - undefined method `preferred_language' for #<Rack::Response
|
||||
```
|
||||
|
||||
This might be accompanied by another error:
|
||||
|
||||
```plaintext
|
||||
>Errno::EACCES","exception.message":"Permission denied
|
||||
```
|
||||
|
||||
This is usually a permissions issue with either:
|
||||
|
||||
- `'packages_storage_path'` default `/var/opt/gitlab/gitlab-rails/shared/packages/`.
|
||||
- The remote bucket if [object storage](../../../administration/packages/#using-object-storage)
|
||||
is used.
|
||||
|
||||
In the latter case, ensure the bucket exists and the GitLab has write access to it.
|
||||
|
|
|
|||
|
|
@ -301,6 +301,12 @@ python -m twine upload --repository <source_name> dist/<package_file>
|
|||
- `<package_file>` is your package filename, ending in `.tar.gz` or `.whl`.
|
||||
- `<source_name>` is the [source name used during setup](#authenticate-with-the-package-registry).
|
||||
|
||||
### Publishing packages with the same name or version
|
||||
|
||||
You cannot publish a package if a package of the same name and version already exists.
|
||||
You must delete the existing package first. If you attempt to publish the same package
|
||||
more than once, a `404 Bad request` error occurs.
|
||||
|
||||
## Install a PyPI package
|
||||
|
||||
To install the latest version of a package, use the following command:
|
||||
|
|
|
|||
|
|
@ -52,14 +52,17 @@ The Advanced Search Syntax also supports the use of filters. The available filte
|
|||
- blob: Filters by Git `object ID`. Exact match only.
|
||||
|
||||
To use them, add them to your keyword in the format `<filter_name>:<value>` without
|
||||
any spaces between the colon (`:`) and the value. A keyword or an asterisk (`*`) is required for filter searches and has to be added in front of the filter separated by a space.
|
||||
any spaces between the colon (`:`) and the value. When no keyword is provided, an asterisk (`*`) will be used as the keyword.
|
||||
|
||||
Examples:
|
||||
|
||||
- Finding a file with any content named `search_results.rb`: [`* filename:search_results.rb`](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=blobs&repository_ref=&search=*+filename%3Asearch_results.rb&group_id=9970&project_id=278964)
|
||||
- Finding a file named `found_blob_spec.rb` with the text `CHANGELOG` inside of it: [`CHANGELOG filename:found_blob_spec.rb](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=blobs&repository_ref=&search=CHANGELOG+filename%3Afound_blob_spec.rb&group_id=9970&project_id=278964)
|
||||
- The leading asterisk (`*`) can be ignored in the case above: [`filename:search_results.rb`](https://gitlab.com/search?group_id=9970&project_id=278964&scope=blobs&search=filename%3Asearch_results.rb)
|
||||
- Finding a file named `found_blob_spec.rb` with the text `CHANGELOG` inside of it: [`CHANGELOG filename:found_blob_spec.rb`](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=blobs&repository_ref=&search=CHANGELOG+filename%3Afound_blob_spec.rb&group_id=9970&project_id=278964)
|
||||
- Finding the text `EpicLinks` inside files with the `.rb` extension: [`EpicLinks extension:rb`](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=blobs&repository_ref=&search=EpicLinks+extension%3Arb&group_id=9970&project_id=278964)
|
||||
- Finding any file with the `.yaml` extension: [`extension:yaml`](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=blobs&repository_ref=&search=extension%3Ayaml&group_id=9970&project_id=278964)
|
||||
- Finding the text `Sidekiq` in a file, when that file is in a path that includes `elastic`: [`Sidekiq path:elastic`](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=blobs&repository_ref=&search=Sidekiq+path%3Aelastic&group_id=9970&project_id=278964)
|
||||
- Finding any file in a path that includes `elasticsearch`: [`path:elasticsearch`](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=blobs&repository_ref=&search=path%3Aelasticsearch&group_id=9970&project_id=278964)
|
||||
- Finding the files represented by the Git object ID `998707b421c89bd9a3063333f9f728ef3e43d101`: [`* blob:998707b421c89bd9a3063333f9f728ef3e43d101`](https://gitlab.com/search?utf8=%E2%9C%93&snippets=false&scope=blobs&repository_ref=&search=*+blob%3A998707b421c89bd9a3063333f9f728ef3e43d101&group_id=9970)
|
||||
- Syntax filters can be combined for complex filtering. Finding any file starting with `search` containing `eventHub` and with the `.js` extension: [`eventHub filename:search* extension:js`](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=blobs&repository_ref=&search=eventHub+filename%3Asearch*+extension%3Ajs&group_id=9970&project_id=278964)
|
||||
|
||||
|
|
|
|||
|
|
@ -9,9 +9,13 @@ module Gitlab
|
|||
|
||||
CONTEXT_LINES = 3
|
||||
|
||||
CONFLICT_MARKER_OUR = 'conflict_marker_our'
|
||||
CONFLICT_MARKER_THEIR = 'conflict_marker_their'
|
||||
CONFLICT_MARKER_SEPARATOR = 'conflict_marker'
|
||||
|
||||
CONFLICT_TYPES = {
|
||||
"old" => "conflict_marker_their",
|
||||
"new" => "conflict_marker_our"
|
||||
"old" => "conflict_their",
|
||||
"new" => "conflict_our"
|
||||
}.freeze
|
||||
|
||||
attr_reader :merge_request
|
||||
|
|
@ -59,18 +63,25 @@ module Gitlab
|
|||
if section[:conflict]
|
||||
lines = []
|
||||
|
||||
initial_type = nil
|
||||
lines << create_separator_line(section[:lines].first, CONFLICT_MARKER_OUR)
|
||||
|
||||
current_type = section[:lines].first.type
|
||||
section[:lines].each do |line|
|
||||
if line.type != initial_type
|
||||
lines << create_separator_line(line)
|
||||
initial_type = line.type
|
||||
if line.type != current_type # insert a separator between our changes and theirs
|
||||
lines << create_separator_line(line, CONFLICT_MARKER_SEPARATOR)
|
||||
current_type = line.type
|
||||
end
|
||||
|
||||
line.type = CONFLICT_TYPES[line.type]
|
||||
|
||||
# Swap the positions around due to conflicts/diffs display inconsistency
|
||||
# https://gitlab.com/gitlab-org/gitlab/-/issues/291989
|
||||
line.old_pos, line.new_pos = line.new_pos, line.old_pos
|
||||
|
||||
lines << line
|
||||
end
|
||||
|
||||
lines << create_separator_line(lines.last)
|
||||
lines << create_separator_line(lines.last, CONFLICT_MARKER_THEIR)
|
||||
|
||||
lines
|
||||
else
|
||||
|
|
@ -156,8 +167,8 @@ module Gitlab
|
|||
Gitlab::Diff::Line.new('', 'match', line.index, line.old_pos, line.new_pos)
|
||||
end
|
||||
|
||||
def create_separator_line(line)
|
||||
Gitlab::Diff::Line.new('', 'conflict_marker', line.index, nil, nil)
|
||||
def create_separator_line(line, type)
|
||||
Gitlab::Diff::Line.new('', type, line.index, nil, nil)
|
||||
end
|
||||
|
||||
# Any line beginning with a letter, an underscore, or a dollar can be used in a
|
||||
|
|
|
|||
|
|
@ -8,9 +8,9 @@ module Gitlab
|
|||
#
|
||||
SERIALIZE_KEYS = %i(line_code rich_text text type index old_pos new_pos).freeze
|
||||
|
||||
attr_reader :line_code, :old_pos, :new_pos
|
||||
attr_reader :line_code
|
||||
attr_writer :rich_text
|
||||
attr_accessor :text, :index, :type
|
||||
attr_accessor :text, :index, :type, :old_pos, :new_pos
|
||||
|
||||
def initialize(text, type, index, old_pos, new_pos, parent_file: nil, line_code: nil, rich_text: nil)
|
||||
@text, @type, @index = text, type, index
|
||||
|
|
|
|||
|
|
@ -8617,6 +8617,9 @@ msgstr ""
|
|||
msgid "DastProfiles|Active"
|
||||
msgstr ""
|
||||
|
||||
msgid "DastProfiles|Additional request headers (Optional)"
|
||||
msgstr ""
|
||||
|
||||
msgid "DastProfiles|Are you sure you want to delete this profile?"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -8686,6 +8689,9 @@ msgstr ""
|
|||
msgid "DastProfiles|Excluded URLs"
|
||||
msgstr ""
|
||||
|
||||
msgid "DastProfiles|Excluded URLs (Optional)"
|
||||
msgstr ""
|
||||
|
||||
msgid "DastProfiles|Hide debug messages"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -69,7 +69,8 @@ RSpec.describe 'Batch diffs', :js do
|
|||
end
|
||||
|
||||
context 'which is in at least page 2 of the batched pages of diffs' do
|
||||
it 'scrolls to the correct discussion' do
|
||||
it 'scrolls to the correct discussion',
|
||||
quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/293814' } do
|
||||
page.within('.diff-file.file-holder:last-of-type') do
|
||||
click_link('just now')
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1119,6 +1119,42 @@ describe('DiffsStoreUtils', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('isConflictMarker', () => {
|
||||
it.each`
|
||||
type | expected
|
||||
${'conflict_marker_our'} | ${true}
|
||||
${'conflict_marker_their'} | ${true}
|
||||
${'conflict_their'} | ${false}
|
||||
${'conflict_our'} | ${false}
|
||||
`('returns $expected when type is $type', ({ type, expected }) => {
|
||||
expect(utils.isConflictMarker({ type })).toBe(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isConflictOur', () => {
|
||||
it.each`
|
||||
type | expected
|
||||
${'conflict_marker_our'} | ${false}
|
||||
${'conflict_marker_their'} | ${false}
|
||||
${'conflict_their'} | ${false}
|
||||
${'conflict_our'} | ${true}
|
||||
`('returns $expected when type is $type', ({ type, expected }) => {
|
||||
expect(utils.isConflictOur({ type })).toBe(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isConflictTheir', () => {
|
||||
it.each`
|
||||
type | expected
|
||||
${'conflict_marker_our'} | ${false}
|
||||
${'conflict_marker_their'} | ${false}
|
||||
${'conflict_their'} | ${true}
|
||||
${'conflict_our'} | ${false}
|
||||
`('returns $expected when type is $type', ({ type, expected }) => {
|
||||
expect(utils.isConflictTheir({ type })).toBe(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('parallelizeDiffLines', () => {
|
||||
it('converts inline diff lines to parallel diff lines', () => {
|
||||
const file = getDiffFileMock();
|
||||
|
|
@ -1128,6 +1164,34 @@ describe('DiffsStoreUtils', () => {
|
|||
);
|
||||
});
|
||||
|
||||
it('converts conflicted diffs line', () => {
|
||||
const lines = [
|
||||
{ type: 'new' },
|
||||
{ type: 'conflict_marker_our' },
|
||||
{ type: 'conflict_our' },
|
||||
{ type: 'conflict_marker' },
|
||||
{ type: 'conflict_their' },
|
||||
{ type: 'conflict_marker_their' },
|
||||
];
|
||||
|
||||
expect(utils.parallelizeDiffLines(lines)).toEqual([
|
||||
{
|
||||
left: null,
|
||||
right: {
|
||||
type: 'new',
|
||||
},
|
||||
},
|
||||
{
|
||||
left: { type: 'conflict_marker_our' },
|
||||
right: { type: 'conflict_marker_their' },
|
||||
},
|
||||
{
|
||||
left: { type: 'conflict_our' },
|
||||
right: { type: 'conflict_their' },
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('converts inline diff lines', () => {
|
||||
const file = getDiffFileMock();
|
||||
const files = utils.parallelizeDiffLines(file.highlighted_diff_lines, true);
|
||||
|
|
|
|||
|
|
@ -97,19 +97,27 @@ RSpec.describe Gitlab::Conflict::File do
|
|||
let(:diff_line_types) { conflict_file.diff_lines_for_serializer.map(&:type) }
|
||||
|
||||
it 'assigns conflict types to the diff lines' do
|
||||
expect(diff_line_types[4]).to eq('conflict_marker')
|
||||
expect(diff_line_types[5..10]).to eq(['conflict_marker_our'] * 6)
|
||||
expect(diff_line_types[4]).to eq('conflict_marker_our')
|
||||
expect(diff_line_types[5..10]).to eq(['conflict_our'] * 6)
|
||||
expect(diff_line_types[11]).to eq('conflict_marker')
|
||||
expect(diff_line_types[12..17]).to eq(['conflict_marker_their'] * 6)
|
||||
expect(diff_line_types[18]).to eq('conflict_marker')
|
||||
expect(diff_line_types[12..17]).to eq(['conflict_their'] * 6)
|
||||
expect(diff_line_types[18]).to eq('conflict_marker_their')
|
||||
|
||||
expect(diff_line_types[19..24]).to eq([nil] * 6)
|
||||
|
||||
expect(diff_line_types[25]).to eq('conflict_marker')
|
||||
expect(diff_line_types[26..27]).to eq(['conflict_marker_our'] * 2)
|
||||
expect(diff_line_types[25]).to eq('conflict_marker_our')
|
||||
expect(diff_line_types[26..27]).to eq(['conflict_our'] * 2)
|
||||
expect(diff_line_types[28]).to eq('conflict_marker')
|
||||
expect(diff_line_types[29..30]).to eq(['conflict_marker_their'] * 2)
|
||||
expect(diff_line_types[31]).to eq('conflict_marker')
|
||||
expect(diff_line_types[29..30]).to eq(['conflict_their'] * 2)
|
||||
expect(diff_line_types[31]).to eq('conflict_marker_their')
|
||||
end
|
||||
|
||||
# Swap the positions around due to conflicts/diffs display inconsistency
|
||||
# https://gitlab.com/gitlab-org/gitlab/-/issues/291989
|
||||
it 'swaps the new and old positions around' do
|
||||
lines = conflict_file.diff_lines_for_serializer
|
||||
expect(lines.map(&:old_pos)[26..27]).to eq([21, 22])
|
||||
expect(lines.map(&:new_pos)[29..30]).to eq([21, 22])
|
||||
end
|
||||
|
||||
it 'does not add a match line to the end of the section' do
|
||||
|
|
@ -124,13 +132,13 @@ RSpec.describe Gitlab::Conflict::File do
|
|||
expect(diff_line_types).to eq([
|
||||
'match',
|
||||
nil, nil, nil,
|
||||
"conflict_marker",
|
||||
"conflict_marker_our",
|
||||
"conflict_our",
|
||||
"conflict_marker",
|
||||
"conflict_their",
|
||||
"conflict_their",
|
||||
"conflict_their",
|
||||
"conflict_marker_their",
|
||||
"conflict_marker_their",
|
||||
"conflict_marker_their",
|
||||
"conflict_marker",
|
||||
nil, nil, nil,
|
||||
"match"
|
||||
])
|
||||
|
|
|
|||
Loading…
Reference in New Issue