Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2020-12-17 09:10:19 +00:00
parent d97b2fedc8
commit 173bd0618f
29 changed files with 563 additions and 240 deletions

View File

@ -1 +1 @@
13.14.0
13.15.0

View File

@ -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"
>
&nbsp;
</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>

View File

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

View File

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

View File

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

View File

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

View File

@ -198,6 +198,8 @@ $dark-il: #de935f;
}
}
@include conflict-colors('dark');
// highlight line via anchor
pre .hll {
background-color: $dark-pre-hll-bg !important;

View File

@ -198,6 +198,8 @@ $monokai-gi: #a6e22e;
}
}
@include conflict-colors('monokai');
// highlight line via anchor
pre .hll {
background-color: $monokai-hll !important;

View File

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

View File

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

View File

@ -1,3 +1,5 @@
.code.white {
@import '../white_base';
@include conflict-colors('white');
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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