summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.haml-lint_todo.yml4
-rw-r--r--app/assets/javascripts/boards/components/board_card.vue6
-rw-r--r--app/assets/javascripts/boards/components/board_card_inner.vue (renamed from app/assets/javascripts/boards/components/issue_card_inner.vue)81
-rw-r--r--app/assets/javascripts/boards/components/board_card_layout_deprecated.vue3
-rw-r--r--app/assets/javascripts/boards/components/issue_card_inner_deprecated.vue6
-rw-r--r--app/assets/javascripts/boards/components/modal/list.vue6
-rw-r--r--app/assets/javascripts/boards/mixins/board_card_inner.js (renamed from app/assets/javascripts/boards/mixins/issue_card_inner.js)4
-rw-r--r--app/assets/javascripts/merge_conflicts/merge_conflict_resolver_app.vue217
-rw-r--r--app/assets/javascripts/merge_conflicts/merge_conflicts_bundle.js26
-rw-r--r--app/assets/javascripts/pages/projects/boards/index.js8
-rw-r--r--app/assets/stylesheets/page_bundles/boards.scss2
-rw-r--r--app/graphql/types/blob_viewers/type_enum.rb6
-rw-r--r--app/services/users/build_service.rb3
-rw-r--r--app/views/projects/merge_requests/conflicts/_commit_stats.html.haml11
-rw-r--r--app/views/projects/merge_requests/conflicts/_file_actions.html.haml12
-rw-r--r--app/views/projects/merge_requests/conflicts/_submit_form.html.haml24
-rw-r--r--app/views/projects/merge_requests/conflicts/show.html.haml32
-rw-r--r--changelogs/unreleased/284116-sync-or-remove-single-file-mode-user-preference.yml5
-rw-r--r--changelogs/unreleased/x509-cert-loading.yml5
-rw-r--r--doc/administration/pages/index.md100
-rw-r--r--doc/administration/repository_storage_types.md132
-rw-r--r--doc/administration/troubleshooting/elasticsearch.md2
-rw-r--r--doc/api/graphql/reference/index.md6
-rw-r--r--doc/api/settings.md2
-rw-r--r--doc/api/users.md2
-rw-r--r--doc/development/git_object_deduplication.md5
-rw-r--r--doc/user/project/merge_requests/browser_performance_testing.md6
-rw-r--r--doc/user/project/merge_requests/code_quality.md12
-rw-r--r--doc/user/project/merge_requests/load_performance_testing.md6
-rw-r--r--lib/api/users.rb1
-rw-r--r--lib/gitlab/x509/signature.rb6
-rw-r--r--locale/gitlab.pot5
-rw-r--r--spec/frontend/boards/board_card_inner_spec.js (renamed from spec/frontend/boards/issue_card_inner_spec.js)50
-rw-r--r--spec/frontend/boards/components/board_card_deprecated_spec.js2
-rw-r--r--spec/frontend/boards/components/board_card_layout_deprecated_spec.js2
-rw-r--r--spec/frontend/boards/components/board_card_spec.js4
-rw-r--r--spec/lib/gitlab/x509/signature_spec.rb122
-rw-r--r--spec/requests/api/users_spec.rb19
38 files changed, 570 insertions, 375 deletions
diff --git a/.haml-lint_todo.yml b/.haml-lint_todo.yml
index bda203f30ac..ac05540aad7 100644
--- a/.haml-lint_todo.yml
+++ b/.haml-lint_todo.yml
@@ -213,10 +213,6 @@ linters:
- 'app/views/projects/mattermosts/new.html.haml'
- 'app/views/projects/merge_requests/_commits.html.haml'
- 'app/views/projects/merge_requests/_mr_title.html.haml'
- - 'app/views/projects/merge_requests/conflicts/_commit_stats.html.haml'
- - 'app/views/projects/merge_requests/conflicts/_file_actions.html.haml'
- - 'app/views/projects/merge_requests/conflicts/_submit_form.html.haml'
- - 'app/views/projects/merge_requests/conflicts/show.html.haml'
- 'app/views/projects/merge_requests/creations/_diffs.html.haml'
- 'app/views/projects/merge_requests/creations/_new_compare.html.haml'
- 'app/views/projects/merge_requests/creations/_new_submit.html.haml'
diff --git a/app/assets/javascripts/boards/components/board_card.vue b/app/assets/javascripts/boards/components/board_card.vue
index a0fee1b064b..408a414ea16 100644
--- a/app/assets/javascripts/boards/components/board_card.vue
+++ b/app/assets/javascripts/boards/components/board_card.vue
@@ -1,11 +1,11 @@
<script>
import { mapActions, mapGetters, mapState } from 'vuex';
-import IssueCardInner from './issue_card_inner.vue';
+import BoardCardInner from './board_card_inner.vue';
export default {
name: 'BoardCard',
components: {
- IssueCardInner,
+ BoardCardInner,
},
props: {
list: {
@@ -76,6 +76,6 @@ export default {
class="board-card gl-p-5 gl-rounded-base"
@mouseup="toggleIssue($event)"
>
- <issue-card-inner :list="list" :issue="issue" :update-filters="true" />
+ <board-card-inner :list="list" :item="issue" :update-filters="true" />
</li>
</template>
diff --git a/app/assets/javascripts/boards/components/issue_card_inner.vue b/app/assets/javascripts/boards/components/board_card_inner.vue
index e5ea30df767..ae1a82b9c4a 100644
--- a/app/assets/javascripts/boards/components/issue_card_inner.vue
+++ b/app/assets/javascripts/boards/components/board_card_inner.vue
@@ -2,7 +2,7 @@
import { GlLabel, GlTooltipDirective, GlIcon } from '@gitlab/ui';
import { sortBy } from 'lodash';
import { mapActions, mapState } from 'vuex';
-import issueCardInner from 'ee_else_ce/boards/mixins/issue_card_inner';
+import boardCardInner from 'ee_else_ce/boards/mixins/board_card_inner';
import { isScopedLabel } from '~/lib/utils/common_utils';
import { updateHistory } from '~/lib/utils/url_utility';
import { sprintf, __, n__ } from '~/locale';
@@ -26,10 +26,10 @@ export default {
directives: {
GlTooltip: GlTooltipDirective,
},
- mixins: [issueCardInner],
+ mixins: [boardCardInner],
inject: ['groupId', 'rootPath', 'scopedLabelsAvailable'],
props: {
- issue: {
+ item: {
type: Object,
required: true,
},
@@ -52,19 +52,19 @@ export default {
};
},
computed: {
- ...mapState(['isShowingLabels']),
+ ...mapState(['isShowingLabels', 'isEpicBoard']),
cappedAssignees() {
// e.g. maxRender is 4,
// Render up to all 4 assignees if there are only 4 assigness
// Otherwise render up to the limitBeforeCounter
- if (this.issue.assignees.length <= this.maxRender) {
- return this.issue.assignees.slice(0, this.maxRender);
+ if (this.item.assignees.length <= this.maxRender) {
+ return this.item.assignees.slice(0, this.maxRender);
}
- return this.issue.assignees.slice(0, this.limitBeforeCounter);
+ return this.item.assignees.slice(0, this.limitBeforeCounter);
},
numberOverLimit() {
- return this.issue.assignees.length - this.limitBeforeCounter;
+ return this.item.assignees.length - this.limitBeforeCounter;
},
assigneeCounterTooltip() {
const { numberOverLimit, maxCounter } = this;
@@ -79,31 +79,35 @@ export default {
return `+${this.numberOverLimit}`;
},
shouldRenderCounter() {
- if (this.issue.assignees.length <= this.maxRender) {
+ if (this.item.assignees.length <= this.maxRender) {
return false;
}
- return this.issue.assignees.length > this.numberOverLimit;
+ return this.item.assignees.length > this.numberOverLimit;
},
- issueId() {
- if (this.issue.iid) {
- return `#${this.issue.iid}`;
+ itemPrefix() {
+ return this.isEpicBoard ? '&' : '#';
+ },
+
+ itemId() {
+ if (this.item.iid) {
+ return `${this.itemPrefix}${this.item.iid}`;
}
return false;
},
showLabelFooter() {
- return this.isShowingLabels && this.issue.labels.find(this.showLabel);
+ return this.isShowingLabels && this.item.labels.find(this.showLabel);
},
- issueReferencePath() {
- const { referencePath, groupId } = this.issue;
- return !groupId ? referencePath.split('#')[0] : null;
+ itemReferencePath() {
+ const { referencePath } = this.item;
+ return referencePath.split(this.itemPrefix)[0];
},
orderedLabels() {
- return sortBy(this.issue.labels.filter(this.isNonListLabel), 'title');
+ return sortBy(this.item.labels.filter(this.isNonListLabel), 'title');
},
blockedLabel() {
- if (this.issue.blockedByCount) {
- return n__(`Blocked by %d issue`, `Blocked by %d issues`, this.issue.blockedByCount);
+ if (this.item.blockedByCount) {
+ return n__(`Blocked by %d issue`, `Blocked by %d issues`, this.item.blockedByCount);
}
return __('Blocked issue');
},
@@ -160,7 +164,7 @@ export default {
<div class="gl-display-flex" dir="auto">
<h4 class="board-card-title gl-mb-0 gl-mt-0">
<gl-icon
- v-if="issue.blocked"
+ v-if="item.blocked"
v-gl-tooltip
name="issue-block"
:title="blockedLabel"
@@ -169,7 +173,7 @@ export default {
data-testid="issue-blocked-icon"
/>
<gl-icon
- v-if="issue.confidential"
+ v-if="item.confidential"
v-gl-tooltip
name="eye-slash"
:title="__('Confidential')"
@@ -177,11 +181,11 @@ export default {
:aria-label="__('Confidential')"
/>
<a
- :href="issue.path || issue.webUrl || ''"
- :title="issue.title"
+ :href="item.path || item.webUrl || ''"
+ :title="item.title"
class="js-no-trigger"
@mousemove.stop
- >{{ issue.title }}</a
+ >{{ item.title }}</a
>
</h4>
</div>
@@ -205,29 +209,30 @@ export default {
class="gl-display-flex align-items-start flex-wrap-reverse board-card-number-container gl-overflow-hidden js-board-card-number-container"
>
<span
- v-if="issue.referencePath"
+ v-if="item.referencePath"
class="board-card-number gl-overflow-hidden gl-display-flex gl-mr-3 gl-mt-3"
+ :class="{ 'gl-font-base': isEpicBoard }"
>
<tooltip-on-truncate
- v-if="issueReferencePath"
- :title="issueReferencePath"
+ v-if="itemReferencePath"
+ :title="itemReferencePath"
placement="bottom"
- class="board-issue-path gl-text-truncate gl-font-weight-bold"
- >{{ issueReferencePath }}</tooltip-on-truncate
+ class="board-item-path gl-text-truncate gl-font-weight-bold"
+ >{{ itemReferencePath }}</tooltip-on-truncate
>
- #{{ issue.iid }}
+ {{ itemId }}
</span>
<span class="board-info-items gl-mt-3 gl-display-inline-block">
<issue-due-date
- v-if="issue.dueDate"
- :date="issue.dueDate"
- :closed="issue.closed || Boolean(issue.closedAt)"
+ v-if="item.dueDate"
+ :date="item.dueDate"
+ :closed="item.closed || Boolean(item.closedAt)"
/>
- <issue-time-estimate v-if="issue.timeEstimate" :estimate="issue.timeEstimate" />
+ <issue-time-estimate v-if="item.timeEstimate" :estimate="item.timeEstimate" />
<issue-card-weight
- v-if="validIssueWeight"
- :weight="issue.weight"
- @click="filterByWeight(issue.weight)"
+ v-if="validIssueWeight(item)"
+ :weight="item.weight"
+ @click="filterByWeight(item.weight)"
/>
</span>
</div>
diff --git a/app/assets/javascripts/boards/components/board_card_layout_deprecated.vue b/app/assets/javascripts/boards/components/board_card_layout_deprecated.vue
index f9a726134a3..3381e4c3a7d 100644
--- a/app/assets/javascripts/boards/components/board_card_layout_deprecated.vue
+++ b/app/assets/javascripts/boards/components/board_card_layout_deprecated.vue
@@ -3,13 +3,12 @@ import { mapActions, mapGetters } from 'vuex';
import { ISSUABLE } from '~/boards/constants';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import boardsStore from '../stores/boards_store';
-import IssueCardInner from './issue_card_inner.vue';
import IssueCardInnerDeprecated from './issue_card_inner_deprecated.vue';
export default {
name: 'BoardCardLayout',
components: {
- IssueCardInner: gon.features?.graphqlBoardLists ? IssueCardInner : IssueCardInnerDeprecated,
+ IssueCardInner: IssueCardInnerDeprecated,
},
mixins: [glFeatureFlagMixin()],
props: {
diff --git a/app/assets/javascripts/boards/components/issue_card_inner_deprecated.vue b/app/assets/javascripts/boards/components/issue_card_inner_deprecated.vue
index 069cc2cda22..2652fac1818 100644
--- a/app/assets/javascripts/boards/components/issue_card_inner_deprecated.vue
+++ b/app/assets/javascripts/boards/components/issue_card_inner_deprecated.vue
@@ -2,7 +2,7 @@
import { GlLabel, GlTooltipDirective, GlIcon } from '@gitlab/ui';
import { sortBy } from 'lodash';
import { mapState } from 'vuex';
-import issueCardInner from 'ee_else_ce/boards/mixins/issue_card_inner';
+import boardCardInner from 'ee_else_ce/boards/mixins/board_card_inner';
import { isScopedLabel } from '~/lib/utils/common_utils';
import { sprintf, __, n__ } from '~/locale';
import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue';
@@ -24,7 +24,7 @@ export default {
directives: {
GlTooltip: GlTooltipDirective,
},
- mixins: [issueCardInner],
+ mixins: [boardCardInner],
inject: ['groupId', 'rootPath'],
props: {
issue: {
@@ -207,7 +207,7 @@ export default {
/>
<issue-time-estimate v-if="issue.timeEstimate" :estimate="issue.timeEstimate" />
<issue-card-weight
- v-if="validIssueWeight"
+ v-if="validIssueWeight(issue)"
:weight="issue.weight"
@click="filterByWeight(issue.weight)"
/>
diff --git a/app/assets/javascripts/boards/components/modal/list.vue b/app/assets/javascripts/boards/components/modal/list.vue
index bf69f8140d5..e66cae0ce18 100644
--- a/app/assets/javascripts/boards/components/modal/list.vue
+++ b/app/assets/javascripts/boards/components/modal/list.vue
@@ -2,11 +2,11 @@
import { GlIcon } from '@gitlab/ui';
import { GlBreakpointInstance as bp } from '@gitlab/ui/dist/utils';
import ModalStore from '../../stores/modal_store';
-import IssueCardInner from '../issue_card_inner.vue';
+import BoardCardInner from '../board_card_inner.vue';
export default {
components: {
- IssueCardInner,
+ BoardCardInner,
GlIcon,
},
props: {
@@ -126,7 +126,7 @@ export default {
class="board-card position-relative p-3 rounded"
@click="toggleIssue($event, issue)"
>
- <issue-card-inner :issue="issue" />
+ <board-card-inner :item="issue" />
<gl-icon
v-if="issue.selected"
:aria-label="'Issue #' + issue.id + ' selected'"
diff --git a/app/assets/javascripts/boards/mixins/issue_card_inner.js b/app/assets/javascripts/boards/mixins/board_card_inner.js
index 04e971b756d..a6f278f3bc9 100644
--- a/app/assets/javascripts/boards/mixins/issue_card_inner.js
+++ b/app/assets/javascripts/boards/mixins/board_card_inner.js
@@ -1,10 +1,8 @@
export default {
- computed: {
+ methods: {
validIssueWeight() {
return false;
},
- },
- methods: {
filterByWeight() {},
},
};
diff --git a/app/assets/javascripts/merge_conflicts/merge_conflict_resolver_app.vue b/app/assets/javascripts/merge_conflicts/merge_conflict_resolver_app.vue
new file mode 100644
index 00000000000..16a7cfb2ba8
--- /dev/null
+++ b/app/assets/javascripts/merge_conflicts/merge_conflict_resolver_app.vue
@@ -0,0 +1,217 @@
+<script>
+import { GlSprintf } from '@gitlab/ui';
+import { __ } from '~/locale';
+import FileIcon from '~/vue_shared/components/file_icon.vue';
+import DiffFileEditor from './components/diff_file_editor.vue';
+import InlineConflictLines from './components/inline_conflict_lines.vue';
+import ParallelConflictLines from './components/parallel_conflict_lines.vue';
+
+/**
+ * NOTE: Most of this component is directly using $root, rather than props or a better data store.
+ * This is BAD and one shouldn't copy that behavior. Similarly a lot of the classes below should
+ * be replaced with GitLab UI components.
+ *
+ * We are just doing it temporarily in order to migrate the template from HAML => Vue in an iterative manner
+ * and are going to clean it up as part of:
+ *
+ * https://gitlab.com/gitlab-org/gitlab/-/issues/321090
+ *
+ */
+export default {
+ components: {
+ GlSprintf,
+ FileIcon,
+ DiffFileEditor,
+ InlineConflictLines,
+ ParallelConflictLines,
+ },
+ inject: ['mergeRequestPath', 'sourceBranchPath'],
+ i18n: {
+ commitStatSummary: __('Showing %{conflict} between %{sourceBranch} and %{targetBranch}'),
+ resolveInfo: __(
+ 'You can resolve the merge conflict using either the Interactive mode, by choosing %{use_ours} or %{use_theirs} buttons, or by editing the files directly. Commit these changes into %{branch_name}',
+ ),
+ },
+};
+</script>
+<template>
+ <div id="conflicts">
+ <div v-if="$root.isLoading" class="loading">
+ <div class="spinner spinner-md"></div>
+ </div>
+ <div v-if="$root.hasError" class="nothing-here-block">
+ {{ $root.conflictsData.errorMessage }}
+ </div>
+ <template v-if="!$root.isLoading && !$root.hasError">
+ <div class="content-block oneline-block files-changed">
+ <div v-if="$root.showDiffViewTypeSwitcher" class="inline-parallel-buttons">
+ <div class="btn-group">
+ <button
+ :class="{ active: !$root.isParallel }"
+ class="btn gl-button"
+ @click="$root.handleViewTypeChange('inline')"
+ >
+ {{ __('Inline') }}
+ </button>
+ <button
+ :class="{ active: $root.isParallel }"
+ class="btn gl-button"
+ @click="$root.handleViewTypeChange('parallel')"
+ >
+ {{ __('Side-by-side') }}
+ </button>
+ </div>
+ </div>
+ <div class="js-toggle-container">
+ <div class="commit-stat-summary">
+ <gl-sprintf :message="$options.i18n.commitStatSummary">
+ <template #conflict>
+ <strong class="cred">
+ {{ $root.conflictsCountText }}
+ </strong>
+ </template>
+ <template #sourceBranch>
+ <strong class="ref-name">
+ {{ $root.conflictsData.sourceBranch }}
+ </strong>
+ </template>
+ <template #targetBranch>
+ <strong class="ref-name">
+ {{ $root.conflictsData.targetBranch }}
+ </strong>
+ </template>
+ </gl-sprintf>
+ </div>
+ </div>
+ </div>
+ <div class="files-wrapper">
+ <div class="files">
+ <div
+ v-for="file in $root.conflictsData.files"
+ :key="file.blobPath"
+ class="diff-file file-holder conflict"
+ >
+ <div class="js-file-title file-title file-title-flex-parent cursor-default">
+ <div class="file-header-content">
+ <file-icon :file-name="file.filePath" :size="18" css-classes="gl-mr-2" />
+ <strong class="file-title-name">{{ file.filePath }}</strong>
+ </div>
+ <div class="file-actions d-flex align-items-center gl-ml-auto gl-align-self-start">
+ <div v-if="file.type === 'text'" class="btn-group gl-mr-3">
+ <button
+ :class="{ active: file.resolveMode === 'interactive' }"
+ class="btn gl-button"
+ type="button"
+ @click="$root.onClickResolveModeButton(file, 'interactive')"
+ >
+ {{ __('Interactive mode') }}
+ </button>
+ <button
+ :class="{ active: file.resolveMode === 'edit' }"
+ class="btn gl-button"
+ type="button"
+ @click="$root.onClickResolveModeButton(file, 'edit')"
+ >
+ {{ __('Edit inline') }}
+ </button>
+ </div>
+ <a :href="file.blobPath" class="btn gl-button view-file">
+ <gl-sprintf :message="__('View file @ %{commitSha}')">
+ <template #commitSha>
+ {{ $root.conflictsData.shortCommitSha }}
+ </template>
+ </gl-sprintf>
+ </a>
+ </div>
+ </div>
+ <div class="diff-content diff-wrap-lines">
+ <div
+ v-show="
+ !$root.isParallel && file.resolveMode === 'interactive' && file.type === 'text'
+ "
+ class="file-content"
+ >
+ <inline-conflict-lines :file="file" />
+ </div>
+ <div
+ v-show="
+ $root.isParallel && file.resolveMode === 'interactive' && file.type === 'text'
+ "
+ class="file-content"
+ >
+ <parallel-conflict-lines :file="file" />
+ </div>
+ <div v-show="file.resolveMode === 'edit' || file.type === 'text-editor'">
+ <diff-file-editor
+ :file="file"
+ :on-accept-discard-confirmation="$root.acceptDiscardConfirmation"
+ :on-cancel-discard-confirmation="$root.cancelDiscardConfirmation"
+ />
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <hr />
+ <div class="resolve-conflicts-form">
+ <div class="form-group row">
+ <div class="col-md-4">
+ <h4>
+ {{ __('Resolve conflicts on source branch') }}
+ </h4>
+ <div class="resolve-info">
+ <gl-sprintf :message="$options.i18n.resolveInfo">
+ <template #use_ours>
+ <code>{{ s__('MergeConflict|Use ours') }}</code>
+ </template>
+ <template #use_theirs>
+ <code>{{ s__('MergeConflict|Use theirs') }}</code>
+ </template>
+ <template #branch_name>
+ <a class="ref-name" :href="sourceBranchPath">
+ {{ $root.conflictsData.sourceBranch }}
+ </a>
+ </template>
+ </gl-sprintf>
+ </div>
+ </div>
+ <div class="col-md-8">
+ <label class="label-bold" for="commit-message">
+ {{ __('Commit message') }}
+ </label>
+ <div class="commit-message-container">
+ <div class="max-width-marker"></div>
+ <textarea
+ id="commit-message"
+ v-model="$root.conflictsData.commitMessage"
+ class="form-control js-commit-message"
+ rows="5"
+ ></textarea>
+ </div>
+ </div>
+ </div>
+ <div class="form-group row">
+ <div class="offset-md-4 col-md-8">
+ <div class="row">
+ <div class="col-6">
+ <button
+ :disabled="!$root.readyToCommit"
+ class="btn gl-button btn-success js-submit-button"
+ type="button"
+ @click="$root.commit()"
+ >
+ <span>{{ $root.commitButtonText }}</span>
+ </button>
+ </div>
+ <div class="col-6 text-right">
+ <a :href="mergeRequestPath" class="gl-button btn btn-default">
+ {{ __('Cancel') }}
+ </a>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </template>
+ </div>
+</template>
diff --git a/app/assets/javascripts/merge_conflicts/merge_conflicts_bundle.js b/app/assets/javascripts/merge_conflicts/merge_conflicts_bundle.js
index a0db0faa592..4b73dd317cd 100644
--- a/app/assets/javascripts/merge_conflicts/merge_conflicts_bundle.js
+++ b/app/assets/javascripts/merge_conflicts/merge_conflicts_bundle.js
@@ -1,18 +1,11 @@
-// This is a true violation of @gitlab/no-runtime-template-compiler, as it
-// relies on app/views/projects/merge_requests/conflicts/show.html.haml for its
-// template.
-/* eslint-disable @gitlab/no-runtime-template-compiler */
import $ from 'jquery';
import Vue from 'vue';
import { __ } from '~/locale';
-import FileIcon from '~/vue_shared/components/file_icon.vue';
import { deprecatedCreateFlash as createFlash } from '../flash';
import initIssuableSidebar from '../init_issuable_sidebar';
import './merge_conflict_store';
import syntaxHighlight from '../syntax_highlight';
-import DiffFileEditor from './components/diff_file_editor.vue';
-import InlineConflictLines from './components/inline_conflict_lines.vue';
-import ParallelConflictLines from './components/parallel_conflict_lines.vue';
+import MergeConflictsResolverApp from './merge_conflict_resolver_app.vue';
import MergeConflictsService from './merge_conflict_service';
export default function initMergeConflicts() {
@@ -24,15 +17,15 @@ export default function initMergeConflicts() {
resolveConflictsPath: conflictsEl.dataset.resolveConflictsPath,
});
+ const { sourceBranchPath, mergeRequestPath } = conflictsEl.dataset;
+
initIssuableSidebar();
- gl.MergeConflictsResolverApp = new Vue({
- el: '#conflicts',
- components: {
- FileIcon,
- DiffFileEditor,
- InlineConflictLines,
- ParallelConflictLines,
+ return new Vue({
+ el: conflictsEl,
+ provide: {
+ sourceBranchPath,
+ mergeRequestPath,
},
data: mergeConflictsStore.state,
computed: {
@@ -103,5 +96,8 @@ export default function initMergeConflicts() {
});
},
},
+ render(createElement) {
+ return createElement(MergeConflictsResolverApp);
+ },
});
}
diff --git a/app/assets/javascripts/pages/projects/boards/index.js b/app/assets/javascripts/pages/projects/boards/index.js
index 3a06d0faa3e..bde0007ec6a 100644
--- a/app/assets/javascripts/pages/projects/boards/index.js
+++ b/app/assets/javascripts/pages/projects/boards/index.js
@@ -2,8 +2,6 @@ import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation';
import initBoards from '~/boards';
import UsersSelect from '~/users_select';
-document.addEventListener('DOMContentLoaded', () => {
- new UsersSelect(); // eslint-disable-line no-new
- new ShortcutsNavigation(); // eslint-disable-line no-new
- initBoards();
-});
+new UsersSelect(); // eslint-disable-line no-new
+new ShortcutsNavigation(); // eslint-disable-line no-new
+initBoards();
diff --git a/app/assets/stylesheets/page_bundles/boards.scss b/app/assets/stylesheets/page_bundles/boards.scss
index 620b37914d8..a157c22a302 100644
--- a/app/assets/stylesheets/page_bundles/boards.scss
+++ b/app/assets/stylesheets/page_bundles/boards.scss
@@ -515,7 +515,7 @@
}
}
-.board-issue-path.js-show-tooltip {
+.board-item-path.js-show-tooltip {
cursor: help;
}
diff --git a/app/graphql/types/blob_viewers/type_enum.rb b/app/graphql/types/blob_viewers/type_enum.rb
index 35e659197e5..3cb5c76d881 100644
--- a/app/graphql/types/blob_viewers/type_enum.rb
+++ b/app/graphql/types/blob_viewers/type_enum.rb
@@ -6,9 +6,9 @@ module Types
graphql_name 'BlobViewersType'
description 'Types of blob viewers'
- value 'rich', value: :rich
- value 'simple', value: :simple
- value 'auxiliary', value: :auxiliary
+ value 'rich', value: :rich, description: 'Rich blob viewers type.'
+ value 'simple', value: :simple, description: 'Simple blob viewers type.'
+ value 'auxiliary', value: :auxiliary, description: 'Auxiliary blob viewers type.'
end
end
end
diff --git a/app/services/users/build_service.rb b/app/services/users/build_service.rb
index e3f02bf85f0..b3b172f9df2 100644
--- a/app/services/users/build_service.rb
+++ b/app/services/users/build_service.rb
@@ -83,7 +83,8 @@ module Users
:location,
:public_email,
:user_type,
- :note
+ :note,
+ :view_diffs_file_by_file
]
end
diff --git a/app/views/projects/merge_requests/conflicts/_commit_stats.html.haml b/app/views/projects/merge_requests/conflicts/_commit_stats.html.haml
deleted file mode 100644
index cb1cb41eb71..00000000000
--- a/app/views/projects/merge_requests/conflicts/_commit_stats.html.haml
+++ /dev/null
@@ -1,11 +0,0 @@
-.content-block.oneline-block.files-changed{ "v-if" => "!isLoading && !hasError" }
- .inline-parallel-buttons{ "v-if" => "showDiffViewTypeSwitcher" }
- .btn-group
- %button.btn.gl-button{ ":class" => "{'active': !isParallel}", "@click" => "handleViewTypeChange('inline')" }
- = _('Inline')
- %button.btn.gl-button{ ":class" => "{'active': isParallel}", "@click" => "handleViewTypeChange('parallel')" }
- = _('Side-by-side')
-
- .js-toggle-container
- .commit-stat-summary
- = _('Showing %{conflict_start}%{conflicts_text}%{strong_end} between %{ref_start}%{source_branch}%{strong_end} and %{ref_start}%{target_branch}%{strong_end}').html_safe % { conflict_start: '<strong class="cred">'.html_safe, ref_start: '<strong class="ref-name">'.html_safe, strong_end: '</strong>'.html_safe, conflicts_text: '{{conflictsCountText}}', source_branch: '{{conflictsData.sourceBranch}}', target_branch: '{{conflictsData.targetBranch}}' }
diff --git a/app/views/projects/merge_requests/conflicts/_file_actions.html.haml b/app/views/projects/merge_requests/conflicts/_file_actions.html.haml
deleted file mode 100644
index 220ddf1bad3..00000000000
--- a/app/views/projects/merge_requests/conflicts/_file_actions.html.haml
+++ /dev/null
@@ -1,12 +0,0 @@
-.file-actions.d-flex.align-items-center.gl-ml-auto.gl-align-self-start
- .btn-group.gl-mr-3{ "v-if" => "file.type === 'text'" }
- %button.btn.gl-button{ ":class" => "{ 'active': file.resolveMode == 'interactive' }",
- '@click' => "onClickResolveModeButton(file, 'interactive')",
- type: 'button' }
- = _('Interactive mode')
- %button.btn.gl-button{ ':class' => "{ 'active': file.resolveMode == 'edit' }",
- '@click' => "onClickResolveModeButton(file, 'edit')",
- type: 'button' }
- = _('Edit inline')
- %a.btn.gl-button.view-file{ ":href" => "file.blobPath" }
- = _('View file @%{commit_sha}') % { commit_sha: '{{conflictsData.shortCommitSha}}' }
diff --git a/app/views/projects/merge_requests/conflicts/_submit_form.html.haml b/app/views/projects/merge_requests/conflicts/_submit_form.html.haml
deleted file mode 100644
index 87356f33b1e..00000000000
--- a/app/views/projects/merge_requests/conflicts/_submit_form.html.haml
+++ /dev/null
@@ -1,24 +0,0 @@
-- branch_name = link_to @merge_request.source_branch, project_tree_path(@merge_request.project, @merge_request.source_branch), class: "ref-name"
-- translation =_('You can resolve the merge conflict using either the Interactive mode, by choosing %{use_ours} or %{use_theirs} buttons, or by editing the files directly. Commit these changes into %{branch_name}') % { use_ours: '<code>Use Ours</code>', use_theirs: '<code>Use Theirs</code>', branch_name: branch_name }
-
-%hr
-.resolve-conflicts-form
- .form-group.row
- .col-md-4
- %h4= _('Resolve conflicts on source branch')
- .resolve-info{ "v-pre": true }
- = translation.html_safe
- .col-md-8
- %label.label-bold{ "for" => "commit-message" }
- #{ _('Commit message') }
- .commit-message-container
- .max-width-marker
- %textarea.form-control.js-commit-message#commit-message{ "v-model" => "conflictsData.commitMessage", "rows" => "5" }
- .form-group.row
- .offset-md-4.col-md-8
- .row
- .col-6
- %button.btn.gl-button.btn-success.js-submit-button{ type: "button", "@click" => "commit()", ":disabled" => "!readyToCommit" }
- %span {{commitButtonText}}
- .col-6.text-right
- = link_to "Cancel", project_merge_request_path(@merge_request.project, @merge_request), class: "gl-button btn btn-default"
diff --git a/app/views/projects/merge_requests/conflicts/show.html.haml b/app/views/projects/merge_requests/conflicts/show.html.haml
index f1191bf220d..e02f126d165 100644
--- a/app/views/projects/merge_requests/conflicts/show.html.haml
+++ b/app/views/projects/merge_requests/conflicts/show.html.haml
@@ -1,5 +1,6 @@
- page_title _("Merge Conflicts"), "#{@merge_request.title} (#{@merge_request.to_reference}", _("Merge Requests")
- add_page_specific_style 'page_bundles/merge_conflicts'
+
= render "projects/merge_requests/mr_title"
.merge-request-details.issuable-details
@@ -7,30 +8,7 @@
= render 'shared/issuable/sidebar', issuable_sidebar: @issuable_sidebar, assignees: @merge_request.assignees, source_branch: @merge_request.source_branch
-#conflicts{ "v-cloak" => "true", data: { conflicts_path: conflicts_project_merge_request_path(@merge_request.project, @merge_request, format: :json),
- resolve_conflicts_path: resolve_conflicts_project_merge_request_path(@merge_request.project, @merge_request) } }
- .loading{ "v-if" => "isLoading" }
- .spinner.spinner-md
-
- .nothing-here-block{ "v-if" => "hasError" }
- {{conflictsData.errorMessage}}
-
- = render partial: "projects/merge_requests/conflicts/commit_stats"
-
- .files-wrapper{ "v-if" => "!isLoading && !hasError" }
- .files
- .diff-file.file-holder.conflict{ "v-for" => "file in conflictsData.files" }
- .js-file-title.file-title.file-title-flex-parent.cursor-default
- .file-header-content
- %file-icon{ ':file-name': 'file.filePath', ':size': '18', 'css-classes': 'gl-mr-2' }
- %strong.file-title-name {{file.filePath}}
- = render partial: 'projects/merge_requests/conflicts/file_actions'
- .diff-content.diff-wrap-lines
- .file-content{ "v-show" => "!isParallel && file.resolveMode === 'interactive' && file.type === 'text'" }
- %inline-conflict-lines{ ":file" => "file" }
- .file-content{ "v-show" => "isParallel && file.resolveMode === 'interactive' && file.type === 'text'" }
- %parallel-conflict-lines{ ":file" => "file" }
- %div{ "v-show" => "file.resolveMode === 'edit' || file.type === 'text-editor'" }
- %diff-file-editor{ ":file" => "file", ":on-cancel-discard-confirmation" => "cancelDiscardConfirmation", ":on-accept-discard-confirmation" => "acceptDiscardConfirmation" }
-
- = render partial: "projects/merge_requests/conflicts/submit_form"
+#conflicts{ data: { conflicts_path: conflicts_project_merge_request_path(@merge_request.project, @merge_request, format: :json),
+ resolve_conflicts_path: resolve_conflicts_project_merge_request_path(@merge_request.project, @merge_request),
+ source_branch_path: project_tree_path(@merge_request.project, @merge_request.source_branch),
+ merge_request_path: project_merge_request_path(@merge_request.project, @merge_request) } }
diff --git a/changelogs/unreleased/284116-sync-or-remove-single-file-mode-user-preference.yml b/changelogs/unreleased/284116-sync-or-remove-single-file-mode-user-preference.yml
new file mode 100644
index 00000000000..1eddb7ab59e
--- /dev/null
+++ b/changelogs/unreleased/284116-sync-or-remove-single-file-mode-user-preference.yml
@@ -0,0 +1,5 @@
+---
+title: Support "view_diffs_file_by_file" param in the Users create and update API
+merge_request: 54595
+author:
+type: added
diff --git a/changelogs/unreleased/x509-cert-loading.yml b/changelogs/unreleased/x509-cert-loading.yml
new file mode 100644
index 00000000000..76fa6907730
--- /dev/null
+++ b/changelogs/unreleased/x509-cert-loading.yml
@@ -0,0 +1,5 @@
+---
+title: Forcibly load OpenSSL::X509::DEFAULT_CERT_FILE
+merge_request: 54569
+author:
+type: fixed
diff --git a/doc/administration/pages/index.md b/doc/administration/pages/index.md
index 7ff7cc62e31..576441c37ca 100644
--- a/doc/administration/pages/index.md
+++ b/doc/administration/pages/index.md
@@ -217,56 +217,56 @@ and take effect after you [reconfigure GitLab](../restart_gitlab.md#omnibus-gitl
Most of these settings don't need to be configured manually unless you need more granular
control over how the Pages daemon runs and serves content in your environment.
-| Setting | Description |
-| ------- | ----------- |
-| `pages_external_url` | The URL where GitLab Pages is accessible, including protocol (HTTP / HTTPS). If `https://` is used, additional configuration is required. See [Wildcard domains with TLS support](#wildcard-domains-with-tls-support) and [Custom domains with TLS support](#custom-domains-with-tls-support) for details.
-| `gitlab_pages[]` | |
-| `access_control` | Whether to enable [access control](index.md#access-control).
-| `api_secret_key` | Full path to file with secret key used to authenticate with the GitLab API. Auto-generated when left unset.
-| `artifacts_server` | Enable viewing [artifacts](../job_artifacts.md) in GitLab Pages.
-| `artifacts_server_timeout` | Timeout (in seconds) for a proxied request to the artifacts server.
-| `artifacts_server_url` | API URL to proxy artifact requests to. Defaults to GitLab `external URL` + `/api/v4`, for example `https://gitlab.com/api/v4`. When running a [separate Pages server](#running-gitlab-pages-on-a-separate-server), this URL must point to the main GitLab server's API.
-| `auth_redirect_uri` | Callback URL for authenticating with GitLab. Defaults to project's subdomain of `pages_external_url` + `/auth`.
-| `auth_secret` | Secret key for signing authentication requests. Leave blank to pull automatically from GitLab during OAuth registration.
-| `dir` | Working directory for configuration and secrets files.
-| `enable` | Enable or disable GitLab Pages on the current system.
-| `external_http` | Configure Pages to bind to one or more secondary IP addresses, serving HTTP requests. Multiple addresses can be given as an array, along with exact ports, for example `['1.2.3.4', '1.2.3.5:8063']`. Sets value for `listen_http`.
-| `external_https` | Configure Pages to bind to one or more secondary IP addresses, serving HTTPS requests. Multiple addresses can be given as an array, along with exact ports, for example `['1.2.3.4', '1.2.3.5:8063']`. Sets value for `listen_https`.
-| `gitlab_client_http_timeout` | GitLab API HTTP client connection timeout in seconds (default: 10s).
-| `gitlab_client_jwt_expiry` | JWT Token expiry time in seconds (default: 30s).
-| `domain_config_source` | Domain configuration source (default: `auto`)
-| `gitlab_id` | The OAuth application public ID. Leave blank to automatically fill when Pages authenticates with GitLab.
-| `gitlab_secret` | The OAuth application secret. Leave blank to automatically fill when Pages authenticates with GitLab.
-| `auth_scope` | The OAuth application scope to use for authentication. Must match GitLab Pages OAuth application settings. Leave blank to use `api` scope by default.
-| `gitlab_server` | Server to use for authentication when access control is enabled; defaults to GitLab `external_url`.
-| `headers` | Specify any additional http headers that should be sent to the client with each response.
-| `inplace_chroot` | On [systems that don't support bind-mounts](index.md#additional-configuration-for-docker-container), this instructs GitLab Pages to `chroot` into its `pages_path` directory. Some caveats exist when using in-place `chroot`; refer to the GitLab Pages [README](https://gitlab.com/gitlab-org/gitlab-pages/blob/master/README.md#caveats) for more information.
-| `insecure_ciphers` | Use default list of cipher suites, may contain insecure ones like 3DES and RC4.
-| `internal_gitlab_server` | Internal GitLab server address used exclusively for API requests. Useful if you want to send that traffic over an internal load balancer. Defaults to GitLab `external_url`.
-| `listen_proxy` | The addresses to listen on for reverse-proxy requests. Pages binds to these addresses' network sockets and receives incoming requests from them. Sets the value of `proxy_pass` in `$nginx-dir/conf/gitlab-pages.conf`.
-| `log_directory` | Absolute path to a log directory.
-| `log_format` | The log output format: `text` or `json`.
-| `log_verbose` | Verbose logging, true/false.
-| `max_connections` | Limit on the number of concurrent connections to the HTTP, HTTPS or proxy listeners.
-| `metrics_address` | The address to listen on for metrics requests.
-| `redirect_http` | Redirect pages from HTTP to HTTPS, true/false.
-| `sentry_dsn` | The address for sending Sentry crash reporting to.
-| `sentry_enabled` | Enable reporting and logging with Sentry, true/false.
-| `sentry_environment` | The environment for Sentry crash reporting.
-| `status_uri` | The URL path for a status page, for example, `/@status`.
-| `tls_max_version` | Specifies the maximum SSL/TLS version ("ssl3", "tls1.0", "tls1.1" or "tls1.2").
-| `tls_min_version` | Specifies the minimum SSL/TLS version ("ssl3", "tls1.0", "tls1.1" or "tls1.2").
-| `use_http2` | Enable HTTP2 support.
-| `gitlab_pages['env'][]` | |
-| `http_proxy` | Configure GitLab Pages to use an HTTP Proxy to mediate traffic between Pages and GitLab. Sets an environment variable `http_proxy` when starting Pages daemon.
-| `gitlab_rails[]` | |
-| `pages_domain_verification_cron_worker` | Schedule for verifying custom GitLab Pages domains.
-| `pages_domain_ssl_renewal_cron_worker` | Schedule for obtaining and renewing SSL certificates through Let's Encrypt for GitLab Pages domains.
-| `pages_domain_removal_cron_worker` | Schedule for removing unverified custom GitLab Pages domains.
-| `pages_path` | The directory on disk where pages are stored, defaults to `GITLAB-RAILS/shared/pages`.
-| `pages_nginx[]` | |
-| `enable` | Include a virtual host `server{}` block for Pages inside NGINX. Needed for NGINX to proxy traffic back to the Pages daemon. Set to `false` if the Pages daemon should directly receive all requests, for example, when using [custom domains](index.md#custom-domains).
-| `FF_ENABLE_REDIRECTS` | Feature flag to disable redirects (enabled by default). Read the [redirects documentation](../../user/project/pages/redirects.md#disable-redirects) for more information. |
+| Setting | Description |
+|-----------------------------------------|-------------|
+| `pages_external_url` | The URL where GitLab Pages is accessible, including protocol (HTTP / HTTPS). If `https://` is used, additional configuration is required. See [Wildcard domains with TLS support](#wildcard-domains-with-tls-support) and [Custom domains with TLS support](#custom-domains-with-tls-support) for details. |
+| **`gitlab_pages[]`** | |
+| `access_control` | Whether to enable [access control](index.md#access-control). |
+| `api_secret_key` | Full path to file with secret key used to authenticate with the GitLab API. Auto-generated when left unset. |
+| `artifacts_server` | Enable viewing [artifacts](../job_artifacts.md) in GitLab Pages. |
+| `artifacts_server_timeout` | Timeout (in seconds) for a proxied request to the artifacts server. |
+| `artifacts_server_url` | API URL to proxy artifact requests to. Defaults to GitLab `external URL` + `/api/v4`, for example `https://gitlab.com/api/v4`. When running a [separate Pages server](#running-gitlab-pages-on-a-separate-server), this URL must point to the main GitLab server's API. |
+| `auth_redirect_uri` | Callback URL for authenticating with GitLab. Defaults to project's subdomain of `pages_external_url` + `/auth`. |
+| `auth_secret` | Secret key for signing authentication requests. Leave blank to pull automatically from GitLab during OAuth registration. |
+| `dir` | Working directory for configuration and secrets files. |
+| `enable` | Enable or disable GitLab Pages on the current system. |
+| `external_http` | Configure Pages to bind to one or more secondary IP addresses, serving HTTP requests. Multiple addresses can be given as an array, along with exact ports, for example `['1.2.3.4', '1.2.3.5:8063']`. Sets value for `listen_http`. |
+| `external_https` | Configure Pages to bind to one or more secondary IP addresses, serving HTTPS requests. Multiple addresses can be given as an array, along with exact ports, for example `['1.2.3.4', '1.2.3.5:8063']`. Sets value for `listen_https`. |
+| `gitlab_client_http_timeout` | GitLab API HTTP client connection timeout in seconds (default: 10s). |
+| `gitlab_client_jwt_expiry` | JWT Token expiry time in seconds (default: 30s). |
+| `domain_config_source` | Domain configuration source (default: `auto`) |
+| `gitlab_id` | The OAuth application public ID. Leave blank to automatically fill when Pages authenticates with GitLab. |
+| `gitlab_secret` | The OAuth application secret. Leave blank to automatically fill when Pages authenticates with GitLab. |
+| `auth_scope` | The OAuth application scope to use for authentication. Must match GitLab Pages OAuth application settings. Leave blank to use `api` scope by default. |
+| `gitlab_server` | Server to use for authentication when access control is enabled; defaults to GitLab `external_url`. |
+| `headers` | Specify any additional http headers that should be sent to the client with each response. |
+| `inplace_chroot` | On [systems that don't support bind-mounts](index.md#additional-configuration-for-docker-container), this instructs GitLab Pages to `chroot` into its `pages_path` directory. Some caveats exist when using in-place `chroot`; refer to the GitLab Pages [README](https://gitlab.com/gitlab-org/gitlab-pages/blob/master/README.md#caveats) for more information. |
+| `insecure_ciphers` | Use default list of cipher suites, may contain insecure ones like 3DES and RC4. |
+| `internal_gitlab_server` | Internal GitLab server address used exclusively for API requests. Useful if you want to send that traffic over an internal load balancer. Defaults to GitLab `external_url`. |
+| `listen_proxy` | The addresses to listen on for reverse-proxy requests. Pages binds to these addresses' network sockets and receives incoming requests from them. Sets the value of `proxy_pass` in `$nginx-dir/conf/gitlab-pages.conf`. |
+| `log_directory` | Absolute path to a log directory. |
+| `log_format` | The log output format: `text` or `json`. |
+| `log_verbose` | Verbose logging, true/false. |
+| `max_connections` | Limit on the number of concurrent connections to the HTTP, HTTPS or proxy listeners. |
+| `metrics_address` | The address to listen on for metrics requests. |
+| `redirect_http` | Redirect pages from HTTP to HTTPS, true/false. |
+| `sentry_dsn` | The address for sending Sentry crash reporting to. |
+| `sentry_enabled` | Enable reporting and logging with Sentry, true/false. |
+| `sentry_environment` | The environment for Sentry crash reporting. |
+| `status_uri` | The URL path for a status page, for example, `/@status`. |
+| `tls_max_version` | Specifies the maximum SSL/TLS version ("ssl3", "tls1.0", "tls1.1" or "tls1.2"). |
+| `tls_min_version` | Specifies the minimum SSL/TLS version ("ssl3", "tls1.0", "tls1.1" or "tls1.2"). |
+| `use_http2` | Enable HTTP2 support. |
+| **`gitlab_pages['env'][]`** | |
+| `http_proxy` | Configure GitLab Pages to use an HTTP Proxy to mediate traffic between Pages and GitLab. Sets an environment variable `http_proxy` when starting Pages daemon. |
+| **`gitlab_rails[]`** | |
+| `pages_domain_verification_cron_worker` | Schedule for verifying custom GitLab Pages domains. |
+| `pages_domain_ssl_renewal_cron_worker` | Schedule for obtaining and renewing SSL certificates through Let's Encrypt for GitLab Pages domains. |
+| `pages_domain_removal_cron_worker` | Schedule for removing unverified custom GitLab Pages domains. |
+| `pages_path` | The directory on disk where pages are stored, defaults to `GITLAB-RAILS/shared/pages`. |
+| **`pages_nginx[]`** | |
+| `enable` | Include a virtual host `server{}` block for Pages inside NGINX. Needed for NGINX to proxy traffic back to the Pages daemon. Set to `false` if the Pages daemon should directly receive all requests, for example, when using [custom domains](index.md#custom-domains). |
+| `FF_ENABLE_REDIRECTS` | Feature flag to disable redirects (enabled by default). Read the [redirects documentation](../../user/project/pages/redirects.md#disable-redirects) for more information. |
---
diff --git a/doc/administration/repository_storage_types.md b/doc/administration/repository_storage_types.md
index b08f661fd14..1cd33711556 100644
--- a/doc/administration/repository_storage_types.md
+++ b/doc/administration/repository_storage_types.md
@@ -125,57 +125,61 @@ The output includes the project ID and the project name. For example:
> [Introduced](https://gitlab.com/gitlab-org/gitaly/-/issues/1606) in GitLab 12.1.
-WARNING:
-Do not run `git prune` or `git gc` in pool repositories! This can
-cause data loss in "real" repositories that depend on the pool in
-question.
+Object pools are repositories used to deduplicate forks of public and internal projects and
+contain the objects from the source project. Using `objects/info/alternates`, the source project and
+forks use the object pool for shared objects. For more information, see
+[How Git object deduplication works in GitLab](../development/git_object_deduplication.md).
-Forks of public and internal projects are deduplicated by creating a third repository, the
-object pool, containing the objects from the source project. Using
-`objects/info/alternates`, the source project and forks use the object pool for
-shared objects. Objects are moved from the source project to the object pool
-when housekeeping is run on the source project.
+Objects are moved from the source project to the object pool when housekeeping is run on the source
+project. Object pool repositories are stored similarly to regular repositories:
```ruby
# object pool paths
"@pools/#{hash[0..1]}/#{hash[2..3]}/#{hash}.git"
```
-### Hashed storage coverage migration
-
-Files stored in an S3-compatible endpoint do not have the downsides
-mentioned earlier, if they are not prefixed with `#{namespace}/#{project_name}`.
-This is true for CI Cache and LFS Objects.
-
-In the table below, you can find the coverage of the migration to the hashed storage.
-
-| Storable Object | Legacy storage | Hashed storage | S3 Compatible | GitLab Version |
-| --------------- | -------------- | -------------- | ------------- | -------------- |
-| Repository | Yes | Yes | - | 10.0 |
-| Attachments | Yes | Yes | - | 10.2 |
-| Avatars | Yes | No | - | - |
-| Pages | Yes | No | - | - |
-| Docker Registry | Yes | No | - | - |
-| CI Build Logs | No | No | - | - |
-| CI Artifacts | No | No | Yes | 9.4 / 10.6 |
-| CI Cache | No | No | Yes | - |
-| LFS Objects | Yes | Similar | Yes | 10.0 / 10.7 |
-| Repository pools| No | Yes | - | 11.6 |
+WARNING:
+Do not run `git prune` or `git gc` in object pool repositories. This can cause data loss in the
+regular repositories that depend on the object pool.
+
+### Object storage support
+
+This table shows which storable objects are storable in each storage type:
+
+| Storable object | Legacy storage | Hashed storage | S3 compatible | GitLab version |
+|:-----------------|:---------------|:---------------|:--------------|:---------------|
+| Repository | Yes | Yes | - | 10.0 |
+| Attachments | Yes | Yes | - | 10.2 |
+| Avatars | Yes | No | - | - |
+| Pages | Yes | No | - | - |
+| Docker Registry | Yes | No | - | - |
+| CI/CD job logs | No | No | - | - |
+| CI/CD artifacts | No | No | Yes | 9.4 / 10.6 |
+| CI/CD cache | No | No | Yes | - |
+| LFS objects | Yes | Similar | Yes | 10.0 / 10.7 |
+| Repository pools | No | Yes | - | 11.6 |
+
+Files stored in an S3-compatible endpoint can have the same advantages as
+[hashed storage](#hashed-storage), as long as they are not prefixed with
+`#{namespace}/#{project_name}`. This is true for CI/CD cache and LFS objects.
#### Avatars
-Each file is stored in a folder with its `id` from the database. The filename is always `avatar.png` for user avatars.
-When avatar is replaced, `Upload` model is destroyed and a new one takes place with different `id`.
+Each file is stored in a directory that matches the `id` assigned to it in the database. The
+filename is always `avatar.png` for user avatars. When an avatar is replaced, the `Upload` model is
+destroyed and a new one takes place with a different `id`.
+
+#### CI/CD artifacts
-#### CI artifacts
+CI/CD artifacts are:
-CI Artifacts are S3 compatible since **9.4** (GitLab Premium), and available in GitLab Free since
-**10.6**.
+- S3-compatible since GitLab 9.4, initially available in [GitLab Premium](https://about.gitlab.com/pricing/).
+- Available in [GitLab Free](https://about.gitlab.com/pricing/) since GitLab 10.6.
#### LFS objects
[LFS Objects in GitLab](../topics/git/lfs/index.md) implement a similar
-storage pattern using 2 chars, 2 level folders, following Git's own implementation:
+storage pattern using two characters and two-level folders, following Git's own implementation:
```ruby
"shared/lfs-objects/#{oid[0..1}/#{oid[2..3]}/#{oid[4..-1]}"
@@ -184,40 +188,32 @@ storage pattern using 2 chars, 2 level folders, following Git's own implementati
"shared/lfs-objects/89/09/029eb962194cfb326259411b22ae3f4a814b5be4f80651735aeef9f3229c"
```
-LFS objects are also [S3 compatible](lfs/index.md#storing-lfs-objects-in-remote-object-storage).
+LFS objects are also [S3-compatible](lfs/index.md#storing-lfs-objects-in-remote-object-storage).
## Legacy storage
WARNING:
-In GitLab 13.0, hashed storage is enabled by default and the legacy storage is
-deprecated. If you haven't migrated yet, check the
-[migration instructions](raketasks/storage.md#migrate-to-hashed-storage).
-Support for legacy storage is scheduled to be removed in GitLab 14.0. If you're on GitLab
-13.0 and later, switching new projects to legacy storage is not possible.
-The option to choose between hashed and legacy storage in the admin area has
-been disabled.
-
-Legacy storage is the storage behavior prior to version 10.0. For historical
-reasons, GitLab replicated the same mapping structure from the projects URLs:
-
-- Project's repository: `#{namespace}/#{project_name}.git`
-- Project's wiki: `#{namespace}/#{project_name}.wiki.git`
-
-This structure enables you to migrate from existing solutions to GitLab, and
-for Administrators to find where the repository is stored.
-
-This approach also has some drawbacks:
-
-Storage location concentrates a huge number of top-level namespaces. The
-impact can be reduced by the introduction of
-[multiple storage paths](repository_storage_paths.md).
-
-Because backups are a snapshot of the same URL mapping, if you try to recover a
-very old backup, you need to verify whether any project has taken the place of
-an old removed or renamed project sharing the same URL. This means that
-`mygroup/myproject` from your backup may not be the same original project that
-is at that same URL today.
-
-Any change in the URL needs to be reflected on disk (when groups / users or
-projects are renamed). This can add a lot of load in big installations,
-especially if using any type of network based file system.
+In GitLab 13.0, legacy storage is deprecated. If you haven't migrated to hashed storage yet, check
+the [migration instructions](raketasks/storage.md#migrate-to-hashed-storage). Support for legacy
+storage is [scheduled to be removed](https://gitlab.com/gitlab-org/gitaly/-/issues/1690) in GitLab
+14.0. In GitLab 13.0 and later, switching new projects to legacy storage is not possible. The
+option to choose between hashed and legacy storage in the Admin Area is disabled.
+
+Legacy storage was the storage behavior prior to version GitLab 10.0. For historical reasons,
+GitLab replicated the same mapping structure from the projects URLs:
+
+- Project's repository: `#{namespace}/#{project_name}.git`.
+- Project's wiki: `#{namespace}/#{project_name}.wiki.git`.
+
+This structure enabled you to migrate from existing solutions to GitLab, and for Administrators to
+find where the repository was stored. This approach also had some drawbacks:
+
+- Storage location concentrated a large number of top-level namespaces. The impact could be
+ reduced by [multiple repository storage paths](repository_storage_paths.md).
+- Because backups were a snapshot of the same URL mapping, if you tried to recover a very old
+ backup, you needed to verify whether any project had taken the place of an old removed or renamed
+ project sharing the same URL. This meant that `mygroup/myproject` from your backup may not have
+ been the same original project that was at that same URL today.
+- Any change in the URL needed to be reflected on disk (when groups, users, or projects were
+ renamed. This could add a lot of load in big installations, especially if using any type of
+ network-based file system.
diff --git a/doc/administration/troubleshooting/elasticsearch.md b/doc/administration/troubleshooting/elasticsearch.md
index 0f60c43ef9e..6baa9c2ed7b 100644
--- a/doc/administration/troubleshooting/elasticsearch.md
+++ b/doc/administration/troubleshooting/elasticsearch.md
@@ -294,7 +294,7 @@ Beyond that, you will want to review the error. If it is:
GitLab support.
- An OS issue, you will want to reach out to your systems administrator.
- A `Faraday::TimeoutError (execution expired)` error **and** you're using a proxy,
- [set a custom `gitlab_rails['env']` environment variable, called `no_proxy`](https://docs.gitlab.com/omnibus/settings/environment-variables.html)
+ [set a custom `gitlab_rails['env']` environment variable, called `no_proxy`](https://docs.gitlab.com/omnibus/settings/environment-variables.html)
with the IP address of your Elasticsearch host.
### Troubleshooting performance
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index b1fa37e4d06..aba9825efc5 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -5021,9 +5021,9 @@ Types of blob viewers.
| Value | Description |
| ----- | ----------- |
-| `auxiliary` | |
-| `rich` | |
-| `simple` | |
+| `auxiliary` | Auxiliary blob viewers type. |
+| `rich` | Rich blob viewers type. |
+| `simple` | Simple blob viewers type. |
### CiConfigStatus
diff --git a/doc/api/settings.md b/doc/api/settings.md
index 53cb1335a54..4d1b66f40ab 100644
--- a/doc/api/settings.md
+++ b/doc/api/settings.md
@@ -335,7 +335,7 @@ listed in the descriptions of the relevant settings.
| `polling_interval_multiplier` | decimal | no | Interval multiplier used by endpoints that perform polling. Set to `0` to disable polling. |
| `project_export_enabled` | boolean | no | Enable project export. |
| `prometheus_metrics_enabled` | boolean | no | Enable Prometheus metrics. |
-| `protected_ci_variables` | boolean | no | Environment variables are protected by default. |
+| `protected_ci_variables` | boolean | no | CI/CD variables are protected by default. |
| `pseudonymizer_enabled` | boolean | no | **(PREMIUM)** When enabled, GitLab runs a background job that produces pseudonymized CSVs of the GitLab database to upload to your configured object storage directory.
| `push_event_activities_limit` | integer | no | Number of changes (branches or tags) in a single push to determine whether individual push events or bulk push events are created. [Bulk push events are created](../user/admin_area/settings/push_event_activities_limit.md) if it surpasses that value. |
| `push_event_hooks_limit` | integer | no | Number of changes (branches or tags) in a single push to determine whether webhooks and services fire or not. Webhooks and services aren't submitted if it surpasses that value. |
diff --git a/doc/api/users.md b/doc/api/users.md
index 5b966d6ba87..b8917f3e215 100644
--- a/doc/api/users.md
+++ b/doc/api/users.md
@@ -448,6 +448,7 @@ Parameters:
| `theme_id` | No | The GitLab theme for the user (see [the user preference docs](../user/profile/preferences.md#navigation-theme) for more information) |
| `twitter` | No | Twitter account |
| `username` | Yes | Username |
+| `view_diffs_file_by_file` | No | Flag indicating the user sees only one file diff per page |
| `website_url` | No | Website URL |
## User modification
@@ -489,6 +490,7 @@ Parameters:
| `theme_id` | No | The GitLab theme for the user (see [the user preference docs](../user/profile/preferences.md#navigation-theme) for more information) |
| `twitter` | No | Twitter account |
| `username` | No | Username |
+| `view_diffs_file_by_file` | No | Flag indicating the user sees only one file diff per page |
| `website_url` | No | Website URL |
On password update, the user is forced to change it upon next login.
diff --git a/doc/development/git_object_deduplication.md b/doc/development/git_object_deduplication.md
index 00993cc2932..d9ff88aef60 100644
--- a/doc/development/git_object_deduplication.md
+++ b/doc/development/git_object_deduplication.md
@@ -1,7 +1,8 @@
---
-stage: none
-group: unassigned
+stage: Create
+group: Gitaly
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
+type: reference
---
# How Git object deduplication works in GitLab
diff --git a/doc/user/project/merge_requests/browser_performance_testing.md b/doc/user/project/merge_requests/browser_performance_testing.md
index f6575ba4173..7a869ed071a 100644
--- a/doc/user/project/merge_requests/browser_performance_testing.md
+++ b/doc/user/project/merge_requests/browser_performance_testing.md
@@ -93,7 +93,7 @@ that you can later download and analyze. This implementation always takes the la
Browser Performance artifact available. If [GitLab Pages](../pages/index.md) is enabled,
you can view the report directly in your browser.
-You can also customize the jobs with environment variables:
+You can also customize the jobs with CI/CD variables:
- `SITESPEED_IMAGE`: Configure the Docker image to use for the job (default `sitespeedio/sitespeed.io`), but not the image version.
- `SITESPEED_VERSION`: Configure the version of the Docker image to use for the job (default `14.1.0`).
@@ -118,7 +118,7 @@ performance:
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/27599) in GitLab 13.0.
You can configure the sensitivity of degradation alerts to avoid getting alerts for minor drops in metrics.
-This is done by setting the `DEGRADATION_THRESHOLD` variable. In the example below, the alert only shows up
+This is done by setting the `DEGRADATION_THRESHOLD` CI/CD variable. In the example below, the alert only shows up
if the `Total Score` metric degrades by 5 points or more:
```yaml
@@ -189,7 +189,7 @@ GitLab version:
- In GitLab 12.4 [a job template was made available](https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Verify/Browser-Performance.gitlab-ci.yml).
- In 13.2 the feature was renamed from `Performance` to `Browser Performance` with
-additional template variables. The job name in the template is still `performance`
+additional template CI/CD variables. The job name in the template is still `performance`
for compatibility reasons, but may be renamed to match in a future iteration.
- For 11.5 to 12.3 no template is available and the job has to be defined manually as follows:
diff --git a/doc/user/project/merge_requests/code_quality.md b/doc/user/project/merge_requests/code_quality.md
index 451561cc22f..e80961464ba 100644
--- a/doc/user/project/merge_requests/code_quality.md
+++ b/doc/user/project/merge_requests/code_quality.md
@@ -89,7 +89,7 @@ scans your source code for code quality issues. The report is saved as a
that you can later download and analyze.
It's also possible to override the URL to the Code Quality image by
-setting the `CODE_QUALITY_IMAGE` variable. This is particularly useful if you want
+setting the `CODE_QUALITY_IMAGE` CI/CD variable. This is particularly useful if you want
to lock in a specific version of Code Quality, or use a fork of it:
```yaml
@@ -235,12 +235,12 @@ was chosen as an operational decision by the runner team, instead of exposing `d
### Disabling the code quality job
-The `code_quality` job doesn't run if the `$CODE_QUALITY_DISABLED` environment
-variable is present. Please refer to the environment variables [documentation](../../../ci/variables/README.md)
+The `code_quality` job doesn't run if the `$CODE_QUALITY_DISABLED` CI/CD variable
+is present. Please refer to the CI/CD variables [documentation](../../../ci/variables/README.md)
to learn more about how to define one.
-To disable the `code_quality` job, add `CODE_QUALITY_DISABLED` as a custom environment
-variable. This can be done:
+To disable the `code_quality` job, add `CODE_QUALITY_DISABLED` as a custom CI/CD variable.
+This can be done:
- For the whole project, [in the project settings](../../../ci/variables/README.md#create-a-custom-variable-in-the-ui)
or [CI/CD configuration](../../../ci/variables/README.md#create-a-custom-variable-in-the-ui).
@@ -364,7 +364,7 @@ After the Code Quality job completes:
In [GitLab 13.6 and later](https://gitlab.com/gitlab-org/ci-cd/codequality/-/issues/10),
it is possible to generate an HTML report file by setting the `REPORT_FORMAT`
-variable to `html`. This is useful if you just want to view the report in a more
+CI/CD variable to `html`. This is useful if you just want to view the report in a more
human-readable format or to publish this artifact on GitLab Pages for even
easier reviewing.
diff --git a/doc/user/project/merge_requests/load_performance_testing.md b/doc/user/project/merge_requests/load_performance_testing.md
index 9154897d42d..e8062fadcfe 100644
--- a/doc/user/project/merge_requests/load_performance_testing.md
+++ b/doc/user/project/merge_requests/load_performance_testing.md
@@ -104,8 +104,8 @@ An example configuration workflow:
1. Set up GitLab Runner to run Docker containers, like the
[Docker-in-Docker workflow](../../../ci/docker/using_docker_build.md#use-the-docker-executor-with-the-docker-image-docker-in-docker).
-1. Configure the default Load Performance Testing CI job in your `.gitlab-ci.yml` file.
- You need to include the template and configure it with variables:
+1. Configure the default Load Performance Testing CI/CD job in your `.gitlab-ci.yml` file.
+ You need to include the template and configure it with CI/CD variables:
```yaml
include:
@@ -153,7 +153,7 @@ but it can be extended to work with [review apps](../../../ci/review_apps) or
[dynamic environments](../../../ci/environments) with a few extra steps.
The best approach is to capture the dynamic URL in a [`.env` file](https://docs.docker.com/compose/env-file/)
-as a job artifact to be shared, then use a custom environment variable we've provided named `K6_DOCKER_OPTIONS`
+as a job artifact to be shared, then use a custom CI/CD variable we've provided named `K6_DOCKER_OPTIONS`
to configure the k6 Docker container to use the file. With this, k6 can then use any
environment variables from the `.env` file in scripts using standard JavaScript,
such as: ``http.get(`${__ENV.ENVIRONMENT_URL}`)``.
diff --git a/lib/api/users.rb b/lib/api/users.rb
index 9b394ad1cfd..b2f99bb18dc 100644
--- a/lib/api/users.rb
+++ b/lib/api/users.rb
@@ -58,6 +58,7 @@ module API
optional :color_scheme_id, type: Integer, desc: 'The color scheme for the file viewer'
optional :private_profile, type: Boolean, desc: 'Flag indicating the user has a private profile'
optional :note, type: String, desc: 'Admin note for this user'
+ optional :view_diffs_file_by_file, type: Boolean, desc: 'Flag indicating the user sees only one file diff per page'
all_or_none_of :extern_uid, :provider
use :optional_params_ee
diff --git a/lib/gitlab/x509/signature.rb b/lib/gitlab/x509/signature.rb
index 7d4d4d9d13a..edff1540cb3 100644
--- a/lib/gitlab/x509/signature.rb
+++ b/lib/gitlab/x509/signature.rb
@@ -52,6 +52,12 @@ module Gitlab
strong_memoize(:cert_store) do
store = OpenSSL::X509::Store.new
store.set_default_paths
+
+ if Feature.enabled?(:x509_forced_cert_loading, type: :ops)
+ # Forcibly load the default cert file because the OpenSSL library seemingly ignores it
+ store.add_file(OpenSSL::X509::DEFAULT_CERT_FILE) if File.exist?(OpenSSL::X509::DEFAULT_CERT_FILE)
+ end
+
# valid_signing_time? checks the time attributes already
# this flag is required, otherwise expired certificates would become
# unverified when notAfter within certificate attribute is reached
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index e73a8f3ed0c..92ee07da74c 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -27387,7 +27387,7 @@ msgid_plural "Showing %d events"
msgstr[0] ""
msgstr[1] ""
-msgid "Showing %{conflict_start}%{conflicts_text}%{strong_end} between %{ref_start}%{source_branch}%{strong_end} and %{ref_start}%{target_branch}%{strong_end}"
+msgid "Showing %{conflict} between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "Showing %{count} of %{total} projects"
@@ -32776,9 +32776,6 @@ msgstr ""
msgid "View file @ %{commitSha}"
msgstr ""
-msgid "View file @%{commit_sha}"
-msgstr ""
-
msgid "View full dashboard"
msgstr ""
diff --git a/spec/frontend/boards/issue_card_inner_spec.js b/spec/frontend/boards/board_card_inner_spec.js
index b9f84fed6b3..ae5bbfd825f 100644
--- a/spec/frontend/boards/issue_card_inner_spec.js
+++ b/spec/frontend/boards/board_card_inner_spec.js
@@ -1,7 +1,7 @@
import { GlLabel } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
import { range } from 'lodash';
-import IssueCardInner from '~/boards/components/issue_card_inner.vue';
+import BoardCardInner from '~/boards/components/board_card_inner.vue';
import eventHub from '~/boards/eventhub';
import defaultStore from '~/boards/stores';
import { updateHistory } from '~/lib/utils/url_utility';
@@ -10,7 +10,7 @@ import { mockLabelList } from './mock_data';
jest.mock('~/lib/utils/url_utility');
jest.mock('~/boards/eventhub');
-describe('Issue card component', () => {
+describe('Board card component', () => {
const user = {
id: 1,
name: 'testing 123',
@@ -31,11 +31,11 @@ describe('Issue card component', () => {
let list;
const createWrapper = (props = {}, store = defaultStore) => {
- wrapper = mount(IssueCardInner, {
+ wrapper = mount(BoardCardInner, {
store,
propsData: {
list,
- issue,
+ item: issue,
...props,
},
stubs: {
@@ -63,7 +63,7 @@ describe('Issue card component', () => {
weight: 1,
};
- createWrapper({ issue, list });
+ createWrapper({ item: issue, list });
});
afterEach(() => {
@@ -103,8 +103,8 @@ describe('Issue card component', () => {
describe('confidential issue', () => {
beforeEach(() => {
wrapper.setProps({
- issue: {
- ...wrapper.props('issue'),
+ item: {
+ ...wrapper.props('item'),
confidential: true,
},
});
@@ -119,8 +119,8 @@ describe('Issue card component', () => {
describe('with avatar', () => {
beforeEach(() => {
wrapper.setProps({
- issue: {
- ...wrapper.props('issue'),
+ item: {
+ ...wrapper.props('item'),
assignees: [user],
updateData(newData) {
Object.assign(this, newData);
@@ -146,8 +146,8 @@ describe('Issue card component', () => {
});
it('renders the avatar using avatarUrl property', async () => {
- wrapper.props('issue').updateData({
- ...wrapper.props('issue'),
+ wrapper.props('item').updateData({
+ ...wrapper.props('item'),
assignees: [
{
id: '1',
@@ -172,8 +172,8 @@ describe('Issue card component', () => {
global.gon.default_avatar_url = 'default_avatar';
wrapper.setProps({
- issue: {
- ...wrapper.props('issue'),
+ item: {
+ ...wrapper.props('item'),
assignees: [
{
id: 1,
@@ -201,8 +201,8 @@ describe('Issue card component', () => {
describe('multiple assignees', () => {
beforeEach(() => {
wrapper.setProps({
- issue: {
- ...wrapper.props('issue'),
+ item: {
+ ...wrapper.props('item'),
assignees: [
{
id: 2,
@@ -233,7 +233,7 @@ describe('Issue card component', () => {
describe('more than three assignees', () => {
beforeEach(() => {
- const { assignees } = wrapper.props('issue');
+ const { assignees } = wrapper.props('item');
assignees.push({
id: 5,
name: 'user5',
@@ -242,8 +242,8 @@ describe('Issue card component', () => {
});
wrapper.setProps({
- issue: {
- ...wrapper.props('issue'),
+ item: {
+ ...wrapper.props('item'),
assignees,
},
});
@@ -259,7 +259,7 @@ describe('Issue card component', () => {
it('renders 99+ avatar counter', async () => {
const assignees = [
- ...wrapper.props('issue').assignees,
+ ...wrapper.props('item').assignees,
...range(5, 103).map((i) => ({
id: i,
name: 'name',
@@ -268,8 +268,8 @@ describe('Issue card component', () => {
})),
];
wrapper.setProps({
- issue: {
- ...wrapper.props('issue'),
+ item: {
+ ...wrapper.props('item'),
assignees,
},
});
@@ -283,7 +283,7 @@ describe('Issue card component', () => {
describe('labels', () => {
beforeEach(() => {
- wrapper.setProps({ issue: { ...issue, labels: [list.label, label1] } });
+ wrapper.setProps({ item: { ...issue, labels: [list.label, label1] } });
});
it('does not render list label but renders all other labels', () => {
@@ -295,7 +295,7 @@ describe('Issue card component', () => {
});
it('does not render label if label does not have an ID', async () => {
- wrapper.setProps({ issue: { ...issue, labels: [label1, { title: 'closed' }] } });
+ wrapper.setProps({ item: { ...issue, labels: [label1, { title: 'closed' }] } });
await wrapper.vm.$nextTick();
@@ -307,8 +307,8 @@ describe('Issue card component', () => {
describe('blocked', () => {
beforeEach(() => {
wrapper.setProps({
- issue: {
- ...wrapper.props('issue'),
+ item: {
+ ...wrapper.props('item'),
blocked: true,
},
});
diff --git a/spec/frontend/boards/components/board_card_deprecated_spec.js b/spec/frontend/boards/components/board_card_deprecated_spec.js
index 6be84f6f111..266cbc7106d 100644
--- a/spec/frontend/boards/components/board_card_deprecated_spec.js
+++ b/spec/frontend/boards/components/board_card_deprecated_spec.js
@@ -7,7 +7,7 @@ import { mount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
import waitForPromises from 'helpers/wait_for_promises';
import BoardCardDeprecated from '~/boards/components/board_card_deprecated.vue';
-import issueCardInner from '~/boards/components/issue_card_inner.vue';
+import issueCardInner from '~/boards/components/issue_card_inner_deprecated.vue';
import eventHub from '~/boards/eventhub';
import store from '~/boards/stores';
import boardsStore from '~/boards/stores/boards_store';
diff --git a/spec/frontend/boards/components/board_card_layout_deprecated_spec.js b/spec/frontend/boards/components/board_card_layout_deprecated_spec.js
index 426c5289ba6..9853c9f434f 100644
--- a/spec/frontend/boards/components/board_card_layout_deprecated_spec.js
+++ b/spec/frontend/boards/components/board_card_layout_deprecated_spec.js
@@ -11,7 +11,7 @@ import '~/boards/models/label';
import '~/boards/models/assignee';
import '~/boards/models/list';
import BoardCardLayout from '~/boards/components/board_card_layout_deprecated.vue';
-import issueCardInner from '~/boards/components/issue_card_inner.vue';
+import issueCardInner from '~/boards/components/issue_card_inner_deprecated.vue';
import { ISSUABLE } from '~/boards/constants';
import boardsVuexStore from '~/boards/stores';
import boardsStore from '~/boards/stores/boards_store';
diff --git a/spec/frontend/boards/components/board_card_spec.js b/spec/frontend/boards/components/board_card_spec.js
index d68e0f9fc23..a1d7a7de2fd 100644
--- a/spec/frontend/boards/components/board_card_spec.js
+++ b/spec/frontend/boards/components/board_card_spec.js
@@ -2,7 +2,7 @@ import { createLocalVue, shallowMount } from '@vue/test-utils';
import Vuex from 'vuex';
import BoardCard from '~/boards/components/board_card.vue';
-import IssueCardInner from '~/boards/components/issue_card_inner.vue';
+import BoardCardInner from '~/boards/components/board_card_inner.vue';
import { inactiveId } from '~/boards/constants';
import { mockLabelList, mockIssue } from '../mock_data';
@@ -38,7 +38,7 @@ describe('Board card layout', () => {
wrapper = shallowMount(BoardCard, {
localVue,
stubs: {
- IssueCardInner,
+ BoardCardInner,
},
store,
propsData: {
diff --git a/spec/lib/gitlab/x509/signature_spec.rb b/spec/lib/gitlab/x509/signature_spec.rb
index ac6f7e49fe0..2ac9c1f3a3b 100644
--- a/spec/lib/gitlab/x509/signature_spec.rb
+++ b/spec/lib/gitlab/x509/signature_spec.rb
@@ -11,6 +11,65 @@ RSpec.describe Gitlab::X509::Signature do
}
end
+ shared_examples "a verified signature" do
+ it 'returns a verified signature if email does match' do
+ signature = described_class.new(
+ X509Helpers::User1.signed_commit_signature,
+ X509Helpers::User1.signed_commit_base_data,
+ X509Helpers::User1.certificate_email,
+ X509Helpers::User1.signed_commit_time
+ )
+
+ expect(signature.x509_certificate).to have_attributes(certificate_attributes)
+ expect(signature.x509_certificate.x509_issuer).to have_attributes(issuer_attributes)
+ expect(signature.verified_signature).to be_truthy
+ expect(signature.verification_status).to eq(:verified)
+ end
+
+ it 'returns an unverified signature if email does not match' do
+ signature = described_class.new(
+ X509Helpers::User1.signed_commit_signature,
+ X509Helpers::User1.signed_commit_base_data,
+ "gitlab@example.com",
+ X509Helpers::User1.signed_commit_time
+ )
+
+ expect(signature.x509_certificate).to have_attributes(certificate_attributes)
+ expect(signature.x509_certificate.x509_issuer).to have_attributes(issuer_attributes)
+ expect(signature.verified_signature).to be_truthy
+ expect(signature.verification_status).to eq(:unverified)
+ end
+
+ it 'returns an unverified signature if email does match and time is wrong' do
+ signature = described_class.new(
+ X509Helpers::User1.signed_commit_signature,
+ X509Helpers::User1.signed_commit_base_data,
+ X509Helpers::User1.certificate_email,
+ Time.new(2020, 2, 22)
+ )
+
+ expect(signature.x509_certificate).to have_attributes(certificate_attributes)
+ expect(signature.x509_certificate.x509_issuer).to have_attributes(issuer_attributes)
+ expect(signature.verified_signature).to be_falsey
+ expect(signature.verification_status).to eq(:unverified)
+ end
+
+ it 'returns an unverified signature if certificate is revoked' do
+ signature = described_class.new(
+ X509Helpers::User1.signed_commit_signature,
+ X509Helpers::User1.signed_commit_base_data,
+ X509Helpers::User1.certificate_email,
+ X509Helpers::User1.signed_commit_time
+ )
+
+ expect(signature.verification_status).to eq(:verified)
+
+ signature.x509_certificate.revoked!
+
+ expect(signature.verification_status).to eq(:unverified)
+ end
+ end
+
context 'commit signature' do
let(:certificate_attributes) do
{
@@ -30,62 +89,25 @@ RSpec.describe Gitlab::X509::Signature do
allow(OpenSSL::X509::Store).to receive(:new).and_return(store)
end
- it 'returns a verified signature if email does match' do
- signature = described_class.new(
- X509Helpers::User1.signed_commit_signature,
- X509Helpers::User1.signed_commit_base_data,
- X509Helpers::User1.certificate_email,
- X509Helpers::User1.signed_commit_time
- )
-
- expect(signature.x509_certificate).to have_attributes(certificate_attributes)
- expect(signature.x509_certificate.x509_issuer).to have_attributes(issuer_attributes)
- expect(signature.verified_signature).to be_truthy
- expect(signature.verification_status).to eq(:verified)
- end
+ it_behaves_like "a verified signature"
+ end
- it 'returns an unverified signature if email does not match' do
- signature = described_class.new(
- X509Helpers::User1.signed_commit_signature,
- X509Helpers::User1.signed_commit_base_data,
- "gitlab@example.com",
- X509Helpers::User1.signed_commit_time
- )
+ context 'with the certificate defined by OpenSSL::X509::DEFAULT_CERT_FILE' do
+ before do
+ store = OpenSSL::X509::Store.new
+ certificate = OpenSSL::X509::Certificate.new(X509Helpers::User1.trust_cert)
+ file_path = Rails.root.join("tmp/cert.pem").to_s
- expect(signature.x509_certificate).to have_attributes(certificate_attributes)
- expect(signature.x509_certificate.x509_issuer).to have_attributes(issuer_attributes)
- expect(signature.verified_signature).to be_truthy
- expect(signature.verification_status).to eq(:unverified)
- end
+ File.open(file_path, "wb") do |f|
+ f.print certificate.to_pem
+ end
- it 'returns an unverified signature if email does match and time is wrong' do
- signature = described_class.new(
- X509Helpers::User1.signed_commit_signature,
- X509Helpers::User1.signed_commit_base_data,
- X509Helpers::User1.certificate_email,
- Time.new(2020, 2, 22)
- )
+ stub_const("OpenSSL::X509::DEFAULT_CERT_FILE", file_path)
- expect(signature.x509_certificate).to have_attributes(certificate_attributes)
- expect(signature.x509_certificate.x509_issuer).to have_attributes(issuer_attributes)
- expect(signature.verified_signature).to be_falsey
- expect(signature.verification_status).to eq(:unverified)
+ allow(OpenSSL::X509::Store).to receive(:new).and_return(store)
end
- it 'returns an unverified signature if certificate is revoked' do
- signature = described_class.new(
- X509Helpers::User1.signed_commit_signature,
- X509Helpers::User1.signed_commit_base_data,
- X509Helpers::User1.certificate_email,
- X509Helpers::User1.signed_commit_time
- )
-
- expect(signature.verification_status).to eq(:verified)
-
- signature.x509_certificate.revoked!
-
- expect(signature.verification_status).to eq(:unverified)
- end
+ it_behaves_like "a verified signature"
end
context 'without trusted certificate within store' do
diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb
index 4a7232d6316..2a7689eaddf 100644
--- a/spec/requests/api/users_spec.rb
+++ b/spec/requests/api/users_spec.rb
@@ -952,6 +952,18 @@ RSpec.describe API::Users do
expect(new_user.private_profile?).to eq(true)
end
+ it "creates user with view_diffs_file_by_file" do
+ post api('/users', admin), params: attributes_for(:user, view_diffs_file_by_file: true)
+
+ expect(response).to have_gitlab_http_status(:created)
+
+ user_id = json_response['id']
+ new_user = User.find(user_id)
+
+ expect(new_user).not_to eq(nil)
+ expect(new_user.user_preference.view_diffs_file_by_file?).to eq(true)
+ end
+
it "does not create user with invalid email" do
post api('/users', admin),
params: {
@@ -1266,6 +1278,13 @@ RSpec.describe API::Users do
expect(user.reload.private_profile).to eq(true)
end
+ it "updates viewing diffs file by file" do
+ put api("/users/#{user.id}", admin), params: { view_diffs_file_by_file: true }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(user.reload.user_preference.view_diffs_file_by_file?).to eq(true)
+ end
+
it "updates private profile to false when nil is given" do
user.update!(private_profile: true)