Commit dc889678 authored by GitLab Bot's avatar GitLab Bot

Add latest changes from gitlab-org/gitlab@master

parent cd52759e
...@@ -80,6 +80,9 @@ ...@@ -80,6 +80,9 @@
- "{,ee/}{app,bin,config,db,haml_lint,lib,locale,public,scripts,symbol,vendor}/**/*" - "{,ee/}{app,bin,config,db,haml_lint,lib,locale,public,scripts,symbol,vendor}/**/*"
- "doc/api/graphql/reference/*" # Files in this folder are auto-generated - "doc/api/graphql/reference/*" # Files in this folder are auto-generated
.frontend-dependency-patterns: &frontend-dependency-patterns
- "{package.json,yarn.lock}"
.qa-patterns: &qa-patterns .qa-patterns: &qa-patterns
- ".dockerignore" - ".dockerignore"
- "qa/**/*" - "qa/**/*"
...@@ -270,6 +273,9 @@ ...@@ -270,6 +273,9 @@
rules: rules:
- <<: *if-master-refs - <<: *if-master-refs
when: on_success when: on_success
- <<: *if-merge-request
changes: *frontend-dependency-patterns
when: on_success
################ ################
# Memory rules # # Memory rules #
......
<script> <script>
import { Sortable, MultiDrag } from 'sortablejs'; import { Sortable, MultiDrag } from 'sortablejs';
import { GlLoadingIcon } from '@gitlab/ui'; import { GlLoadingIcon } from '@gitlab/ui';
import _ from 'underscore';
import boardNewIssue from './board_new_issue.vue'; import boardNewIssue from './board_new_issue.vue';
import boardCard from './board_card.vue'; import boardCard from './board_card.vue';
import eventHub from '../eventhub'; import eventHub from '../eventhub';
...@@ -266,11 +265,12 @@ export default { ...@@ -266,11 +265,12 @@ export default {
* same list or the other list. Don't remove items if it's same list. * same list or the other list. Don't remove items if it's same list.
*/ */
const isSameList = toList && toList.id === this.list.id; const isSameList = toList && toList.id === this.list.id;
if (toList && !isSameList && boardsStore.shouldRemoveIssue(this.list, toList)) { if (toList && !isSameList && boardsStore.shouldRemoveIssue(this.list, toList)) {
const issues = items.map(item => this.list.findIssue(Number(item.dataset.issueId))); const issues = items.map(item => this.list.findIssue(Number(item.dataset.issueId)));
if (
if (_.compact(issues).length && !boardsStore.issuesAreContiguous(this.list, issues)) { issues.filter(Boolean).length &&
!boardsStore.issuesAreContiguous(this.list, issues)
) {
const indexes = []; const indexes = [];
const ids = this.list.issues.map(i => i.id); const ids = this.list.issues.map(i => i.id);
issues.forEach(issue => { issues.forEach(issue => {
......
<script> <script>
import { throttle } from 'underscore'; import { throttle } from 'lodash';
import { import {
GlLoadingIcon, GlLoadingIcon,
GlSearchBoxByType, GlSearchBoxByType,
......
<script> <script>
import _ from 'underscore'; import { sortBy } from 'lodash';
import { mapState } from 'vuex'; import { mapState } from 'vuex';
import { GlLabel, GlTooltipDirective } from '@gitlab/ui'; import { GlLabel, GlTooltipDirective } from '@gitlab/ui';
import issueCardInner from 'ee_else_ce/boards/mixins/issue_card_inner'; import issueCardInner from 'ee_else_ce/boards/mixins/issue_card_inner';
...@@ -100,10 +100,7 @@ export default { ...@@ -100,10 +100,7 @@ export default {
return !groupId ? referencePath.split('#')[0] : null; return !groupId ? referencePath.split('#')[0] : null;
}, },
orderedLabels() { orderedLabels() {
return _.chain(this.issue.labels) return sortBy(this.issue.labels.filter(this.isNonListLabel), 'title');
.filter(this.isNonListLabel)
.sortBy('title')
.value();
}, },
helpLink() { helpLink() {
return boardsStore.scopedLabels.helpLink; return boardsStore.scopedLabels.helpLink;
......
<script> <script>
import $ from 'jquery'; import $ from 'jquery';
import _ from 'underscore'; import { escape } from 'lodash';
import { GlLoadingIcon } from '@gitlab/ui'; import { GlLoadingIcon } from '@gitlab/ui';
import Icon from '~/vue_shared/components/icon.vue'; import Icon from '~/vue_shared/components/icon.vue';
import { __ } from '~/locale'; import { __ } from '~/locale';
...@@ -83,7 +83,7 @@ export default { ...@@ -83,7 +83,7 @@ export default {
}" data-project-name="${project.name}" data-project-name-with-namespace="${ }" data-project-name="${project.name}" data-project-name-with-namespace="${
project.name_with_namespace project.name_with_namespace
}"> }">
${_.escape(project.name_with_namespace)} ${escape(project.name_with_namespace)}
</a> </a>
</li> </li>
`; `;
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
/* global List */ /* global List */
import $ from 'jquery'; import $ from 'jquery';
import _ from 'underscore'; import { sortBy } from 'lodash';
import Vue from 'vue'; import Vue from 'vue';
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
import BoardsStoreEE from 'ee_else_ce/boards/stores/boards_store_ee'; import BoardsStoreEE from 'ee_else_ce/boards/stores/boards_store_ee';
...@@ -76,8 +76,7 @@ const boardsStore = { ...@@ -76,8 +76,7 @@ const boardsStore = {
}, },
addList(listObj) { addList(listObj) {
const list = new List(listObj); const list = new List(listObj);
this.state.lists = _.sortBy([...this.state.lists, list], 'position'); this.state.lists = sortBy([...this.state.lists, list], 'position');
return list; return list;
}, },
new(listObj) { new(listObj) {
...@@ -90,7 +89,7 @@ const boardsStore = { ...@@ -90,7 +89,7 @@ const boardsStore = {
// Remove any new issues from the backlog // Remove any new issues from the backlog
// as they will be visible in the new list // as they will be visible in the new list
list.issues.forEach(backlogList.removeIssue.bind(backlogList)); list.issues.forEach(backlogList.removeIssue.bind(backlogList));
this.state.lists = _.sortBy(this.state.lists, 'position'); this.state.lists = sortBy(this.state.lists, 'position');
}) })
.catch(() => { .catch(() => {
// https://gitlab.com/gitlab-org/gitlab-foss/issues/30821 // https://gitlab.com/gitlab-org/gitlab-foss/issues/30821
...@@ -194,10 +193,9 @@ const boardsStore = { ...@@ -194,10 +193,9 @@ const boardsStore = {
moveMultipleIssuesToList({ listFrom, listTo, issues, newIndex }) { moveMultipleIssuesToList({ listFrom, listTo, issues, newIndex }) {
const issueTo = issues.map(issue => listTo.findIssue(issue.id)); const issueTo = issues.map(issue => listTo.findIssue(issue.id));
const issueLists = _.flatten(issues.map(issue => issue.getLists())); const issueLists = issues.map(issue => issue.getLists()).flat();
const listLabels = issueLists.map(list => list.label); const listLabels = issueLists.map(list => list.label);
const hasMoveableIssues = issueTo.filter(Boolean).length > 0;
const hasMoveableIssues = _.compact(issueTo).length > 0;
if (!hasMoveableIssues) { if (!hasMoveableIssues) {
// Check if target list assignee is already present in this issue // Check if target list assignee is already present in this issue
......
...@@ -315,10 +315,13 @@ export default class Clusters { ...@@ -315,10 +315,13 @@ export default class Clusters {
this.checkForNewInstalls(prevApplicationMap, this.store.state.applications); this.checkForNewInstalls(prevApplicationMap, this.store.state.applications);
this.updateContainer(prevStatus, this.store.state.status, this.store.state.statusReason); this.updateContainer(prevStatus, this.store.state.status, this.store.state.statusReason);
this.toggleIngressDomainHelpText(
prevApplicationMap[INGRESS], if (this.ingressDomainHelpText) {
this.store.state.applications[INGRESS], this.toggleIngressDomainHelpText(
); prevApplicationMap[INGRESS],
this.store.state.applications[INGRESS],
);
}
} }
showToken() { showToken() {
......
...@@ -263,7 +263,6 @@ Crossplane runs inside your Kubernetes cluster and supports secure connectivity ...@@ -263,7 +263,6 @@ Crossplane runs inside your Kubernetes cluster and supports secure connectivity
<template> <template>
<section id="cluster-applications"> <section id="cluster-applications">
<h4>{{ s__('ClusterIntegration|Applications') }}</h4>
<p class="append-bottom-0"> <p class="append-bottom-0">
{{ {{
s__(`ClusterIntegration|Choose which applications to install on your Kubernetes cluster. s__(`ClusterIntegration|Choose which applications to install on your Kubernetes cluster.
......
const BOLD = 'bold';
const ITALIC = 'italic';
const BOLD_ITALIC = 'bold italic';
const UNDERLINE = 'underline';
export default { export default {
base: 'vs', base: 'vs',
inherit: true, inherit: false,
rules: [], rules: [
// Standard theme defaults and overrides based on VS theme
// https://github.com/Microsoft/vscode/blob/master/src/vs/editor/standalone/common/themes.ts
// License: MIT (https://github.com/microsoft/vscode/blob/master/LICENSE.txt)
{ token: '', foreground: '2e2e2e', background: 'ffffff' },
{ token: 'keyword.css', fontStyle: BOLD, foreground: '999999' },
{ token: 'keyword.less', fontStyle: BOLD, foreground: '999999' },
{ token: 'keyword.scss', fontStyle: BOLD, foreground: '999999' },
{ token: 'keyword.md', fontStyle: BOLD, foreground: '800080' },
{ token: 'variable', foreground: '008080' },
{ token: 'variable.md', foreground: 'dd1144' },
{ token: 'variable.predefined', foreground: '008080' },
{ token: 'number', foreground: '009999' },
{ token: 'number.hex', foreground: '3030c0' },
{ token: 'type.identifier.ts', foreground: '445588', fontStyle: BOLD },
{ token: 'type.identifier.swift', foreground: '445588', fontStyle: BOLD },
{ token: 'type.identifier.kt', foreground: '445588', fontStyle: BOLD },
{ token: 'type.identifier.perl', foreground: '2e2e2e', fontStyle: BOLD },
{ token: 'tag', foreground: '000080' },
{ token: 'tag.class', foreground: '445588', fontStyle: BOLD },
{ token: 'tag.css', foreground: '445588', fontStyle: BOLD },
{ token: 'tag.less', foreground: '445588', fontStyle: BOLD },
{ token: 'tag.scss', foreground: '445588', fontStyle: BOLD },
{ token: 'tag.id.jade', foreground: '445588' },
{ token: 'tag.class.jade', foreground: '445588' },
{ token: 'meta.scss', foreground: '800000' },
{ token: 'metatag', foreground: 'e00000' },
{ token: 'metatag.content.html', foreground: 'e00000' },
{ token: 'metatag.html', foreground: '808080' },
{ token: 'metatag.xml', foreground: '808080' },
{ token: 'metatag.php', fontStyle: BOLD },
{ token: 'key', foreground: '863b00' },
{ token: 'key.ini', foreground: '008080' },
{ token: 'string.key.json', foreground: '2e2e2e' },
{ token: 'string.value.json', foreground: 'dd1144' },
{ token: 'string.link.md', foreground: 'aa0000' },
{ token: 'attribute.name', foreground: '008080' },
{ token: 'attribute.name.css', foreground: '2e2e2e' },
{ token: 'attribute.name.json', foreground: '2e2e2e' },
{ token: 'attribute.name.scss', foreground: '2e2e2e' },
{ token: 'attribute.name.less', foreground: '2e2e2e' },
{ token: 'attribute.value', foreground: 'dd1144' },
{ token: 'attribute.value.css', foreground: '0086b3' },
{ token: 'attribute.value.hex', foreground: '0086b3' },
{ token: 'attribute.value.number', foreground: '009999' },
{ token: 'attribute.value.unit', foreground: '009999' },
{ token: 'attribute.value.xml', foreground: 'dd1144' },
{ token: 'attribute.value.html', foreground: 'dd1144' },
{ token: 'attribute.value.md', foreground: 'aa0000' },
{ token: 'string', foreground: 'dd1144' },
{ token: 'string.target', foreground: 'aa0000' },
{ token: 'string.sql', foreground: 'dd1144' },
{ token: 'keyword.flow', foreground: '2e2e2e', fontStyle: BOLD },
{ token: 'keyword.st', foreground: '445588', fontStyle: BOLD },
{ token: 'variable.st', foreground: '445588', fontStyle: BOLD },
{ token: 'type.st', foreground: '445588', fontStyle: BOLD },
{ token: 'operator.scss', foreground: '666666' },
{ token: 'operator.sql', foreground: '2e2e2e', fontStyle: BOLD },
{ token: 'operator.swift', foreground: '666666' },
{ token: 'predefined.sql', foreground: '2e2e2e', fontStyle: BOLD },
// GitHub theme based on https://github.com/brijeshb42/monaco-themes/blob/master/themes/GitHub.json
// Customized for Web IDE
// License: MIT (https://github.com/brijeshb42/monaco-themes/blob/master/LICENSE)
{ token: 'comment', foreground: '999988', fontStyle: ITALIC },
{ token: 'comment.block.preprocessor', foreground: '999999', fontStyle: BOLD },
{ token: 'comment.documentation', foreground: '999999', fontStyle: BOLD_ITALIC },
{ token: 'comment.block.documentation', foreground: '999999', fontStyle: BOLD_ITALIC },
{ token: 'invalid.illegal', foreground: 'aa0000', background: 'e3d2d2' },
{ token: 'keyword', fontStyle: BOLD, foreground: '2e2e2e' },
{ token: 'storage', fontStyle: BOLD },
{ token: 'keyword.operator', fontStyle: BOLD },
{ token: 'constant.language', fontStyle: BOLD },
{ token: 'support.constant', fontStyle: BOLD },
{ token: 'storage.type', foreground: '445588', fontStyle: BOLD },
{ token: 'support.type', foreground: '445588', fontStyle: BOLD },
{ token: 'entity.other.attribute-name', foreground: '008080' },
{ token: 'variable.other', foreground: '0086b3' },
{ token: 'variable.language', foreground: '999999' },
{ token: 'entity.name.type', foreground: '445588', fontStyle: BOLD },
{ token: 'entity.other.inherited-class', foreground: '445588', fontStyle: BOLD },
{ token: 'support.class', foreground: '445588', fontStyle: BOLD },
{ token: 'variable.other.constant', foreground: '008080' },
{ token: 'constant.character.entity', foreground: '800080' },
{ token: 'entity.name.exception', foreground: 'aa0000' },
{ token: 'entity.name.function', foreground: 'aa0000' },
{ token: 'support.function', foreground: 'aa0000' },
{ token: 'keyword.other.name-of-parameter', foreground: 'aa0000' },
{ token: 'entity.name.section', foreground: '666666' },
{ token: 'entity.name.tag', foreground: '000080' },
{ token: 'variable.parameter', foreground: '008080' },
{ token: 'support.variable', foreground: '008080' },
{ token: 'constant.numeric', foreground: '009999' },
{ token: 'constant.other', foreground: '009999' },
{ token: 'constant.character', foreground: 'dd1144' },
{ token: 'string.regexp', foreground: '009926' },
{ token: 'constant.other.symbol', foreground: '990073' },
{ token: 'punctuation', fontStyle: BOLD },
{ token: 'markup.deleted', foreground: '000000', background: 'ffdddd' },
{ token: 'markup.italic', fontStyle: ITALIC },
{ token: 'markup.error', foreground: 'aa0000' },
{ token: 'markup.heading.1', foreground: '999999' },
{ token: 'markup.inserted', foreground: '000000', background: 'ddffdd' },
{ token: 'markup.output', foreground: '808080' },
{ token: 'markup.raw', foreground: '808080' },
{ token: 'markup.prompt', foreground: '666666' },
{ token: 'markup.bold', fontStyle: BOLD },
{ token: 'markup.heading', foreground: '999999' },
{ token: 'markup.traceback', foreground: 'aa0000' },
{ token: 'markup.underline', fontStyle: UNDERLINE },
{ token: 'meta.diff.range', foreground: '999999', background: 'eaf2f5' },
{ token: 'meta.diff.index', foreground: '999999', background: 'eaf2f5' },
{ token: 'meta.separator', foreground: '999999', background: 'eaf2f5' },
{ token: 'meta.diff.header.from-file', foreground: '999999', background: 'ffdddd' },
{ token: 'meta.diff.header.to-file', foreground: '999999', background: 'ddffdd' },
{ token: 'meta.link', foreground: '4183c4' },
],
colors: { colors: {
'editorLineNumber.foreground': '#CCCCCC', 'editor.foreground': '#2e2e2e',
'diffEditor.insertedTextBackground': '#A0F5B420',
'diffEditor.removedTextBackground': '#f9d7dc20',
'editor.selectionBackground': '#aad6f8', 'editor.selectionBackground': '#aad6f8',
'editor.lineHighlightBackground': '#fffeeb',
'editorCursor.foreground': '#666666',
'editorWhitespace.foreground': '#bbbbbb',
'editorLineNumber.foreground': '#cccccc',
'diffEditor.insertedTextBackground': '#a0f5b420',
'diffEditor.removedTextBackground': '#f9d7dc20',
'editorIndentGuide.activeBackground': '#cccccc', 'editorIndentGuide.activeBackground': '#cccccc',
}, },
}; };
...@@ -67,7 +67,7 @@ export default { ...@@ -67,7 +67,7 @@ export default {
</template> </template>
</expand-button> </expand-button>
<clipboard-button <clipboard-button
:title="__('Copy commit SHA')" :title="__('Copy evidence SHA')"
:text="sha" :text="sha"
css-class="btn-default btn-transparent btn-clipboard" css-class="btn-default btn-transparent btn-clipboard"
/> />
......
...@@ -93,7 +93,10 @@ export default { ...@@ -93,7 +93,10 @@ export default {
<release-block-header :release="release" /> <release-block-header :release="release" />
<div class="card-body"> <div class="card-body">
<div v-if="shouldRenderMilestoneInfo"> <div v-if="shouldRenderMilestoneInfo">
<release-block-milestone-info :milestones="milestones" /> <release-block-milestone-info
:milestones="milestones"
:open-issues-path="release._links.issuesUrl"
/>
<hr class="mb-3 mt-0" /> <hr class="mb-3 mt-0" />
</div> </div>
......
...@@ -34,7 +34,7 @@ export default { ...@@ -34,7 +34,7 @@ export default {
<ul v-if="assets.links.length" class="pl-0 mb-0 prepend-top-8 list-unstyled js-assets-list"> <ul v-if="assets.links.length" class="pl-0 mb-0 prepend-top-8 list-unstyled js-assets-list">
<li v-for="link in assets.links" :key="link.name" class="append-bottom-8"> <li v-for="link in assets.links" :key="link.name" class="append-bottom-8">
<gl-link v-gl-tooltip.bottom :title="__('Download asset')" :href="link.url"> <gl-link v-gl-tooltip.bottom :title="__('Download asset')" :href="link.directAssetUrl">
<icon name="package" class="align-middle append-right-4 align-text-bottom" /> <icon name="package" class="align-middle append-right-4 align-text-bottom" />
{{ link.name }} {{ link.name }}
<span v-if="link.external">{{ __('(external source)') }}</span> <span v-if="link.external">{{ __('(external source)') }}</span>
......
<script> <script>
import { GlProgressBar, GlLink, GlBadge, GlButton, GlTooltipDirective } from '@gitlab/ui'; import {
GlProgressBar,
GlLink,
GlBadge,
GlButton,
GlTooltipDirective,
GlSprintf,
} from '@gitlab/ui';
import { __, n__, sprintf } from '~/locale'; import { __, n__, sprintf } from '~/locale';
import { MAX_MILESTONES_TO_DISPLAY } from '../constants'; import { MAX_MILESTONES_TO_DISPLAY } from '../constants';
import { sum } from 'lodash';
/** Sums the values of an array. For use with Array.reduce. */
const sumReducer = (acc, curr) => acc + curr;
export default { export default {
name: 'ReleaseBlockMilestoneInfo', name: 'ReleaseBlockMilestoneInfo',
...@@ -13,6 +18,7 @@ export default { ...@@ -13,6 +18,7 @@ export default {
GlLink, GlLink,
GlBadge, GlBadge,
GlButton, GlButton,
GlSprintf,
}, },
directives: { directives: {
GlTooltip: GlTooltipDirective, GlTooltip: GlTooltipDirective,
...@@ -22,6 +28,16 @@ export default { ...@@ -22,6 +28,16 @@ export default {
type: Array, type: Array,
required: true, required: true,
}, },
openIssuesPath: {
type: String,
required: false,
default: '',
},
closedIssuesPath: {
type: String,
required: false,
default: '',
},
}, },
data() { data() {
return { return {
...@@ -42,14 +58,14 @@ export default { ...@@ -42,14 +58,14 @@ export default {
allIssueStats() { allIssueStats() {
return this.milestones.map(m => m.issueStats || {}); return this.milestones.map(m => m.issueStats || {});
}, },
openIssuesCount() { totalIssuesCount() {
return this.allIssueStats.map(stats => stats.opened || 0).reduce(sumReducer); return sum(this.allIssueStats.map(stats => stats.total || 0));
}, },
closedIssuesCount() { closedIssuesCount() {
return this.allIssueStats.map(stats => stats.closed || 0).reduce(sumReducer); return sum(this.allIssueStats.map(stats => stats.closed || 0));
}, },
totalIssuesCount() { openIssuesCount() {
return this.openIssuesCount + this.closedIssuesCount; return this.totalIssuesCount - this.closedIssuesCount;
}, },
milestoneLabelText() { milestoneLabelText() {
return n__('Milestone', 'Milestones', this.milestones.length); return n__('Milestone', 'Milestones', this.milestones.length);
...@@ -130,7 +146,27 @@ export default { ...@@ -130,7 +146,27 @@ export default {
{{ __('Issues') }} {{ __('Issues') }}
<gl-badge pill variant="light" class="font-weight-bold">{{ totalIssuesCount }}</gl-badge> <gl-badge pill variant="light" class="font-weight-bold">{{ totalIssuesCount }}</gl-badge>
</span> </span>
{{ issueCountsText }} <div class="d-flex">
<gl-link v-if="openIssuesPath" ref="openIssuesLink" :href="openIssuesPath">
<gl-sprintf :message="__('Open: %{openIssuesCount}')">
<template #openIssuesCount>{{ openIssuesCount }}</template>
</gl-sprintf>
</gl-link>
<span v-else ref="openIssuesText">
{{ sprintf(__('Open: %{openIssuesCount}'), { openIssuesCount }) }}
</span>
<span class="mx-1">&bull;</span>
<gl-link v-if="closedIssuesPath" ref="closedIssuesLink" :href="closedIssuesPath">
<gl-sprintf :message="__('Closed: %{closedIssuesCount}')">
<template #closedIssuesCount>{{ closedIssuesCount }}</template>
</gl-sprintf>
</gl-link>
<span v-else ref="closedIssuesText">
{{ sprintf(__('Closed: %{closedIssuesCount}'), { closedIssuesCount }) }}
</span>
</div>
</div> </div>
</div> </div>
</template> </template>
...@@ -307,7 +307,7 @@ class ApplicationController < ActionController::Base ...@@ -307,7 +307,7 @@ class ApplicationController < ActionController::Base
if current_user && current_user.requires_ldap_check? if current_user && current_user.requires_ldap_check?
return unless current_user.try_obtain_ldap_lease return unless current_user.try_obtain_ldap_lease
unless Gitlab::Auth::LDAP::Access.allowed?(current_user) unless Gitlab::Auth::Ldap::Access.allowed?(current_user)
sign_out current_user sign_out current_user
flash[:alert] = _("Access denied for your LDAP account.") flash[:alert] = _("Access denied for your LDAP account.")
redirect_to new_user_session_path redirect_to new_user_session_path
......
...@@ -30,9 +30,9 @@ module SnippetsActions ...@@ -30,9 +30,9 @@ module SnippetsActions
end end
def check_repository_error def check_repository_error
repository_error = snippet.errors.delete(:repository) repository_errors = Array(snippet.errors.delete(:repository))
flash.now[:alert] = repository_error if repository_error flash.now[:alert] = repository_errors.first if repository_errors.present?
recaptcha_check_with_fallback(repository_error.nil?) { render :edit } recaptcha_check_with_fallback(repository_errors.empty?) { render :edit }
end end
end end
...@@ -4,9 +4,9 @@ class Ldap::OmniauthCallbacksController < OmniauthCallbacksController ...@@ -4,9 +4,9 @@ class Ldap::OmniauthCallbacksController < OmniauthCallbacksController
extend ::Gitlab::Utils::Override extend ::Gitlab::Utils::Override
def self.define_providers! def self.define_providers!
return unless Gitlab::Auth::LDAP::Config.sign_in_enabled? return unless Gitlab::Auth::Ldap::Config.sign_in_enabled?
Gitlab::Auth::LDAP::Config.available_servers.each do |server| Gitlab::Auth::Ldap::Config.available_servers.each do |server|
alias_method server['provider_name'], :ldap alias_method server['provider_name'], :ldap
end end
end end
...@@ -14,9 +14,9 @@ class Ldap::OmniauthCallbacksController < OmniauthCallbacksController ...@@ -14,9 +14,9 @@ class Ldap::OmniauthCallbacksController < OmniauthCallbacksController
# We only find ourselves here # We only find ourselves here
# if the authentication to LDAP was successful. # if the authentication to LDAP was successful.
def ldap def ldap
return unless Gitlab::Auth::LDAP::Config.sign_in_enabled? return unless Gitlab::Auth::Ldap::Config.sign_in_enabled?
sign_in_user_flow(Gitlab::Auth::LDAP::User) sign_in_user_flow(Gitlab::Auth::Ldap::User)
end end
define_providers! define_providers!
......
...@@ -6,7 +6,7 @@ class Projects::ReleasesController < Projects::ApplicationController ...@@ -6,7 +6,7 @@ class Projects::ReleasesController < Projects::ApplicationController
before_action :release, only: %i[edit show update downloads] before_action :release, only: %i[edit show update downloads]
before_action :authorize_read_release! before_action :authorize_read_release!
before_action do before_action do
push_frontend_feature_flag(:release_issue_summary, project) push_frontend_feature_flag(:release_issue_summary, project, default_enabled: true)
push_frontend_feature_flag(:release_evidence_collection, project, default_enabled: true) push_frontend_feature_flag(:release_evidence_collection, project, default_enabled: true)
push_frontend_feature_flag(:release_show_page, project, default_enabled: true) push_frontend_feature_flag(:release_show_page, project, default_enabled: true)
end end
......
...@@ -273,8 +273,8 @@ class SessionsController < Devise::SessionsController ...@@ -273,8 +273,8 @@ class SessionsController < Devise::SessionsController
def ldap_servers def ldap_servers
@ldap_servers ||= begin @ldap_servers ||= begin
if Gitlab::Auth::LDAP::Config.sign_in_enabled? if Gitlab::Auth::Ldap::Config.sign_in_enabled?
Gitlab::Auth::LDAP::Config.available_servers Gitlab::Auth::Ldap::Config.available_servers
else else
[] []
end end
......
...@@ -5,11 +5,11 @@ module AuthHelper ...@@ -5,11 +5,11 @@ module AuthHelper
LDAP_PROVIDER = /\Aldap/.freeze LDAP_PROVIDER = /\Aldap/.freeze
def ldap_enabled? def ldap_enabled?
Gitlab::Auth::LDAP::Config.enabled? Gitlab::Auth::Ldap::Config.enabled?
end end
def ldap_sign_in_enabled? def ldap_sign_in_enabled?
Gitlab::Auth::LDAP::Config.sign_in_enabled? Gitlab::Auth::Ldap::Config.sign_in_enabled?
end end
def omniauth_enabled? def omniauth_enabled?
......
...@@ -26,11 +26,38 @@ module ClustersHelper ...@@ -26,11 +26,38 @@ module ClustersHelper
end end
end end
def render_cluster_info_tab_content(tab, expanded)
case tab
when 'environments'
render_if_exists 'clusters/clusters/environments'
when 'health'
render_if_exists 'clusters/clusters/health'
when 'apps'
render 'applications'
when 'settings'
render 'advanced_settings_container'
else
render('details', expanded: expanded)
end
end
def has_rbac_enabled?(cluster) def has_rbac_enabled?(cluster)
return cluster.platform_kubernetes_rbac? if cluster.platform_kubernetes return cluster.platform_kubernetes_rbac? if cluster.platform_kubernetes
cluster.provider.has_rbac_enabled? cluster.provider.has_rbac_enabled?
end end
def project_cluster?(cluster)
cluster.cluster_type.in?('project_type')
end
def cluster_created?(cluster)
!cluster.status_name.in?(%i/scheduled creating/)
end
def can_admin_cluster?(user, cluster)
can?(user, :admin_cluster, cluster)
end
end end
ClustersHelper.prepend_if_ee('EE::ClustersHelper') ClustersHelper.prepend_if_ee('EE::ClustersHelper')
...@@ -25,7 +25,7 @@ class Identity < ApplicationRecord ...@@ -25,7 +25,7 @@ class Identity < ApplicationRecord
def self.normalize_uid(provider, uid) def self.normalize_uid(provider, uid)
if Gitlab::Auth::OAuth::Provider.ldap_provider?(provider) if Gitlab::Auth::OAuth::Provider.ldap_provider?(provider)
Gitlab::Auth::LDAP::Person.normalize_dn(uid) Gitlab::Auth::Ldap::Person.normalize_dn(uid)
else else
uid.to_s uid.to_s
end end
......
...@@ -98,6 +98,10 @@ class ProjectImportState < ApplicationRecord ...@@ -98,6 +98,10 @@ class ProjectImportState < ApplicationRecord
Gitlab::SidekiqStatus.set(jid, StuckImportJobsWorker::IMPORT_JOBS_EXPIRATION) Gitlab::SidekiqStatus.set(jid, StuckImportJobsWorker::IMPORT_JOBS_EXPIRATION)
end end
def self.jid_by(project_id:, status:)
select(:jid).with_status(status).find_by(project_id: project_id)
end
end end
ProjectImportState.prepend_if_ee('EE::ProjectImportState') ProjectImportState.prepend_if_ee('EE::ProjectImportState')
...@@ -1562,7 +1562,7 @@ class User < ApplicationRecord ...@@ -1562,7 +1562,7 @@ class User < ApplicationRecord
def read_only_attribute?(attribute) def read_only_attribute?(attribute)
if Feature.enabled?(:ldap_readonly_attributes, default_enabled: true) if Feature.enabled?(:ldap_readonly_attributes, default_enabled: true)
enabled = Gitlab::Auth::LDAP::Config.enabled? enabled = Gitlab::Auth::Ldap::Config.enabled?
read_only = attribute.to_sym.in?(UserSyncedAttributesMetadata::SYNCABLE_ATTRIBUTES) read_only = attribute.to_sym.in?(UserSyncedAttributesMetadata::SYNCABLE_ATTRIBUTES)
return true if enabled && read_only return true if enabled && read_only
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
Password authentication enabled for Git over HTTP(S) Password authentication enabled for Git over HTTP(S)
.form-text.text-muted .form-text.text-muted
When disabled, a Personal Access Token When disabled, a Personal Access Token
- if Gitlab::Auth::LDAP::Config.enabled? - if Gitlab::Auth::Ldap::Config.enabled?
or LDAP password or LDAP password
must be used to authenticate. must be used to authenticate.
- if omniauth_enabled? && button_based_providers.any? - if omniauth_enabled? && button_based_providers.any?
......
- if can_admin_cluster?(current_user, @cluster)
.settings.expanded.border-0.m-0
%p
= s_('ClusterIntegration|Advanced options on this Kubernetes cluster’s integration')
.settings-content#advanced-settings-section
= render 'clusters/clusters/advanced_settings'
- active = params[:tab] == 'settings'
- if can_admin_cluster?(current_user, @cluster)
%li.nav-item{ role: 'presentation' }
%a#cluster-settings-tab.nav-link{ class: active_when(active), href: clusterable.cluster_path(@cluster.id, params: {tab: 'settings'}) }
%span= _('Advanced Settings')
.cluster-applications-table#js-cluster-applications
- active = params[:tab] == 'apps'
%li.nav-item{ role: 'presentation' }
%a#cluster-apps-tab.nav-link.qa-applications{ class: active_when(active), href: clusterable.cluster_path(@cluster.id, params: {tab: 'apps'}) }
%span= _('Applications')
%section#cluster-integration
- unless @cluster.status_name.in? %i/scheduled creating/
= render 'form'
- unless @cluster.status_name.in? %i/scheduled creating/
= render_if_exists 'projects/clusters/prometheus_graphs'
.cluster-applications-table#js-cluster-applications
%section.settings#js-cluster-details{ class: ('expanded' if expanded) }
.settings-header
%h4= s_('ClusterIntegration|Kubernetes cluster details')
%button.btn.js-settings-toggle{ type: 'button' }
= expanded ? _('Collapse') : _('Expand')
%p= s_('ClusterIntegration|See and edit the details for your Kubernetes cluster')
.settings-content
= render 'clusters/platforms/kubernetes/form', cluster: @cluster, platform: @cluster.platform_kubernetes, update_cluster_url_path: clusterable.cluster_path(@cluster)
%section.settings.no-animate#js-cluster-advanced-settings{ class: ('expanded' if expanded) }
.settings-header
%h4= _('Advanced settings')
%button.btn.js-settings-toggle{ type: 'button' }
= expanded ? _('Collapse') : _('Expand')
%p= s_("ClusterIntegration|Advanced options on this Kubernetes cluster's integration")
.settings-content#advanced-settings-section
= render 'advanced_settings'
%section#cluster-integration
= render 'gitlab_integration_form'
%section.settings.no-animate{ class: ('expanded' if expanded) }
.settings-header
%h4= s_('ClusterIntegration|Provider details')
%button.btn.js-settings-toggle{ type: 'button' }
= expanded ? _('Collapse') : _('Expand')
%p= s_('ClusterIntegration|See and edit the details for your Kubernetes cluster')
.settings-content
= render 'provider_details_form', cluster: @cluster, platform: @cluster.platform_kubernetes, update_cluster_url_path: clusterable.cluster_path(@cluster)
- active = params[:tab] == 'details' || !params[:tab].present?
%li.nav-item{ role: 'presentation' }
%a#cluster-details-tab.nav-link.qa-details{ class: active_when(active), href: clusterable.cluster_path(@cluster.id, params: {tab: 'details'}) }
%span= _('Details')
= form_for @cluster, url: clusterable.cluster_path(@cluster), as: :cluster, html: { class: 'cluster_integration_form' } do |field| = form_for @cluster, url: clusterable.cluster_path(@cluster), as: :cluster, html: { class: 'js-cluster-integration-form' } do |field|
= form_errors(@cluster) = form_errors(@cluster)
.form-group .form-group
%h5= s_('ClusterIntegration|Integration status') .d-flex.align-items-center
%label.append-bottom-0.js-cluster-enable-toggle-area %h4.pr-2.m-0
= render "shared/buttons/project_feature_toggle", is_checked: @cluster.enabled?, label: s_("ClusterIntegration|Toggle Kubernetes cluster"), disabled: !can?(current_user, :update_cluster, @cluster), data: { qa_selector: 'integration_status_toggle' } do = s_('ClusterIntegration|GitLab Integration')
= field.hidden_field :enabled, { class: 'js-project-feature-toggle-input'} %label.append-bottom-0.js-cluster-enable-toggle-area{ title: s_('ClusterIntegration|Enable or disable GitLab\'s connection to your Kubernetes cluster.'), data: { toggle: 'tooltip', container: 'body' } }
.form-text.text-muted= s_('ClusterIntegration|Enable or disable GitLab\'s connection to your Kubernetes cluster.') = render "shared/buttons/project_feature_toggle", is_checked: @cluster.enabled?, label: s_("ClusterIntegration|Toggle Kubernetes cluster"), disabled: !can?(current_user, :update_cluster, @cluster), data: { qa_selector: 'integration_status_toggle' } do
= field.hidden_field :enabled, { class: 'js-project-feature-toggle-input'}
.form-group .form-group
%h5= s_('ClusterIntegration|Environment scope') %h5= s_('ClusterIntegration|Environment scope')
...@@ -17,7 +18,8 @@ ...@@ -17,7 +18,8 @@
- environment_scope_url = help_page_path('user/project/clusters/index', anchor: 'base-domain') - environment_scope_url = help_page_path('user/project/clusters/index', anchor: 'base-domain')
- environment_scope_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: environment_scope_url } - environment_scope_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: environment_scope_url }
.form-text.text-muted .form-text.text-muted
%code * %code
= _('*')
= s_("ClusterIntegration| is the default environment scope for this cluster. This means that all jobs, regardless of their environment, will use this cluster. %{environment_scope_start}More information%{environment_scope_end}").html_safe % { environment_scope_start: environment_scope_start, environment_scope_end: '</a>'.html_safe } = s_("ClusterIntegration| is the default environment scope for this cluster. This means that all jobs, regardless of their environment, will use this cluster. %{environment_scope_start}More information%{environment_scope_end}").html_safe % { environment_scope_start: environment_scope_start, environment_scope_end: '</a>'.html_safe }
.form-group .form-group
...@@ -29,7 +31,8 @@ ...@@ -29,7 +31,8 @@
= s_('ClusterIntegration|Specifying a domain will allow you to use Auto Review Apps and Auto Deploy stages for %{auto_devops_start}Auto DevOps%{auto_devops_end}. The domain should have a wildcard DNS configured matching the domain.').html_safe % { auto_devops_start: auto_devops_start, auto_devops_end: '</a>'.html_safe } = s_('ClusterIntegration|Specifying a domain will allow you to use Auto Review Apps and Auto Deploy stages for %{auto_devops_start}Auto DevOps%{auto_devops_end}. The domain should have a wildcard DNS configured matching the domain.').html_safe % { auto_devops_start: auto_devops_start, auto_devops_end: '</a>'.html_safe }
%span{ :class => ["js-ingress-domain-help-text", ("hide" unless @cluster.application_ingress_external_ip.present?)] } %span{ :class => ["js-ingress-domain-help-text", ("hide" unless @cluster.application_ingress_external_ip.present?)] }
= s_('ClusterIntegration|Alternatively') = s_('ClusterIntegration|Alternatively')
%code{ :class => "js-ingress-domain-snippet" } #{@cluster.application_ingress_external_ip}.nip.io %code{ :class => "js-ingress-domain-snippet" }
= s_('ClusterIntegration|%{external_ip}.nip.io').html_safe % { external_ip: @cluster.application_ingress_external_ip }
= s_('ClusterIntegration| can be used instead of a custom domain.') = s_('ClusterIntegration| can be used instead of a custom domain.')
- custom_domain_url = help_page_path('user/clusters/applications.md', anchor: 'pointing-your-dns-at-the-external-endpoint') - custom_domain_url = help_page_path('user/clusters/applications.md', anchor: 'pointing-your-dns-at-the-external-endpoint')
- custom_domain_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: custom_domain_url } - custom_domain_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: custom_domain_url }
......
= bootstrap_form_for cluster, url: update_cluster_url_path, html: { class: 'gl-show-field-errors' }, = bootstrap_form_for cluster, url: update_cluster_url_path, html: { class: 'js-provider-details gl-show-field-errors' },
as: :cluster do |field| as: :cluster do |field|
- copy_name_btn = clipboard_button(text: cluster.name, title: s_('ClusterIntegration|Copy Kubernetes cluster name'), - copy_name_btn = clipboard_button(text: cluster.name, title: s_('ClusterIntegration|Copy Kubernetes cluster name'),
class: 'input-group-text btn-default') if cluster.read_only_kubernetes_platform_fields? class: 'input-group-text btn-default') if cluster.read_only_kubernetes_platform_fields?
......
...@@ -5,8 +5,6 @@ ...@@ -5,8 +5,6 @@
- manage_prometheus_path = edit_project_service_path(@cluster.project, 'prometheus') if @project - manage_prometheus_path = edit_project_service_path(@cluster.project, 'prometheus') if @project
- cluster_environments_path = clusterable.environments_cluster_path(@cluster) - cluster_environments_path = clusterable.environments_cluster_path(@cluster)
- expanded = expanded_by_default?
- status_path = clusterable.cluster_status_cluster_path(@cluster.id, format: :json) if can?(current_user, :admin_cluster, @cluster) - status_path = clusterable.cluster_status_cluster_path(@cluster.id, format: :json) if can?(current_user, :admin_cluster, @cluster)
.edit-cluster-form.js-edit-cluster-form{ data: { status_path: status_path, .edit-cluster-form.js-edit-cluster-form{ data: { status_path: status_path,
install_helm_path: clusterable.install_applications_cluster_path(@cluster, :helm), install_helm_path: clusterable.install_applications_cluster_path(@cluster, :helm),
...@@ -44,7 +42,19 @@ ...@@ -44,7 +42,19 @@
%h4= @cluster.name %h4= @cluster.name
= render 'banner' = render 'banner'
- if cluster_environments_path.present? - if cluster_created?(@cluster)
= render_if_exists 'clusters/clusters/cluster_environments', expanded: expanded .js-toggle-container
- else %ul.nav-links.mobile-separator.nav.nav-tabs{ role: 'tablist' }
= render 'configure', expanded: expanded = render 'details_tab'
= render_if_exists 'clusters/clusters/environments_tab'
= render_if_exists 'clusters/clusters/health_tab'
= render 'applications_tab'
= render 'advanced_settings_tab'
.tab-content.py-3
.tab-pane.active{ role: 'tabpanel' }
= render_cluster_info_tab_content(params[:tab], expanded_by_default?)
...@@ -8,15 +8,12 @@ module Gitlab ...@@ -8,15 +8,12 @@ module Gitlab
# stage. # stage.
class AdvanceStageWorker # rubocop:disable Scalability/IdempotentWorker class AdvanceStageWorker # rubocop:disable Scalability/IdempotentWorker
include ApplicationWorker include ApplicationWorker
include ::Gitlab::Import::AdvanceStage
sidekiq_options dead: false sidekiq_options dead: false
feature_category :importers feature_category :importers
INTERVAL = 30.seconds.to_i private
# The number of seconds to wait (while blocking the thread) before
# continuing to the next waiter.
BLOCKING_WAIT_TIME = 5
# The known importer stages and their corresponding Sidekiq workers. # The known importer stages and their corresponding Sidekiq workers.
STAGES = { STAGES = {
...@@ -26,49 +23,9 @@ module Gitlab ...@@ -26,49 +23,9 @@ module Gitlab
finish: Stage::FinishImportWorker finish: Stage::FinishImportWorker
}.freeze }.freeze
# project_id - The ID of the project being imported. def next_stage_worker(next_stage)
# waiters - A Hash mapping Gitlab::JobWaiter keys to the number of STAGES.fetch(next_stage.to_sym)
# remaining jobs.
# next_stage - The name of the next stage to start when all jobs have been
# completed.
def perform(project_id, waiters, next_stage)
return unless import_state = find_import_state(project_id)
new_waiters = wait_for_jobs(waiters)
if new_waiters.empty?
# We refresh the import JID here so workers importing individual
# resources (e.g. notes) don't have to do this all the time, reducing
# the pressure on Redis. We _only_ do this once all jobs are done so
# we don't get stuck forever if one or more jobs failed to notify the
# JobWaiter.
import_state.refresh_jid_expiration
STAGES.fetch(next_stage.to_sym).perform_async(project_id)
else
self.class.perform_in(INTERVAL, project_id, new_waiters, next_stage)
end
end
def wait_for_jobs(waiters)
waiters.each_with_object({}) do |(key, remaining), new_waiters|
waiter = JobWaiter.new(remaining, key)
# We wait for a brief moment of time so we don't reschedule if we can
# complete the work fast enough.
waiter.wait(BLOCKING_WAIT_TIME)
next unless waiter.jobs_remaining.positive?
new_waiters[waiter.key] = waiter.jobs_remaining
end
end
# rubocop: disable CodeReuse/ActiveRecord
def find_import_state(project_id)
ProjectImportState.select(:jid).with_status(:started).find_by(project_id: project_id)
end end
# rubocop: enable CodeReuse/ActiveRecord
end end
end end
end end
# frozen_string_literal: true
module Gitlab
module Import
module AdvanceStage
INTERVAL = 30.seconds.to_i
# The number of seconds to wait (while blocking the thread) before
# continuing to the next waiter.
BLOCKING_WAIT_TIME = 5
# project_id - The ID of the project being imported.
# waiters - A Hash mapping Gitlab::JobWaiter keys to the number of
# remaining jobs.
# next_stage - The name of the next stage to start when all jobs have been
# completed.
def perform(project_id, waiters, next_stage)
return unless import_state = find_import_state(project_id)
new_waiters = wait_for_jobs(waiters)
if new_waiters.empty?
# We refresh the import JID here so workers importing individual
# resources (e.g. notes) don't have to do this all the time, reducing
# the pressure on Redis. We _only_ do this once all jobs are done so
# we don't get stuck forever if one or more jobs failed to notify the
# JobWaiter.
import_state.refresh_jid_expiration
next_stage_worker(next_stage).perform_async(project_id)
else
self.class.perform_in(INTERVAL, project_id, new_waiters, next_stage)
end
end
def wait_for_jobs(waiters)
waiters.each_with_object({}) do |(key, remaining), new_waiters|
waiter = JobWaiter.new(remaining, key)
# We wait for a brief moment of time so we don't reschedule if we can
# complete the work fast enough.
waiter.wait(BLOCKING_WAIT_TIME)
next unless waiter.jobs_remaining.positive?
new_waiters[waiter.key] = waiter.jobs_remaining
end
end
def find_import_state(project_id)
ProjectImportState.jid_by(project_id: project_id, status: :started)
end
private
def next_stage_worker(next_stage)
raise NotImplementedError
end
end
end
end
...@@ -77,11 +77,6 @@ class PostReceive # rubocop:disable Scalability/IdempotentWorker ...@@ -77,11 +77,6 @@ class PostReceive # rubocop:disable Scalability/IdempotentWorker
return false unless user return false unless user
# We can remove once we implement multi-file snippets
# https://gitlab.com/gitlab-org/gitlab/-/issues/39269
blob = snippet.blobs.first
snippet.update(file_name: blob.path, content: blob.data) if blob
# At the moment, we only expires the repository caches. # At the moment, we only expires the repository caches.
# In the future we might need to call ProjectCacheWorker # In the future we might need to call ProjectCacheWorker
# (or the custom class we create) to update the snippet # (or the custom class we create) to update the snippet
......
---
title: Fix White syntax highlighting theme in Monaco to closely match the Pygments theme.
merge_request: 25966
author:
type: fixed
---
title: Fix evidence SHA clipboard hover text.
merge_request: 26608
author: Gilang Gumilar
type: fixed
---
title: Expose assets filepath URL on UI
merge_request: 25635
author:
type: added
---
title: Split cluster info page into tabs
merge_request: 25940
author:
type: changed
---
title: Fix bug displaying snippet update error
merge_request: 27082
author:
type: fixed
---
title: Add issue summary to Release blocks on the Releases page
merge_request: 27032
author:
type: added
...@@ -226,9 +226,9 @@ Devise.setup do |config| ...@@ -226,9 +226,9 @@ Devise.setup do |config|
manager.failure_app = Gitlab::DeviseFailure manager.failure_app = Gitlab::DeviseFailure
end end
if Gitlab::Auth::LDAP::Config.enabled? if Gitlab::Auth::Ldap::Config.enabled?
Gitlab::Auth::LDAP::Config.providers.each do |provider| Gitlab::Auth::Ldap::Config.providers.each do |provider|
ldap_config = Gitlab::Auth::LDAP::Config.new(provider) ldap_config = Gitlab::Auth::Ldap::Config.new(provider)
config.omniauth(provider, ldap_config.omniauth_options) config.omniauth(provider, ldap_config.omniauth_options)
end end
end end
......
if Gitlab::Auth::LDAP::Config.enabled? if Gitlab::Auth::Ldap::Config.enabled?
module OmniAuth::Strategies module OmniAuth::Strategies
Gitlab::Auth::LDAP::Config.available_servers.each do |server| Gitlab::Auth::Ldap::Config.available_servers.each do |server|
# do not redeclare LDAP # do not redeclare LDAP
next if server['provider_name'] == 'ldap' next if server['provider_name'] == 'ldap'
......
...@@ -10,9 +10,9 @@ def override_omniauth(provider, controller, path_prefix = '/users/auth') ...@@ -10,9 +10,9 @@ def override_omniauth(provider, controller, path_prefix = '/users/auth')
end end
# Use custom controller for LDAP omniauth callback # Use custom controller for LDAP omniauth callback
if Gitlab::Auth::LDAP::Config.sign_in_enabled? if Gitlab::Auth::Ldap::Config.sign_in_enabled?
devise_scope :user do devise_scope :user do
Gitlab::Auth::LDAP::Config.available_servers.each do |server| Gitlab::Auth::Ldap::Config.available_servers.each do |server|
override_omniauth(server['provider_name'], 'ldap/omniauth_callbacks') override_omniauth(server['provider_name'], 'ldap/omniauth_callbacks')
end end
end end
......
...@@ -493,7 +493,7 @@ step of the sync. ...@@ -493,7 +493,7 @@ step of the sync.
1. Run a group sync for this particular group. 1. Run a group sync for this particular group.
```ruby ```ruby
EE::Gitlab::Auth::LDAP::Sync::Group.execute_all_providers(group) EE::Gitlab::Auth::Ldap::Sync::Group.execute_all_providers(group)
``` ```
1. Look through the output of the sync. See [example log output](#example-log-output) 1. Look through the output of the sync. See [example log output](#example-log-output)
...@@ -503,11 +503,11 @@ step of the sync. ...@@ -503,11 +503,11 @@ step of the sync.
run the following query: run the following query:
```ruby ```ruby
adapter = Gitlab::Auth::LDAP::Adapter.new('ldapmain') # If `main` is the LDAP provider adapter = Gitlab::Auth::Ldap::Adapter.new('ldapmain') # If `main` is the LDAP provider
ldap_group = EE::Gitlab::Auth::LDAP::Group.find_by_cn('group_cn_here', adapter) ldap_group = EE::Gitlab::Auth::Ldap::Group.find_by_cn('group_cn_here', adapter)
# Output # Output
=> #<EE::Gitlab::Auth::LDAP::Group:0x007fcbdd0bb6d8 => #<EE::Gitlab::Auth::Ldap::Group:0x007fcbdd0bb6d8
``` ```
1. Query the LDAP group's member DNs and see if the user's DN is in the list. 1. Query the LDAP group's member DNs and see if the user's DN is in the list.
......
...@@ -9,8 +9,8 @@ ensure that they are scalable and highly available. While these needs can be tac ...@@ -9,8 +9,8 @@ ensure that they are scalable and highly available. While these needs can be tac
individually, they typically go hand in hand: a performant scalable environment individually, they typically go hand in hand: a performant scalable environment
will have availability by default, as its components are separated and pooled. will have availability by default, as its components are separated and pooled.
On this page, we present recommendations for setups based on the number On this page, we present a maturity model for a progression from simple to complex
of users you expect. For larger setups we give several recommended GitLab installations as your GitLab usage evolves. For larger setups we give several recommended
architectures based on experience with GitLab.com and internal scale architectures based on experience with GitLab.com and internal scale
testing that aim to achieve the right balance between both scalability testing that aim to achieve the right balance between both scalability
and availability. and availability.
...@@ -20,9 +20,60 @@ watch [this 1 hour Q&A](https://www.youtube.com/watch?v=uCU8jdYzpac) ...@@ -20,9 +20,60 @@ watch [this 1 hour Q&A](https://www.youtube.com/watch?v=uCU8jdYzpac)
with [John Northrup](https://gitlab.com/northrup), and live questions coming with [John Northrup](https://gitlab.com/northrup), and live questions coming
in from some of our customers. in from some of our customers.
## Maturity levels
### Level 1: Single-node Omnibus installation
This solution is appropriate for many teams that have a single server at their disposal. With automatic backup of the GitLab repositories, configuration, and the database, this can be an optimal solution if you don't have strict availability requirements.
This configuration is supported in [GitLab Starter, Premium and Ultimate](https://about.gitlab.com/pricing/).
References:
- [Installation Docs](../../install/README.html)
- [Backup/Restore Docs](https://docs.gitlab.com/omnibus/settings/backups.html#backup-and-restore-omnibus-gitlab-configuration)
### Level 2: Multiple application servers
By separating components you can see a number of advantages compared to a single-node setup. Namely, you can:
- Increase the number of users
- Enable zero-downtime upgrades
- Increase availability
Additional application nodes will handle frontend traffic, with a load balancer in front to distribute traffic across those nodes. Meanwhile, each application node connects to a shared file server and database systems on the back end. This way, if one of the application servers fails, the workflow is not interrupted.
This configuration is supported in [GitLab Starter, Premium and Ultimate](https://about.gitlab.com/pricing/).
References:
- [High Availability Reference Architectures](#reference-architectures), without HA components
### Level 3: Highly Available
By adding automatic failover for database systems, we can enable higher uptime with an additional layer of complexity.
This configuration is supported in [GitLab Premium and Ultimate](https://about.gitlab.com/pricing/).
References:
- [High Availability Reference Architectures](#reference-architectures)
### Level 4: GitLab Geo
GitLab Geo allows you to replicate your GitLab instance to other geographical locations as a read-only fully operational instance that can also be promoted in case of disaster.
This configuration is supported in [GitLab Premium and Ultimate](https://about.gitlab.com/pricing/).
References:
- [Geo Documentation](../../gitlab-geo/README.html)
- [GitLab Geo with a highly available configuration](../geo/replication/high_availability.html)
## Recommended setups based on number of users ## Recommended setups based on number of users
- 1 - 1000 Users: A single-node [Omnibus](https://docs.gitlab.com/omnibus/) setup with frequent backups. Refer to the [requirements page](../../install/requirements.md) for further details of the specs you will require. - 1 - 1000 Users: A single-node [Omnibus](https://docs.gitlab.com/omnibus/) setup with frequent backups. Refer to the [requirements page](../../install/requirements.md) for further details of the specs you will require.
- 1000 - 10000 Users: A scaled environment based on one of our [Reference Architectures](#reference-architectures), without the HA components applied. This can be a reasonable step towards a fully HA environment.
- 2000 - 50000+ Users: A scaled HA environment based on one of our [Reference Architectures](#reference-architectures) below. - 2000 - 50000+ Users: A scaled HA environment based on one of our [Reference Architectures](#reference-architectures) below.
## GitLab components and configuration instructions ## GitLab components and configuration instructions
......
...@@ -626,7 +626,7 @@ EE::Gitlab::LDAP::Sync::Group.execute_all_providers(group) ...@@ -626,7 +626,7 @@ EE::Gitlab::LDAP::Sync::Group.execute_all_providers(group)
# Run a GroupSync for a single group (10.6+) # Run a GroupSync for a single group (10.6+)
group = Group.find_by(name: 'my_gitlab_group') group = Group.find_by(name: 'my_gitlab_group')
EE::Gitlab::Auth::LDAP::Sync::Group.execute_all_providers(group) EE::Gitlab::Auth::Ldap::Sync::Group.execute_all_providers(group)
# Query an LDAP group directly (10.6-) # Query an LDAP group directly (10.6-)
adapter = Gitlab::LDAP::Adapter.new('ldapmain') # If `main` is the LDAP provider adapter = Gitlab::LDAP::Adapter.new('ldapmain') # If `main` is the LDAP provider
...@@ -635,20 +635,20 @@ ldap_group.member_dns ...@@ -635,20 +635,20 @@ ldap_group.member_dns
ldap_group.member_uids ldap_group.member_uids
# Query an LDAP group directly (10.6+) # Query an LDAP group directly (10.6+)
adapter = Gitlab::Auth::LDAP::Adapter.new('ldapmain') # If `main` is the LDAP provider adapter = Gitlab::Auth::Ldap::Adapter.new('ldapmain') # If `main` is the LDAP provider
ldap_group = EE::Gitlab::Auth::LDAP::Group.find_by_cn('group_cn_here', adapter) ldap_group = EE::Gitlab::Auth::Ldap::Group.find_by_cn('group_cn_here', adapter)
ldap_group.member_dns ldap_group.member_dns
ldap_group.member_uids ldap_group.member_uids
# Lookup a particular user (10.6+) # Lookup a particular user (10.6+)
# This could expose potential errors connecting to and/or querying LDAP that may seem to # This could expose potential errors connecting to and/or querying LDAP that may seem to
# fail silently in the GitLab UI # fail silently in the GitLab UI
adapter = Gitlab::Auth::LDAP::Adapter.new('ldapmain') # If `main` is the LDAP provider adapter = Gitlab::Auth::Ldap::Adapter.new('ldapmain') # If `main` is the LDAP provider
user = Gitlab::Auth::LDAP::Person.find_by_uid('<username>',adapter) user = Gitlab::Auth::Ldap::Person.find_by_uid('<username>',adapter)
# Query the LDAP server directly (10.6+) # Query the LDAP server directly (10.6+)
## For an example, see https://gitlab.com/gitlab-org/gitlab/blob/master/ee/lib/ee/gitlab/auth/ldap/adapter.rb ## For an example, see https://gitlab.com/gitlab-org/gitlab/blob/master/ee/lib/ee/gitlab/auth/ldap/adapter.rb
adapter = Gitlab::Auth::LDAP::Adapter.new('ldapmain') adapter = Gitlab::Auth::Ldap::Adapter.new('ldapmain')
options = { options = {
# the :base is required # the :base is required
# use adapter.config.base for the base or .group_base for the group_base # use adapter.config.base for the base or .group_base for the group_base
......
...@@ -188,7 +188,7 @@ External users could steal secret variables from the parent project by modifying ...@@ -188,7 +188,7 @@ External users could steal secret variables from the parent project by modifying
We're discussing a secure solution of running pipelines for merge requests We're discussing a secure solution of running pipelines for merge requests
that are submitted from forked projects, that are submitted from forked projects,
see [the issue about the permission extension](https://gitlab.com/gitlab-org/gitlab-foss/issues/23902). see [the issue about the permission extension](https://gitlab.com/gitlab-org/gitlab/-/issues/11934).
## Additional predefined variables ## Additional predefined variables
......
...@@ -88,7 +88,7 @@ module Gitlab ...@@ -88,7 +88,7 @@ module Gitlab
else else
# If no user is provided, try LDAP. # If no user is provided, try LDAP.
# LDAP users are only authenticated via LDAP # LDAP users are only authenticated via LDAP
authenticators << Gitlab::Auth::LDAP::Authentication authenticators << Gitlab::Auth::Ldap::Authentication
end end
authenticators.compact! authenticators.compact!
...@@ -134,7 +134,7 @@ module Gitlab ...@@ -134,7 +134,7 @@ module Gitlab
end end
def authenticate_using_internal_or_ldap_password? def authenticate_using_internal_or_ldap_password?
Gitlab::CurrentSettings.password_authentication_enabled_for_git? || Gitlab::Auth::LDAP::Config.enabled? Gitlab::CurrentSettings.password_authentication_enabled_for_git? || Gitlab::Auth::Ldap::Config.enabled?
end end
def service_request_check(login, password, project) def service_request_check(login, password, project)
......
...@@ -6,14 +6,14 @@ ...@@ -6,14 +6,14 @@
# #
module Gitlab module Gitlab
module Auth module Auth
module LDAP module Ldap
class Access class Access
prepend_if_ee('::EE::Gitlab::Auth::LDAP::Access') # rubocop: disable Cop/InjectEnterpriseEditionModule prepend_if_ee('::EE::Gitlab::Auth::Ldap::Access') # rubocop: disable Cop/InjectEnterpriseEditionModule
attr_reader :provider, :user, :ldap_identity attr_reader :provider, :user, :ldap_identity
def self.open(user, &block) def self.open(user, &block)
Gitlab::Auth::LDAP::Adapter.open(user.ldap_identity.provider) do |adapter| Gitlab::Auth::Ldap::Adapter.open(user.ldap_identity.provider) do |adapter|
block.call(self.new(user, adapter)) block.call(self.new(user, adapter))
end end
end end
...@@ -50,7 +50,7 @@ module Gitlab ...@@ -50,7 +50,7 @@ module Gitlab
end end
# Block user in GitLab if they were blocked in AD # Block user in GitLab if they were blocked in AD
if Gitlab::Auth::LDAP::Person.disabled_via_active_directory?(ldap_identity.extern_uid, adapter) if Gitlab::Auth::Ldap::Person.disabled_via_active_directory?(ldap_identity.extern_uid, adapter)
block_user(user, 'is disabled in Active Directory') block_user(user, 'is disabled in Active Directory')
false false
else else
...@@ -62,7 +62,7 @@ module Gitlab ...@@ -62,7 +62,7 @@ module Gitlab
block_user(user, 'does not exist anymore') block_user(user, 'does not exist anymore')
false false
end end
rescue LDAPConnectionError rescue LdapConnectionError
false false
end end
...@@ -73,11 +73,11 @@ module Gitlab ...@@ -73,11 +73,11 @@ module Gitlab
private private
def adapter def adapter
@adapter ||= Gitlab::Auth::LDAP::Adapter.new(provider) @adapter ||= Gitlab::Auth::Ldap::Adapter.new(provider)
end end
def ldap_config def ldap_config
Gitlab::Auth::LDAP::Config.new(provider) Gitlab::Auth::Ldap::Config.new(provider)
end end
def ldap_user def ldap_user
...@@ -87,7 +87,7 @@ module Gitlab ...@@ -87,7 +87,7 @@ module Gitlab
end end
def find_ldap_user def find_ldap_user
Gitlab::Auth::LDAP::Person.find_by_dn(ldap_identity.extern_uid, adapter) Gitlab::Auth::Ldap::Person.find_by_dn(ldap_identity.extern_uid, adapter)
end end
def block_user(user, reason) def block_user(user, reason)
......
...@@ -2,9 +2,9 @@ ...@@ -2,9 +2,9 @@
module Gitlab module Gitlab
module Auth module Auth
module LDAP module Ldap
class Adapter class Adapter
prepend_if_ee('::EE::Gitlab::Auth::LDAP::Adapter') # rubocop: disable Cop/InjectEnterpriseEditionModule prepend_if_ee('::EE::Gitlab::Auth::Ldap::Adapter') # rubocop: disable Cop/InjectEnterpriseEditionModule
SEARCH_RETRY_FACTOR = [1, 1, 2, 3].freeze SEARCH_RETRY_FACTOR = [1, 1, 2, 3].freeze
MAX_SEARCH_RETRIES = Rails.env.test? ? 1 : SEARCH_RETRY_FACTOR.size.freeze MAX_SEARCH_RETRIES = Rails.env.test? ? 1 : SEARCH_RETRY_FACTOR.size.freeze
...@@ -18,7 +18,7 @@ module Gitlab ...@@ -18,7 +18,7 @@ module Gitlab
end end
def self.config(provider) def self.config(provider)
Gitlab::Auth::LDAP::Config.new(provider) Gitlab::Auth::Ldap::Config.new(provider)
end end
def initialize(provider, ldap = nil) def initialize(provider, ldap = nil)
...@@ -27,7 +27,7 @@ module Gitlab ...@@ -27,7 +27,7 @@ module Gitlab
end end
def config def config
Gitlab::Auth::LDAP::Config.new(provider) Gitlab::Auth::Ldap::Config.new(provider)
end end
def users(fields, value, limit = nil) def users(fields, value, limit = nil)
...@@ -75,7 +75,7 @@ module Gitlab ...@@ -75,7 +75,7 @@ module Gitlab
renew_connection_adapter renew_connection_adapter
retry retry
else else
raise LDAPConnectionError, error_message raise LdapConnectionError, error_message
end end
end end
...@@ -91,13 +91,13 @@ module Gitlab ...@@ -91,13 +91,13 @@ module Gitlab
end end
entries.map do |entry| entries.map do |entry|
Gitlab::Auth::LDAP::Person.new(entry, provider) Gitlab::Auth::Ldap::Person.new(entry, provider)
end end
end end
def user_options(fields, value, limit) def user_options(fields, value, limit)
options = { options = {
attributes: Gitlab::Auth::LDAP::Person.ldap_attributes(config), attributes: Gitlab::Auth::Ldap::Person.ldap_attributes(config),
base: config.base base: config.base
} }
......
...@@ -4,10 +4,10 @@ ...@@ -4,10 +4,10 @@
# #
module Gitlab module Gitlab
module Auth module Auth
module LDAP module Ldap
class AuthHash < Gitlab::Auth::OAuth::AuthHash class AuthHash < Gitlab::Auth::OAuth::AuthHash
def uid def uid
@uid ||= Gitlab::Auth::LDAP::Person.normalize_dn(super) @uid ||= Gitlab::Auth::Ldap::Person.normalize_dn(super)
end end
def username def username
...@@ -42,7 +42,7 @@ module Gitlab ...@@ -42,7 +42,7 @@ module Gitlab
end end
def ldap_config def ldap_config
@ldap_config ||= Gitlab::Auth::LDAP::Config.new(self.provider) @ldap_config ||= Gitlab::Auth::Ldap::Config.new(self.provider)
end end
end end
end end
......
...@@ -8,10 +8,10 @@ ...@@ -8,10 +8,10 @@
module Gitlab module Gitlab
module Auth module Auth
module LDAP module Ldap
class Authentication < Gitlab::Auth::OAuth::Authentication class Authentication < Gitlab::Auth::OAuth::Authentication
def self.login(login, password) def self.login(login, password)
return unless Gitlab::Auth::LDAP::Config.enabled? return unless Gitlab::Auth::Ldap::Config.enabled?
return unless login.present? && password.present? return unless login.present? && password.present?
# return found user that was authenticated by first provider for given login credentials # return found user that was authenticated by first provider for given login credentials
...@@ -22,7 +22,7 @@ module Gitlab ...@@ -22,7 +22,7 @@ module Gitlab
end end
def self.providers def self.providers
Gitlab::Auth::LDAP::Config.providers Gitlab::Auth::Ldap::Config.providers
end end
def login(login, password) def login(login, password)
...@@ -33,7 +33,7 @@ module Gitlab ...@@ -33,7 +33,7 @@ module Gitlab
) )
return unless result return unless result
@user = Gitlab::Auth::LDAP::User.find_by_uid_and_provider(result.dn, provider) @user = Gitlab::Auth::Ldap::User.find_by_uid_and_provider(result.dn, provider)
end end
def adapter def adapter
...@@ -41,7 +41,7 @@ module Gitlab ...@@ -41,7 +41,7 @@ module Gitlab
end end
def config def config
Gitlab::Auth::LDAP::Config.new(provider) Gitlab::Auth::Ldap::Config.new(provider)
end end
def user_filter(login) def user_filter(login)
......
...@@ -3,9 +3,9 @@ ...@@ -3,9 +3,9 @@
# Load a specific server configuration # Load a specific server configuration
module Gitlab module Gitlab
module Auth module Auth
module LDAP module Ldap
class Config class Config
prepend_if_ee('::EE::Gitlab::Auth::LDAP::Config') # rubocop: disable Cop/InjectEnterpriseEditionModule prepend_if_ee('::EE::Gitlab::Auth::Ldap::Config') # rubocop: disable Cop/InjectEnterpriseEditionModule
NET_LDAP_ENCRYPTION_METHOD = { NET_LDAP_ENCRYPTION_METHOD = {
simple_tls: :simple_tls, simple_tls: :simple_tls,
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
# class also helps take care of that. # class also helps take care of that.
module Gitlab module Gitlab
module Auth module Auth
module LDAP module Ldap
class DN class DN
FormatError = Class.new(StandardError) FormatError = Class.new(StandardError)
MalformedError = Class.new(FormatError) MalformedError = Class.new(FormatError)
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
module Gitlab module Gitlab
module Auth module Auth
module LDAP module Ldap
LDAPConnectionError = Class.new(StandardError) LdapConnectionError = Class.new(StandardError)
end end
end end
end end
...@@ -2,9 +2,9 @@ ...@@ -2,9 +2,9 @@
module Gitlab module Gitlab
module Auth module Auth
module LDAP module Ldap
class Person class Person
prepend_if_ee('::EE::Gitlab::Auth::LDAP::Person') # rubocop: disable Cop/InjectEnterpriseEditionModule prepend_if_ee('::EE::Gitlab::Auth::Ldap::Person') # rubocop: disable Cop/InjectEnterpriseEditionModule
# Active Directory-specific LDAP filter that checks if bit 2 of the # Active Directory-specific LDAP filter that checks if bit 2 of the
# userAccountControl attribute is set. # userAccountControl attribute is set.
...@@ -45,8 +45,8 @@ module Gitlab ...@@ -45,8 +45,8 @@ module Gitlab
end end
def self.normalize_dn(dn) def self.normalize_dn(dn)
::Gitlab::Auth::LDAP::DN.new(dn).to_normalized_s ::Gitlab::Auth::Ldap::DN.new(dn).to_normalized_s
rescue ::Gitlab::Auth::LDAP::DN::FormatError => e rescue ::Gitlab::Auth::Ldap::DN::FormatError => e
Rails.logger.info("Returning original DN \"#{dn}\" due to error during normalization attempt: #{e.message}") # rubocop:disable Gitlab/RailsLogger Rails.logger.info("Returning original DN \"#{dn}\" due to error during normalization attempt: #{e.message}") # rubocop:disable Gitlab/RailsLogger
dn dn
...@@ -57,8 +57,8 @@ module Gitlab ...@@ -57,8 +57,8 @@ module Gitlab
# 1. Excess spaces are stripped # 1. Excess spaces are stripped
# 2. The string is downcased (for case-insensitivity) # 2. The string is downcased (for case-insensitivity)
def self.normalize_uid(uid) def self.normalize_uid(uid)
::Gitlab::Auth::LDAP::DN.normalize_value(uid) ::Gitlab::Auth::Ldap::DN.normalize_value(uid)
rescue ::Gitlab::Auth::LDAP::DN::FormatError => e rescue ::Gitlab::Auth::Ldap::DN::FormatError => e
Rails.logger.info("Returning original UID \"#{uid}\" due to error during normalization attempt: #{e.message}") # rubocop:disable Gitlab/RailsLogger Rails.logger.info("Returning original UID \"#{uid}\" due to error during normalization attempt: #{e.message}") # rubocop:disable Gitlab/RailsLogger
uid uid
...@@ -103,7 +103,7 @@ module Gitlab ...@@ -103,7 +103,7 @@ module Gitlab
attr_reader :entry attr_reader :entry
def config def config
@config ||= Gitlab::Auth::LDAP::Config.new(provider) @config ||= Gitlab::Auth::Ldap::Config.new(provider)
end end
# Using the LDAP attributes configuration, find and return the first # Using the LDAP attributes configuration, find and return the first
......
...@@ -8,10 +8,10 @@ ...@@ -8,10 +8,10 @@
# #
module Gitlab module Gitlab
module Auth module Auth
module LDAP module Ldap
class User < Gitlab::Auth::OAuth::User class User < Gitlab::Auth::OAuth::User
extend ::Gitlab::Utils::Override extend ::Gitlab::Utils::Override
prepend_if_ee('::EE::Gitlab::Auth::LDAP::User') # rubocop: disable Cop/InjectEnterpriseEditionModule prepend_if_ee('::EE::Gitlab::Auth::Ldap::User') # rubocop: disable Cop/InjectEnterpriseEditionModule
class << self class << self
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
...@@ -46,7 +46,7 @@ module Gitlab ...@@ -46,7 +46,7 @@ module Gitlab
end end
def allowed? def allowed?
Gitlab::Auth::LDAP::Access.allowed?(gl_user) Gitlab::Auth::Ldap::Access.allowed?(gl_user)
end end
def valid_sign_in? def valid_sign_in?
...@@ -54,11 +54,11 @@ module Gitlab ...@@ -54,11 +54,11 @@ module Gitlab
end end
def ldap_config def ldap_config
Gitlab::Auth::LDAP::Config.new(auth_hash.provider) Gitlab::Auth::Ldap::Config.new(auth_hash.provider)
end end
def auth_hash=(auth_hash) def auth_hash=(auth_hash)
@auth_hash = Gitlab::Auth::LDAP::AuthHash.new(auth_hash) @auth_hash = Gitlab::Auth::Ldap::AuthHash.new(auth_hash)
end end
end end
end end
......
...@@ -18,7 +18,7 @@ module Gitlab ...@@ -18,7 +18,7 @@ module Gitlab
authenticator = authenticator =
case provider case provider
when /^ldap/ when /^ldap/
Gitlab::Auth::LDAP::Authentication Gitlab::Auth::Ldap::Authentication
when 'database' when 'database'
Gitlab::Auth::Database::Authentication Gitlab::Auth::Database::Authentication
end end
...@@ -60,8 +60,8 @@ module Gitlab ...@@ -60,8 +60,8 @@ module Gitlab
def self.config_for(name) def self.config_for(name)
name = name.to_s name = name.to_s
if ldap_provider?(name) if ldap_provider?(name)
if Gitlab::Auth::LDAP::Config.valid_provider?(name) if Gitlab::Auth::Ldap::Config.valid_provider?(name)
Gitlab::Auth::LDAP::Config.new(name).options Gitlab::Auth::Ldap::Config.new(name).options
else else
nil nil
end end
......
...@@ -111,7 +111,7 @@ module Gitlab ...@@ -111,7 +111,7 @@ module Gitlab
def find_or_build_ldap_user def find_or_build_ldap_user
return unless ldap_person return unless ldap_person
user = Gitlab::Auth::LDAP::User.find_by_uid_and_provider(ldap_person.dn, ldap_person.provider) user = Gitlab::Auth::Ldap::User.find_by_uid_and_provider(ldap_person.dn, ldap_person.provider)
if user if user
log.info "LDAP account found for user #{user.username}. Building new #{auth_hash.provider} identity." log.info "LDAP account found for user #{user.username}. Building new #{auth_hash.provider} identity."
return user return user
...@@ -141,8 +141,8 @@ module Gitlab ...@@ -141,8 +141,8 @@ module Gitlab
return @ldap_person if defined?(@ldap_person) return @ldap_person if defined?(@ldap_person)
# Look for a corresponding person with same uid in any of the configured LDAP providers # Look for a corresponding person with same uid in any of the configured LDAP providers
Gitlab::Auth::LDAP::Config.providers.each do |provider| Gitlab::Auth::Ldap::Config.providers.each do |provider|
adapter = Gitlab::Auth::LDAP::Adapter.new(provider) adapter = Gitlab::Auth::Ldap::Adapter.new(provider)
@ldap_person = find_ldap_person(auth_hash, adapter) @ldap_person = find_ldap_person(auth_hash, adapter)
break if @ldap_person break if @ldap_person
end end
...@@ -150,15 +150,15 @@ module Gitlab ...@@ -150,15 +150,15 @@ module Gitlab
end end
def find_ldap_person(auth_hash, adapter) def find_ldap_person(auth_hash, adapter)
Gitlab::Auth::LDAP::Person.find_by_uid(auth_hash.uid, adapter) || Gitlab::Auth::Ldap::Person.find_by_uid(auth_hash.uid, adapter) ||
Gitlab::Auth::LDAP::Person.find_by_email(auth_hash.uid, adapter) || Gitlab::Auth::Ldap::Person.find_by_email(auth_hash.uid, adapter) ||
Gitlab::Auth::LDAP::Person.find_by_dn(auth_hash.uid, adapter) Gitlab::Auth::Ldap::Person.find_by_dn(auth_hash.uid, adapter)
rescue Gitlab::Auth::LDAP::LDAPConnectionError rescue Gitlab::Auth::Ldap::LdapConnectionError
nil nil
end end
def ldap_config def ldap_config
Gitlab::Auth::LDAP::Config.new(ldap_person.provider) if ldap_person Gitlab::Auth::Ldap::Config.new(ldap_person.provider) if ldap_person
end end
def needs_blocking? def needs_blocking?
......
...@@ -33,7 +33,7 @@ module Gitlab ...@@ -33,7 +33,7 @@ module Gitlab
return false unless can_access_git? return false unless can_access_git?
if user.requires_ldap_check? && user.try_obtain_ldap_lease if user.requires_ldap_check? && user.try_obtain_ldap_lease
return false unless Gitlab::Auth::LDAP::Access.allowed?(user) return false unless Gitlab::Auth::Ldap::Access.allowed?(user)
end end
true true
......
...@@ -6,7 +6,7 @@ module SystemCheck ...@@ -6,7 +6,7 @@ module SystemCheck
set_name 'LDAP:' set_name 'LDAP:'
def multi_check def multi_check
if Gitlab::Auth::LDAP::Config.enabled? if Gitlab::Auth::Ldap::Config.enabled?
# Only show up to 100 results because LDAP directories can be very big. # Only show up to 100 results because LDAP directories can be very big.
# This setting only affects the `rake gitlab:check` script. # This setting only affects the `rake gitlab:check` script.
limit = ENV['LDAP_CHECK_LIMIT'] limit = ENV['LDAP_CHECK_LIMIT']
...@@ -21,13 +21,13 @@ module SystemCheck ...@@ -21,13 +21,13 @@ module SystemCheck
private private
def check_ldap(limit) def check_ldap(limit)
servers = Gitlab::Auth::LDAP::Config.providers servers = Gitlab::Auth::Ldap::Config.providers
servers.each do |server| servers.each do |server|
$stdout.puts "Server: #{server}" $stdout.puts "Server: #{server}"
begin begin
Gitlab::Auth::LDAP::Adapter.open(server) do |adapter| Gitlab::Auth::Ldap::Adapter.open(server) do |adapter|
check_ldap_auth(adapter) check_ldap_auth(adapter)
$stdout.puts "LDAP users with access to your GitLab server (only showing the first #{limit} results)" $stdout.puts "LDAP users with access to your GitLab server (only showing the first #{limit} results)"
......
...@@ -13,7 +13,7 @@ namespace :gitlab do ...@@ -13,7 +13,7 @@ namespace :gitlab do
print "#{user.name} (#{user.ldap_identity.extern_uid}) ..." print "#{user.name} (#{user.ldap_identity.extern_uid}) ..."
if Gitlab::Auth::LDAP::Access.allowed?(user) if Gitlab::Auth::Ldap::Access.allowed?(user)
puts " [OK]".color(:green) puts " [OK]".color(:green)
else else
if block_flag if block_flag
......
...@@ -1550,13 +1550,13 @@ msgstr "" ...@@ -1550,13 +1550,13 @@ msgstr ""
msgid "Advanced" msgid "Advanced"
msgstr "" msgstr ""
msgid "Advanced permissions, Large File Storage and Two-Factor authentication settings." msgid "Advanced Settings"
msgstr "" msgstr ""
msgid "Advanced search functionality" msgid "Advanced permissions, Large File Storage and Two-Factor authentication settings."
msgstr "" msgstr ""
msgid "Advanced settings" msgid "Advanced search functionality"
msgstr "" msgstr ""
msgid "After a successful password update you will be redirected to login screen." msgid "After a successful password update you will be redirected to login screen."
...@@ -3991,6 +3991,9 @@ msgstr "" ...@@ -3991,6 +3991,9 @@ msgstr ""
msgid "Closed this %{quick_action_target}." msgid "Closed this %{quick_action_target}."
msgstr "" msgstr ""
msgid "Closed: %{closedIssuesCount}"
msgstr ""
msgid "Closes this %{quick_action_target}." msgid "Closes this %{quick_action_target}."
msgstr "" msgstr ""
...@@ -4021,6 +4024,9 @@ msgstr "" ...@@ -4021,6 +4024,9 @@ msgstr ""
msgid "ClusterIntegration|%{appList} was successfully installed on your Kubernetes cluster" msgid "ClusterIntegration|%{appList} was successfully installed on your Kubernetes cluster"
msgstr "" msgstr ""
msgid "ClusterIntegration|%{external_ip}.nip.io"
msgstr ""
msgid "ClusterIntegration|%{title} uninstalled successfully." msgid "ClusterIntegration|%{title} uninstalled successfully."
msgstr "" msgstr ""
...@@ -4057,7 +4063,7 @@ msgstr "" ...@@ -4057,7 +4063,7 @@ msgstr ""
msgid "ClusterIntegration|Adding an integration will share the cluster across all projects." msgid "ClusterIntegration|Adding an integration will share the cluster across all projects."
msgstr "" msgstr ""
msgid "ClusterIntegration|Advanced options on this Kubernetes cluster's integration" msgid "ClusterIntegration|Advanced options on this Kubernetes clusters integration"
msgstr "" msgstr ""
msgid "ClusterIntegration|All data not committed to GitLab will be deleted and cannot be restored." msgid "ClusterIntegration|All data not committed to GitLab will be deleted and cannot be restored."
...@@ -4093,9 +4099,6 @@ msgstr "" ...@@ -4093,9 +4099,6 @@ msgstr ""
msgid "ClusterIntegration|Any running pipelines will be canceled." msgid "ClusterIntegration|Any running pipelines will be canceled."
msgstr "" msgstr ""
msgid "ClusterIntegration|Applications"
msgstr ""
msgid "ClusterIntegration|Apply for credit" msgid "ClusterIntegration|Apply for credit"
msgstr "" msgstr ""
...@@ -4147,9 +4150,6 @@ msgstr "" ...@@ -4147,9 +4150,6 @@ msgstr ""
msgid "ClusterIntegration|Cluster being created" msgid "ClusterIntegration|Cluster being created"
msgstr "" msgstr ""
msgid "ClusterIntegration|Cluster health"
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)" msgid "ClusterIntegration|Cluster management project (alpha)"
msgstr "" msgstr ""
...@@ -4342,7 +4342,7 @@ msgstr "" ...@@ -4342,7 +4342,7 @@ msgstr ""
msgid "ClusterIntegration|If you do not wish to delete all associated GitLab resources, you can simply remove the integration." msgid "ClusterIntegration|If you do not wish to delete all associated GitLab resources, you can simply remove the integration."
msgstr "" msgstr ""
msgid "ClusterIntegration|In order to view the health of your cluster, you must first install Prometheus below." msgid "ClusterIntegration|In order to view the health of your cluster, you must first install Prometheus in the Applications tab."
msgstr "" msgstr ""
msgid "ClusterIntegration|Ingress" msgid "ClusterIntegration|Ingress"
...@@ -4366,9 +4366,6 @@ msgstr "" ...@@ -4366,9 +4366,6 @@ msgstr ""
msgid "ClusterIntegration|Integrate Kubernetes cluster automation" msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
msgstr "" msgstr ""
msgid "ClusterIntegration|Integration status"
msgstr ""
msgid "ClusterIntegration|Issuer Email" msgid "ClusterIntegration|Issuer Email"
msgstr "" msgstr ""
...@@ -4405,9 +4402,6 @@ msgstr "" ...@@ -4405,9 +4402,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes cluster" msgid "ClusterIntegration|Kubernetes cluster"
msgstr "" msgstr ""
msgid "ClusterIntegration|Kubernetes cluster details"
msgstr ""
msgid "ClusterIntegration|Kubernetes cluster is being created..." msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr "" msgstr ""
...@@ -4558,6 +4552,9 @@ msgstr "" ...@@ -4558,6 +4552,9 @@ msgstr ""
msgid "ClusterIntegration|Prometheus is an open-source monitoring system with %{gitlabIntegrationLink} to monitor deployed applications." msgid "ClusterIntegration|Prometheus is an open-source monitoring system with %{gitlabIntegrationLink} to monitor deployed applications."
msgstr "" msgstr ""
msgid "ClusterIntegration|Provider details"
msgstr ""
msgid "ClusterIntegration|Provision Role ARN" msgid "ClusterIntegration|Provision Role ARN"
msgstr "" msgstr ""
...@@ -5570,6 +5567,9 @@ msgstr "" ...@@ -5570,6 +5567,9 @@ msgstr ""
msgid "Copy commit SHA" msgid "Copy commit SHA"
msgstr "" msgstr ""
msgid "Copy evidence SHA"
msgstr ""
msgid "Copy file contents" msgid "Copy file contents"
msgstr "" msgstr ""
...@@ -5630,9 +5630,6 @@ msgstr "" ...@@ -5630,9 +5630,6 @@ msgstr ""
msgid "Could not create group" msgid "Could not create group"
msgstr "" msgstr ""
msgid "Could not create issue"
msgstr ""
msgid "Could not create project" msgid "Could not create project"
msgstr "" msgstr ""
...@@ -5642,9 +5639,6 @@ msgstr "" ...@@ -5642,9 +5639,6 @@ msgstr ""
msgid "Could not delete chat nickname %{chat_name}." msgid "Could not delete chat nickname %{chat_name}."
msgstr "" msgstr ""
msgid "Could not fetch projects"
msgstr ""
msgid "Could not find design" msgid "Could not find design"
msgstr "" msgstr ""
...@@ -7840,6 +7834,9 @@ msgstr "" ...@@ -7840,6 +7834,9 @@ msgstr ""
msgid "Epics|Something went wrong while creating child epics." msgid "Epics|Something went wrong while creating child epics."
msgstr "" msgstr ""
msgid "Epics|Something went wrong while creating issue."
msgstr ""
msgid "Epics|Something went wrong while fetching child epics." msgid "Epics|Something went wrong while fetching child epics."
msgstr "" msgstr ""
...@@ -10288,6 +10285,9 @@ msgstr "" ...@@ -10288,6 +10285,9 @@ msgstr ""
msgid "Header message" msgid "Header message"
msgstr "" msgstr ""
msgid "Health"
msgstr ""
msgid "Health Check" msgid "Health Check"
msgstr "" msgstr ""
...@@ -13178,6 +13178,9 @@ msgstr "" ...@@ -13178,6 +13178,9 @@ msgstr ""
msgid "No licenses found." msgid "No licenses found."
msgstr "" msgstr ""
msgid "No matches found"
msgstr ""
msgid "No matching labels" msgid "No matching labels"
msgstr "" msgstr ""
...@@ -13636,6 +13639,9 @@ msgstr "" ...@@ -13636,6 +13639,9 @@ msgstr ""
msgid "Open source software to collaborate on code" msgid "Open source software to collaborate on code"
msgstr "" msgstr ""
msgid "Open: %{openIssuesCount}"
msgstr ""
msgid "Open: %{open} • Closed: %{closed}" msgid "Open: %{open} • Closed: %{closed}"
msgstr "" msgstr ""
...@@ -18320,6 +18326,9 @@ msgstr "" ...@@ -18320,6 +18326,9 @@ msgstr ""
msgid "Something went wrong while fetching projects" msgid "Something went wrong while fetching projects"
msgstr "" msgstr ""
msgid "Something went wrong while fetching projects."
msgstr ""
msgid "Something went wrong while fetching related merge requests." msgid "Something went wrong while fetching related merge requests."
msgstr "" msgstr ""
......
...@@ -10,17 +10,35 @@ module QA ...@@ -10,17 +10,35 @@ module QA
element :ingress_ip_address, 'id="ingress-endpoint"' # rubocop:disable QA/ElementWithPattern element :ingress_ip_address, 'id="ingress-endpoint"' # rubocop:disable QA/ElementWithPattern
end end
view 'app/views/clusters/clusters/_form.html.haml' do view 'app/views/clusters/clusters/_gitlab_integration_form.html.haml' do
element :integration_status_toggle, required: true element :integration_status_toggle, required: true
element :base_domain_field, required: true element :base_domain_field, required: true
element :save_changes_button, required: true element :save_changes_button, required: true
end end
view 'app/views/clusters/clusters/_details_tab.html.haml' do
element :details, required: true
end
view 'app/views/clusters/clusters/_applications_tab.html.haml' do
element :applications, required: true
end
view 'app/assets/javascripts/clusters/components/application_row.vue' do view 'app/assets/javascripts/clusters/components/application_row.vue' do
element :install_button element :install_button
element :uninstall_button element :uninstall_button
end end
def open_details
has_element?(:details, wait: 30)
click_element :details
end
def open_applications
has_element?(:applications, wait: 30)
click_element :applications
end
def install!(application_name) def install!(application_name)
within_element(application_name) do within_element(application_name) do
has_element?(:install_button, application: application_name, wait: 30) has_element?(:install_button, application: application_name, wait: 30)
......
...@@ -38,6 +38,9 @@ module QA ...@@ -38,6 +38,9 @@ module QA
# We must wait a few seconds for permissions to be set up correctly for new cluster # We must wait a few seconds for permissions to be set up correctly for new cluster
sleep 10 sleep 10
# Open applications tab
show.open_applications
# Helm must be installed before everything else # Helm must be installed before everything else
show.install!(:helm) show.install!(:helm)
show.await_installed(:helm) show.await_installed(:helm)
...@@ -52,6 +55,8 @@ module QA ...@@ -52,6 +55,8 @@ module QA
if @install_ingress if @install_ingress
populate(:ingress_ip) populate(:ingress_ip)
show.open_details
show.set_domain("#{ingress_ip}.nip.io") show.set_domain("#{ingress_ip}.nip.io")
show.save_domain show.save_domain
end end
......
...@@ -57,97 +57,3 @@ function echoinfo() { ...@@ -57,97 +57,3 @@ function echoinfo() {
printf "\033[0;33m%s\n\033[0m" "${1}" >&2; printf "\033[0;33m%s\n\033[0m" "${1}" >&2;
fi fi
} }
function get_job_id() {
local job_name="${1}"
local query_string="${2:+&${2}}"
local api_token="${API_TOKEN-${GITLAB_BOT_MULTI_PROJECT_PIPELINE_POLLING_TOKEN}}"
if [ -z "${api_token}" ]; then
echoerr "Please provide an API token with \$API_TOKEN or \$GITLAB_BOT_MULTI_PROJECT_PIPELINE_POLLING_TOKEN."
return
fi
local max_page=3
local page=1
while true; do
local url="https://gitlab.com/api/v4/projects/${CI_PROJECT_ID}/pipelines/${CI_PIPELINE_ID}/jobs?per_page=100&page=${page}${query_string}"
echoinfo "GET ${url}"
local job_id
job_id=$(curl --silent --show-error --header "PRIVATE-TOKEN: ${api_token}" "${url}" | jq "map(select(.name == \"${job_name}\")) | map(.id) | last")
[[ "${job_id}" == "null" && "${page}" -lt "$max_page" ]] || break
let "page++"
done
if [[ "${job_id}" == "" ]]; then
echoerr "The '${job_name}' job ID couldn't be retrieved!"
else
echoinfo "The '${job_name}' job ID is ${job_id}"
echo "${job_id}"
fi
}
function play_job() {
local job_name="${1}"
local job_id
job_id=$(get_job_id "${job_name}" "scope=manual");
if [ -z "${job_id}" ]; then return; fi
local api_token="${API_TOKEN-${GITLAB_BOT_MULTI_PROJECT_PIPELINE_POLLING_TOKEN}}"
if [ -z "${api_token}" ]; then
echoerr "Please provide an API token with \$API_TOKEN or \$GITLAB_BOT_MULTI_PROJECT_PIPELINE_POLLING_TOKEN."
return
fi
local url="https://gitlab.com/api/v4/projects/${CI_PROJECT_ID}/jobs/${job_id}/play"
echoinfo "POST ${url}"
local job_url
job_url=$(curl --silent --show-error --request POST --header "PRIVATE-TOKEN: ${api_token}" "${url}" | jq ".web_url")
echoinfo "Manual job '${job_name}' started at: ${job_url}"
}
function wait_for_job_to_be_done() {
local job_name="${1}"
local query_string="${2}"
local job_id
job_id=$(get_job_id "${job_name}" "${query_string}")
if [ -z "${job_id}" ]; then return; fi
local api_token="${API_TOKEN-${GITLAB_BOT_MULTI_PROJECT_PIPELINE_POLLING_TOKEN}}"
if [ -z "${api_token}" ]; then
echoerr "Please provide an API token with \$API_TOKEN or \$GITLAB_BOT_MULTI_PROJECT_PIPELINE_POLLING_TOKEN."
return
fi
echoinfo "Waiting for the '${job_name}' job to finish..."
local url="https://gitlab.com/api/v4/projects/${CI_PROJECT_ID}/jobs/${job_id}"
echoinfo "GET ${url}"
# In case the job hasn't finished yet. Keep trying until the job times out.
local interval=30
local elapsed_seconds=0
while true; do
local job_status
job_status=$(curl --silent --show-error --header "PRIVATE-TOKEN: ${api_token}" "${url}" | jq ".status" | sed -e s/\"//g)
[[ "${job_status}" == "pending" || "${job_status}" == "running" ]] || break
printf "."
let "elapsed_seconds+=interval"
sleep ${interval}
done
local elapsed_minutes=$((elapsed_seconds / 60))
echoinfo "Waited '${job_name}' for ${elapsed_minutes} minutes."
if [[ "${job_status}" == "failed" ]]; then
echoerr "The '${job_name}' failed."
elif [[ "${job_status}" == "manual" ]]; then
echoinfo "The '${job_name}' is manual."
else
echoinfo "The '${job_name}' passed."
fi
}
...@@ -198,6 +198,46 @@ describe Projects::ReleasesController do ...@@ -198,6 +198,46 @@ describe Projects::ReleasesController do
end end
end end
context 'GET #downloads' do
subject do
get :downloads, params: { namespace_id: project.namespace, project_id: project, tag: tag, filepath: filepath }
end
before do
sign_in(user)
end
let(:release) { create(:release, project: project, tag: tag ) }
let!(:link) { create(:release_link, release: release, name: 'linux-amd64 binaries', filepath: '/binaries/linux-amd64', url: 'https://downloads.example.com/bin/gitlab-linux-amd64') }
let(:tag) { 'v11.9.0-rc2' }
context 'valid filepath' do
let(:filepath) { CGI.escape('/binaries/linux-amd64') }
it 'redirects to the asset direct link' do
subject
expect(response).to redirect_to('https://downloads.example.com/bin/gitlab-linux-amd64')
end
it 'redirects with a status of 302' do
subject
expect(response).to have_gitlab_http_status(:redirect)
end
end
context 'invalid filepath' do
let(:filepath) { CGI.escape('/binaries/win32') }
it 'is not found' do
subject
expect(response).to have_gitlab_http_status(:not_found)
end
end
end
context 'GET #downloads' do context 'GET #downloads' do
subject do subject do
get :downloads, params: { get :downloads, params: {
......
...@@ -17,7 +17,7 @@ describe 'Clusterable > Show page' do ...@@ -17,7 +17,7 @@ describe 'Clusterable > Show page' do
it 'allow the user to set domain' do it 'allow the user to set domain' do
visit cluster_path visit cluster_path
within '#cluster-integration' do within '.js-cluster-integration-form' do
fill_in('cluster_base_domain', with: 'test.com') fill_in('cluster_base_domain', with: 'test.com')
click_on 'Save changes' click_on 'Save changes'
end end
...@@ -34,7 +34,7 @@ describe 'Clusterable > Show page' do ...@@ -34,7 +34,7 @@ describe 'Clusterable > Show page' do
end end
it 'shows help text with the domain as an alternative to custom domain' do it 'shows help text with the domain as an alternative to custom domain' do
within '#cluster-integration' do within '.js-cluster-integration-form' do
expect(find(cluster_ingress_help_text_selector)).not_to match_css(hide_modifier_selector) expect(find(cluster_ingress_help_text_selector)).not_to match_css(hide_modifier_selector)
end end
end end
...@@ -44,7 +44,7 @@ describe 'Clusterable > Show page' do ...@@ -44,7 +44,7 @@ describe 'Clusterable > Show page' do
it 'alternative to custom domain is not shown' do it 'alternative to custom domain is not shown' do
visit cluster_path visit cluster_path
within '#cluster-integration' do within '.js-cluster-integration-form' do
expect(find(cluster_ingress_help_text_selector)).to match_css(hide_modifier_selector) expect(find(cluster_ingress_help_text_selector)).to match_css(hide_modifier_selector)
end end
end end
...@@ -63,7 +63,7 @@ describe 'Clusterable > Show page' do ...@@ -63,7 +63,7 @@ describe 'Clusterable > Show page' do
end end
it 'is not able to edit the name, API url, CA certificate nor token' do it 'is not able to edit the name, API url, CA certificate nor token' do
within('#js-cluster-details') do within('.js-provider-details') do
cluster_name_field = find('.cluster-name') cluster_name_field = find('.cluster-name')
api_url_field = find('#cluster_platform_kubernetes_attributes_api_url') api_url_field = find('#cluster_platform_kubernetes_attributes_api_url')
ca_certificate_field = find('#cluster_platform_kubernetes_attributes_ca_cert') ca_certificate_field = find('#cluster_platform_kubernetes_attributes_ca_cert')
...@@ -77,6 +77,8 @@ describe 'Clusterable > Show page' do ...@@ -77,6 +77,8 @@ describe 'Clusterable > Show page' do
end end
it 'displays GKE information' do it 'displays GKE information' do
click_link 'Advanced Settings'
within('#advanced-settings-section') do within('#advanced-settings-section') do
expect(page).to have_content('Google Kubernetes Engine') expect(page).to have_content('Google Kubernetes Engine')
expect(page).to have_content('Manage your Kubernetes cluster by visiting') expect(page).to have_content('Manage your Kubernetes cluster by visiting')
...@@ -91,7 +93,7 @@ describe 'Clusterable > Show page' do ...@@ -91,7 +93,7 @@ describe 'Clusterable > Show page' do
end end
it 'is able to edit the name, API url, CA certificate and token' do it 'is able to edit the name, API url, CA certificate and token' do
within('#js-cluster-details') do within('.js-provider-details') do
cluster_name_field = find('#cluster_name') cluster_name_field = find('#cluster_name')
api_url_field = find('#cluster_platform_kubernetes_attributes_api_url') api_url_field = find('#cluster_platform_kubernetes_attributes_api_url')
ca_certificate_field = find('#cluster_platform_kubernetes_attributes_ca_cert') ca_certificate_field = find('#cluster_platform_kubernetes_attributes_ca_cert')
...@@ -105,6 +107,8 @@ describe 'Clusterable > Show page' do ...@@ -105,6 +107,8 @@ describe 'Clusterable > Show page' do
end end
it 'does not display GKE information' do it 'does not display GKE information' do
click_link 'Advanced Settings'
within('#advanced-settings-section') do within('#advanced-settings-section') do
expect(page).not_to have_content('Google Kubernetes Engine') expect(page).not_to have_content('Google Kubernetes Engine')
expect(page).not_to have_content('Manage your Kubernetes cluster by visiting') expect(page).not_to have_content('Manage your Kubernetes cluster by visiting')
......
...@@ -17,6 +17,12 @@ shared_examples "installing applications on a cluster" do ...@@ -17,6 +17,12 @@ shared_examples "installing applications on a cluster" do
context 'when cluster is created' do context 'when cluster is created' do
let(:cluster) { create(:cluster, :provided_by_gcp, *cluster_factory_args) } let(:cluster) { create(:cluster, :provided_by_gcp, *cluster_factory_args) }
before do
page.within('.js-edit-cluster-form') do
click_link 'Applications'
end
end
it 'user can install applications' do it 'user can install applications' do
wait_for_requests wait_for_requests
...@@ -29,6 +35,7 @@ shared_examples "installing applications on a cluster" do ...@@ -29,6 +35,7 @@ shared_examples "installing applications on a cluster" do
context 'when user installs Helm' do context 'when user installs Helm' do
before do before do
allow(ClusterInstallAppWorker).to receive(:perform_async) allow(ClusterInstallAppWorker).to receive(:perform_async)
wait_for_requests
page.within('.js-cluster-application-row-helm') do page.within('.js-cluster-application-row-helm') do
page.find(:css, '.js-cluster-application-install-button').click page.find(:css, '.js-cluster-application-install-button').click
......
...@@ -34,7 +34,7 @@ describe 'User Cluster', :js do ...@@ -34,7 +34,7 @@ describe 'User Cluster', :js do
it 'user sees a cluster details page' do it 'user sees a cluster details page' do
subject subject
expect(page).to have_content('Kubernetes cluster integration') expect(page).to have_content('GitLab Integration')
expect(page.find_field('cluster[name]').value).to eq('dev-cluster') expect(page.find_field('cluster[name]').value).to eq('dev-cluster')
expect(page.find_field('cluster[platform_kubernetes_attributes][api_url]').value) expect(page.find_field('cluster[platform_kubernetes_attributes][api_url]').value)
.to have_content('http://example.com') .to have_content('http://example.com')
...@@ -93,7 +93,7 @@ describe 'User Cluster', :js do ...@@ -93,7 +93,7 @@ describe 'User Cluster', :js do
context 'when user disables the cluster' do context 'when user disables the cluster' do
before do before do
page.find(:css, '.js-cluster-enable-toggle-area .js-project-feature-toggle').click page.find(:css, '.js-cluster-enable-toggle-area .js-project-feature-toggle').click
page.within('#cluster-integration') { click_button 'Save changes' } page.within('.js-cluster-integration-form') { click_button 'Save changes' }
end end
it 'user sees the successful message' do it 'user sees the successful message' do
...@@ -105,7 +105,7 @@ describe 'User Cluster', :js do ...@@ -105,7 +105,7 @@ describe 'User Cluster', :js do
before do before do
fill_in 'cluster_name', with: 'my-dev-cluster' fill_in 'cluster_name', with: 'my-dev-cluster'
fill_in 'cluster_platform_kubernetes_attributes_token', with: 'new-token' fill_in 'cluster_platform_kubernetes_attributes_token', with: 'new-token'
page.within('#js-cluster-details') { click_button 'Save changes' } page.within('.js-provider-details') { click_button 'Save changes' }
end end
it 'user sees the successful message' do it 'user sees the successful message' do
...@@ -117,6 +117,7 @@ describe 'User Cluster', :js do ...@@ -117,6 +117,7 @@ describe 'User Cluster', :js do
context 'when user destroys the cluster' do context 'when user destroys the cluster' do
before do before do
click_link 'Advanced Settings'
click_button 'Remove integration and resources' click_button 'Remove integration and resources'
fill_in 'confirm_cluster_name_input', with: cluster.name fill_in 'confirm_cluster_name_input', with: cluster.name
click_button 'Remove integration' click_button 'Remove integration'
......
...@@ -119,7 +119,7 @@ describe 'Gcp Cluster', :js, :do_not_mock_admin_mode do ...@@ -119,7 +119,7 @@ describe 'Gcp Cluster', :js, :do_not_mock_admin_mode do
context 'when user disables the cluster' do context 'when user disables the cluster' do
before do before do
page.find(:css, '.js-cluster-enable-toggle-area .js-project-feature-toggle').click page.find(:css, '.js-cluster-enable-toggle-area .js-project-feature-toggle').click
page.within('#cluster-integration') { click_button 'Save changes' } page.within('.js-cluster-integration-form') { click_button 'Save changes' }
end end
it 'user sees the successful message' do it 'user sees the successful message' do
...@@ -130,7 +130,7 @@ describe 'Gcp Cluster', :js, :do_not_mock_admin_mode do ...@@ -130,7 +130,7 @@ describe 'Gcp Cluster', :js, :do_not_mock_admin_mode do
context 'when user changes cluster parameters' do context 'when user changes cluster parameters' do
before do before do
fill_in 'cluster_platform_kubernetes_attributes_namespace', with: 'my-namespace' fill_in 'cluster_platform_kubernetes_attributes_namespace', with: 'my-namespace'
page.within('#js-cluster-details') { click_button 'Save changes' } page.within('.js-provider-details') { click_button 'Save changes' }
end end
it 'user sees the successful message' do it 'user sees the successful message' do
...@@ -141,6 +141,7 @@ describe 'Gcp Cluster', :js, :do_not_mock_admin_mode do ...@@ -141,6 +141,7 @@ describe 'Gcp Cluster', :js, :do_not_mock_admin_mode do
context 'when user destroys the cluster' do context 'when user destroys the cluster' do
before do before do
click_link 'Advanced Settings'
click_button 'Remove integration and resources' click_button 'Remove integration and resources'
fill_in 'confirm_cluster_name_input', with: cluster.name fill_in 'confirm_cluster_name_input', with: cluster.name
click_button 'Remove integration' click_button 'Remove integration'
......
...@@ -41,7 +41,7 @@ describe 'User Cluster', :js do ...@@ -41,7 +41,7 @@ describe 'User Cluster', :js do
it 'user sees a cluster details page' do it 'user sees a cluster details page' do
subject subject
expect(page).to have_content('Kubernetes cluster integration') expect(page).to have_content('GitLab Integration')
expect(page.find_field('cluster[name]').value).to eq('dev-cluster') expect(page.find_field('cluster[name]').value).to eq('dev-cluster')
expect(page.find_field('cluster[platform_kubernetes_attributes][api_url]').value) expect(page.find_field('cluster[platform_kubernetes_attributes][api_url]').value)
.to have_content('http://example.com') .to have_content('http://example.com')
...@@ -79,7 +79,7 @@ describe 'User Cluster', :js do ...@@ -79,7 +79,7 @@ describe 'User Cluster', :js do
context 'when user disables the cluster' do context 'when user disables the cluster' do
before do before do
page.find(:css, '.js-cluster-enable-toggle-area .js-project-feature-toggle').click page.find(:css, '.js-cluster-enable-toggle-area .js-project-feature-toggle').click
page.within('#cluster-integration') { click_button 'Save changes' } page.within('.js-cluster-integration-form') { click_button 'Save changes' }
end end
it 'user sees the successful message' do it 'user sees the successful message' do
...@@ -91,7 +91,7 @@ describe 'User Cluster', :js do ...@@ -91,7 +91,7 @@ describe 'User Cluster', :js do
before do before do
fill_in 'cluster_name', with: 'my-dev-cluster' fill_in 'cluster_name', with: 'my-dev-cluster'
fill_in 'cluster_platform_kubernetes_attributes_namespace', with: 'my-namespace' fill_in 'cluster_platform_kubernetes_attributes_namespace', with: 'my-namespace'
page.within('#js-cluster-details') { click_button 'Save changes' } page.within('.js-provider-details') { click_button 'Save changes' }
end end
it 'user sees the successful message' do it 'user sees the successful message' do
...@@ -103,6 +103,7 @@ describe 'User Cluster', :js do ...@@ -103,6 +103,7 @@ describe 'User Cluster', :js do
context 'when user destroys the cluster' do context 'when user destroys the cluster' do
before do before do
click_link 'Advanced Settings'
click_button 'Remove integration and resources' click_button 'Remove integration and resources'
fill_in 'confirm_cluster_name_input', with: cluster.name fill_in 'confirm_cluster_name_input', with: cluster.name
click_button 'Remove integration' click_button 'Remove integration'
......
...@@ -24,16 +24,31 @@ describe 'User views releases', :js do ...@@ -24,16 +24,31 @@ describe 'User views releases', :js do
context 'when there is a link as an asset' do context 'when there is a link as an asset' do
let!(:release_link) { create(:release_link, release: release, url: url ) } let!(:release_link) { create(:release_link, release: release, url: url ) }
let(:url) { "#{project.web_url}/-/jobs/1/artifacts/download" } let(:url) { "#{project.web_url}/-/jobs/1/artifacts/download" }
let(:direct_asset_link) { Gitlab::Routing.url_helpers.project_release_url(project, release) << release_link.filepath }
it 'sees the link' do it 'sees the link' do
visit project_releases_path(project) visit project_releases_path(project)
page.within('.js-assets-list') do page.within('.js-assets-list') do
expect(page).to have_link release_link.name, href: release_link.url expect(page).to have_link release_link.name, href: direct_asset_link
expect(page).not_to have_content('(external source)') expect(page).not_to have_content('(external source)')
end end
end end
context 'when there is a link redirect' do
let!(:release_link) { create(:release_link, release: release, name: 'linux-amd64 binaries', filepath: '/binaries/linux-amd64', url: url) }
let(:url) { "#{project.web_url}/-/jobs/1/artifacts/download" }
it 'sees the link' do
visit project_releases_path(project)
page.within('.js-assets-list') do
expect(page).to have_link release_link.name, href: direct_asset_link
expect(page).not_to have_content('(external source)')
end
end
end
context 'when url points to external resource' do context 'when url points to external resource' do
let(:url) { 'http://google.com/download' } let(:url) { 'http://google.com/download' }
......
...@@ -38,7 +38,7 @@ describe 'Projects > Snippets > User updates a snippet' do ...@@ -38,7 +38,7 @@ describe 'Projects > Snippets > User updates a snippet' do
end end
it 'renders edit page and displays the error' do it 'renders edit page and displays the error' do
expect(page).to have_content('Error updating the snippet') expect(page.find('.flash-container span').text).to eq('Error updating the snippet')
expect(page).to have_content('Edit Snippet') expect(page).to have_content('Edit Snippet')
end end
end end
......
...@@ -71,7 +71,7 @@ describe 'User edits snippet', :js do ...@@ -71,7 +71,7 @@ describe 'User edits snippet', :js do
end end
it 'renders edit page and displays the error' do it 'renders edit page and displays the error' do
expect(page).to have_content('Error updating the snippet') expect(page.find('.flash-container span').text).to eq('Error updating the snippet')
expect(page).to have_content('Edit Snippet') expect(page).to have_content('Edit Snippet')
end end
end end
......
...@@ -67,7 +67,7 @@ describe('Evidence Block', () => { ...@@ -67,7 +67,7 @@ describe('Evidence Block', () => {
}); });
it('renders the correct hover text', () => { it('renders the correct hover text', () => {
expect(wrapper.find(ClipboardButton).attributes('title')).toBe('Copy commit SHA'); expect(wrapper.find(ClipboardButton).attributes('title')).toBe('Copy evidence SHA');
}); });
it('copies the sha', () => { it('copies the sha', () => {
......
...@@ -10,11 +10,9 @@ describe('Release block milestone info', () => { ...@@ -10,11 +10,9 @@ describe('Release block milestone info', () => {
let wrapper; let wrapper;
let milestones; let milestones;
const factory = milestonesProp => { const factory = props => {
wrapper = mount(ReleaseBlockMilestoneInfo, { wrapper = mount(ReleaseBlockMilestoneInfo, {
propsData: { propsData: props,
milestones: milestonesProp,
},
}); });
return wrapper.vm.$nextTick(); return wrapper.vm.$nextTick();
...@@ -26,6 +24,7 @@ describe('Release block milestone info', () => { ...@@ -26,6 +24,7 @@ describe('Release block milestone info', () => {
afterEach(() => { afterEach(() => {
wrapper.destroy(); wrapper.destroy();
wrapper = null;
}); });
const milestoneProgressBarContainer = () => wrapper.find('.js-milestone-progress-bar-container'); const milestoneProgressBarContainer = () => wrapper.find('.js-milestone-progress-bar-container');
...@@ -33,7 +32,7 @@ describe('Release block milestone info', () => { ...@@ -33,7 +32,7 @@ describe('Release block milestone info', () => {
const issuesContainer = () => wrapper.find('.js-issues-container'); const issuesContainer = () => wrapper.find('.js-issues-container');
describe('with default props', () => { describe('with default props', () => {
beforeEach(() => factory(milestones)); beforeEach(() => factory({ milestones }));
it('renders the correct percentage', () => { it('renders the correct percentage', () => {
expect(milestoneProgressBarContainer().text()).toContain('41% complete'); expect(milestoneProgressBarContainer().text()).toContain('41% complete');
...@@ -102,7 +101,7 @@ describe('Release block milestone info', () => { ...@@ -102,7 +101,7 @@ describe('Release block milestone info', () => {
.map(m => m.title) .map(m => m.title)
.join(''); .join('');
return factory(lotsOfMilestones); return factory({ milestones: lotsOfMilestones });
}); });
const clickShowMoreFewerButton = () => { const clickShowMoreFewerButton = () => {
...@@ -153,12 +152,12 @@ describe('Release block milestone info', () => { ...@@ -153,12 +152,12 @@ describe('Release block milestone info', () => {
...m, ...m,
issueStats: { issueStats: {
...m.issueStats, ...m.issueStats,
opened: 0, total: 0,
closed: 0, closed: 0,
}, },
})); }));
return factory(milestones); return factory({ milestones });
}); });
expectAllZeros(); expectAllZeros();
...@@ -171,9 +170,72 @@ describe('Release block milestone info', () => { ...@@ -171,9 +170,72 @@ describe('Release block milestone info', () => {
issueStats: undefined, issueStats: undefined,
})); }));
return factory(milestones); return factory({ milestones });
}); });
expectAllZeros(); expectAllZeros();
}); });
describe('Issue links', () => {
const findOpenIssuesLink = () => wrapper.find({ ref: 'openIssuesLink' });
const findOpenIssuesText = () => wrapper.find({ ref: 'openIssuesText' });
const findClosedIssuesLink = () => wrapper.find({ ref: 'closedIssuesLink' });
const findClosedIssuesText = () => wrapper.find({ ref: 'closedIssuesText' });
describe('when openIssuePath is provided', () => {
const openIssuesPath = '/path/to/open/issues';
beforeEach(() => {
return factory({ milestones, openIssuesPath });
});
it('renders the open issues as a link', () => {
expect(findOpenIssuesLink().exists()).toBe(true);
expect(findOpenIssuesText().exists()).toBe(false);
});
it('renders the open issues link with the correct href', () => {
expect(findOpenIssuesLink().attributes().href).toBe(openIssuesPath);
});
});
describe('when openIssuePath is not provided', () => {
beforeEach(() => {
return factory({ milestones });
});
it('renders the open issues as plain text', () => {
expect(findOpenIssuesLink().exists()).toBe(false);
expect(findOpenIssuesText().exists()).toBe(true);
});
});
describe('when closedIssuePath is provided', () => {
const closedIssuesPath = '/path/to/closed/issues';
beforeEach(() => {
return factory({ milestones, closedIssuesPath });
});
it('renders the closed issues as a link', () => {
expect(findClosedIssuesLink().exists()).toBe(true);
expect(findClosedIssuesText().exists()).toBe(false);
});
it('renders the closed issues link with the correct href', () => {
expect(findClosedIssuesLink().attributes().href).toBe(closedIssuesPath);
});
});
describe('when closedIssuePath is not provided', () => {
beforeEach(() => {
return factory({ milestones });
});
it('renders the closed issues as plain text', () => {
expect(findClosedIssuesLink().exists()).toBe(false);
expect(findClosedIssuesText().exists()).toBe(true);
});
});
});
}); });
...@@ -92,7 +92,7 @@ describe('Release block', () => { ...@@ -92,7 +92,7 @@ describe('Release block', () => {
expect(wrapper.findAll('.js-assets-list li').length).toEqual(release.assets.links.length); expect(wrapper.findAll('.js-assets-list li').length).toEqual(release.assets.links.length);
expect(wrapper.find('.js-assets-list li a').attributes().href).toEqual( expect(wrapper.find('.js-assets-list li a').attributes().href).toEqual(
first(release.assets.links).url, first(release.assets.links).directAssetUrl,
); );
expect(wrapper.find('.js-assets-list li a').text()).toContain( expect(wrapper.find('.js-assets-list li a').text()).toContain(
......
...@@ -12,7 +12,7 @@ export const milestones = [ ...@@ -12,7 +12,7 @@ export const milestones = [
start_date: '2019-08-31', start_date: '2019-08-31',
web_url: 'http://0.0.0.0:3001/root/release-test/-/milestones/2', web_url: 'http://0.0.0.0:3001/root/release-test/-/milestones/2',
issue_stats: { issue_stats: {
opened: 14, total: 33,
closed: 19, closed: 19,
}, },
}, },
...@@ -29,7 +29,7 @@ export const milestones = [ ...@@ -29,7 +29,7 @@ export const milestones = [
start_date: '2019-08-19', start_date: '2019-08-19',
web_url: 'http://0.0.0.0:3001/root/release-test/-/milestones/1', web_url: 'http://0.0.0.0:3001/root/release-test/-/milestones/1',
issue_stats: { issue_stats: {
opened: 18, total: 21,
closed: 3, closed: 3,
}, },
}, },
...@@ -96,6 +96,7 @@ export const release = { ...@@ -96,6 +96,7 @@ export const release = {
id: 1, id: 1,
name: 'my link', name: 'my link',
url: 'https://google.com', url: 'https://google.com',
direct_asset_url: 'https://redirected.google.com',
external: true, external: true,
}, },
{ {
...@@ -103,6 +104,7 @@ export const release = { ...@@ -103,6 +104,7 @@ export const release = {
name: 'my second link', name: 'my second link',
url: url:
'https://gitlab.com/gitlab-org/gitlab-foss/-/jobs/artifacts/v11.6.0-rc4/download?job=rspec-mysql+41%2F50', 'https://gitlab.com/gitlab-org/gitlab-foss/-/jobs/artifacts/v11.6.0-rc4/download?job=rspec-mysql+41%2F50',
direct_asset_url: 'https://redirected.google.com',
external: false, external: false,
}, },
], ],
......
...@@ -56,7 +56,7 @@ describe AuthHelper do ...@@ -56,7 +56,7 @@ describe AuthHelper do
describe 'any_form_based_providers_enabled?' do describe 'any_form_based_providers_enabled?' do
before do before do
allow(Gitlab::Auth::LDAP::Config).to receive(:enabled?).and_return(true) allow(Gitlab::Auth::Ldap::Config).to receive(:enabled?).and_return(true)
end end
it 'detects form-based providers' do it 'detects form-based providers' do
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
describe Gitlab::Auth::LDAP::Access do describe Gitlab::Auth::Ldap::Access do
include LdapHelpers include LdapHelpers
let(:user) { create(:omniauth_user) } let(:user) { create(:omniauth_user) }
...@@ -64,7 +64,7 @@ describe Gitlab::Auth::LDAP::Access do ...@@ -64,7 +64,7 @@ describe Gitlab::Auth::LDAP::Access do
context 'and the user is disabled via active directory' do context 'and the user is disabled via active directory' do
before do before do
allow(Gitlab::Auth::LDAP::Person).to receive(:disabled_via_active_directory?).and_return(true) allow(Gitlab::Auth::Ldap::Person).to receive(:disabled_via_active_directory?).and_return(true)
end end
it 'returns false' do it 'returns false' do
...@@ -90,7 +90,7 @@ describe Gitlab::Auth::LDAP::Access do ...@@ -90,7 +90,7 @@ describe Gitlab::Auth::LDAP::Access do
context 'and has no disabled flag in active directory' do context 'and has no disabled flag in active directory' do
before do before do
allow(Gitlab::Auth::LDAP::Person).to receive(:disabled_via_active_directory?).and_return(false) allow(Gitlab::Auth::Ldap::Person).to receive(:disabled_via_active_directory?).and_return(false)
end end
it { is_expected.to be_truthy } it { is_expected.to be_truthy }
...@@ -135,8 +135,8 @@ describe Gitlab::Auth::LDAP::Access do ...@@ -135,8 +135,8 @@ describe Gitlab::Auth::LDAP::Access do
context 'without ActiveDirectory enabled' do context 'without ActiveDirectory enabled' do
before do before do
allow(Gitlab::Auth::LDAP::Config).to receive(:enabled?).and_return(true) allow(Gitlab::Auth::Ldap::Config).to receive(:enabled?).and_return(true)
allow_next_instance_of(Gitlab::Auth::LDAP::Config) do |instance| allow_next_instance_of(Gitlab::Auth::Ldap::Config) do |instance|
allow(instance).to receive(:active_directory).and_return(false) allow(instance).to receive(:active_directory).and_return(false)
end end
end end
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
describe Gitlab::Auth::LDAP::Adapter do describe Gitlab::Auth::Ldap::Adapter do
include LdapHelpers include LdapHelpers
let(:ldap) { double(:ldap) } let(:ldap) { double(:ldap) }
...@@ -138,7 +138,7 @@ describe Gitlab::Auth::LDAP::Adapter do ...@@ -138,7 +138,7 @@ describe Gitlab::Auth::LDAP::Adapter do
it 'as many times as MAX_SEARCH_RETRIES' do it 'as many times as MAX_SEARCH_RETRIES' do
expect(ldap).to receive(:search).exactly(3).times expect(ldap).to receive(:search).exactly(3).times
expect { subject }.to raise_error(Gitlab::Auth::LDAP::LDAPConnectionError) expect { subject }.to raise_error(Gitlab::Auth::Ldap::LdapConnectionError)
end end
context 'when no more retries' do context 'when no more retries' do
...@@ -147,11 +147,11 @@ describe Gitlab::Auth::LDAP::Adapter do ...@@ -147,11 +147,11 @@ describe Gitlab::Auth::LDAP::Adapter do
end end
it 'raises the exception' do it 'raises the exception' do
expect { subject }.to raise_error(Gitlab::Auth::LDAP::LDAPConnectionError) expect { subject }.to raise_error(Gitlab::Auth::Ldap::LdapConnectionError)
end end
it 'logs the error' do it 'logs the error' do
expect { subject }.to raise_error(Gitlab::Auth::LDAP::LDAPConnectionError) expect { subject }.to raise_error(Gitlab::Auth::Ldap::LdapConnectionError)
expect(Rails.logger).to have_received(:warn).with( expect(Rails.logger).to have_received(:warn).with(
"LDAP search raised exception Net::LDAP::Error: some error") "LDAP search raised exception Net::LDAP::Error: some error")
end end
...@@ -161,6 +161,6 @@ describe Gitlab::Auth::LDAP::Adapter do ...@@ -161,6 +161,6 @@ describe Gitlab::Auth::LDAP::Adapter do
end end
def ldap_attributes def ldap_attributes
Gitlab::Auth::LDAP::Person.ldap_attributes(Gitlab::Auth::LDAP::Config.new('ldapmain')) Gitlab::Auth::Ldap::Person.ldap_attributes(Gitlab::Auth::Ldap::Config.new('ldapmain'))
end end
end end
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
describe Gitlab::Auth::LDAP::AuthHash do describe Gitlab::Auth::Ldap::AuthHash do
include LdapHelpers include LdapHelpers
let(:auth_hash) do let(:auth_hash) do
...@@ -58,7 +58,7 @@ describe Gitlab::Auth::LDAP::AuthHash do ...@@ -58,7 +58,7 @@ describe Gitlab::Auth::LDAP::AuthHash do
end end
before do before do
allow_next_instance_of(Gitlab::Auth::LDAP::Config) do |instance| allow_next_instance_of(Gitlab::Auth::Ldap::Config) do |instance|
allow(instance).to receive(:attributes).and_return(attributes) allow(instance).to receive(:attributes).and_return(attributes)
end end
end end
......
...@@ -2,15 +2,15 @@ ...@@ -2,15 +2,15 @@
require 'spec_helper' require 'spec_helper'
describe Gitlab::Auth::LDAP::Authentication do describe Gitlab::Auth::Ldap::Authentication do
let(:dn) { 'uid=John Smith, ou=People, dc=example, dc=com' } let(:dn) { 'uid=John Smith, ou=People, dc=example, dc=com' }
let(:user) { create(:omniauth_user, extern_uid: Gitlab::Auth::LDAP::Person.normalize_dn(dn)) } let(:user) { create(:omniauth_user, extern_uid: Gitlab::Auth::Ldap::Person.normalize_dn(dn)) }
let(:login) { 'john' } let(:login) { 'john' }
let(:password) { 'password' } let(:password) { 'password' }
describe 'login' do describe 'login' do
before do before do
allow(Gitlab::Auth::LDAP::Config).to receive(:enabled?).and_return(true) allow(Gitlab::Auth::Ldap::Config).to receive(:enabled?).and_return(true)
end end
it "finds the user if authentication is successful" do it "finds the user if authentication is successful" do
...@@ -48,7 +48,7 @@ describe Gitlab::Auth::LDAP::Authentication do ...@@ -48,7 +48,7 @@ describe Gitlab::Auth::LDAP::Authentication do
end end
it "fails if ldap is disabled" do it "fails if ldap is disabled" do
allow(Gitlab::Auth::LDAP::Config).to receive(:enabled?).and_return(false) allow(Gitlab::Auth::Ldap::Config).to receive(:enabled?).and_return(false)
expect(described_class.login(login, password)).to be_falsey expect(described_class.login(login, password)).to be_falsey
end end
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
describe Gitlab::Auth::LDAP::Config do describe Gitlab::Auth::Ldap::Config do
include LdapHelpers include LdapHelpers
let(:config) { described_class.new('ldapmain') } let(:config) { described_class.new('ldapmain') }
......
This diff is collapsed.
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
describe Gitlab::Auth::LDAP::Person do describe Gitlab::Auth::Ldap::Person do
include LdapHelpers include LdapHelpers
let(:entry) { ldap_user_entry('john.doe') } let(:entry) { ldap_user_entry('john.doe') }
...@@ -61,7 +61,7 @@ describe Gitlab::Auth::LDAP::Person do ...@@ -61,7 +61,7 @@ describe Gitlab::Auth::LDAP::Person do
} }
} }
) )
config = Gitlab::Auth::LDAP::Config.new('ldapmain') config = Gitlab::Auth::Ldap::Config.new('ldapmain')
ldap_attributes = described_class.ldap_attributes(config) ldap_attributes = described_class.ldap_attributes(config)
expect(ldap_attributes).to match_array(%w(dn uid cn mail memberof)) expect(ldap_attributes).to match_array(%w(dn uid cn mail memberof))
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
describe Gitlab::Auth::LDAP::User do describe Gitlab::Auth::Ldap::User do
include LdapHelpers include LdapHelpers
let(:ldap_user) { described_class.new(auth_hash) } let(:ldap_user) { described_class.new(auth_hash) }
......
...@@ -22,7 +22,7 @@ describe Gitlab::Auth::OAuth::User do ...@@ -22,7 +22,7 @@ describe Gitlab::Auth::OAuth::User do
} }
} }
end end
let(:ldap_user) { Gitlab::Auth::LDAP::Person.new(Net::LDAP::Entry.new, 'ldapmain') } let(:ldap_user) { Gitlab::Auth::Ldap::Person.new(Net::LDAP::Entry.new, 'ldapmain') }
describe '#persisted?' do describe '#persisted?' do
let!(:existing_user) { create(:omniauth_user, extern_uid: 'my-uid', provider: 'my-provider') } let!(:existing_user) { create(:omniauth_user, extern_uid: 'my-uid', provider: 'my-provider') }
...@@ -230,7 +230,7 @@ describe Gitlab::Auth::OAuth::User do ...@@ -230,7 +230,7 @@ describe Gitlab::Auth::OAuth::User do
context "and no account for the LDAP user" do context "and no account for the LDAP user" do
before do before do
allow(Gitlab::Auth::LDAP::Person).to receive(:find_by_uid).and_return(ldap_user) allow(Gitlab::Auth::Ldap::Person).to receive(:find_by_uid).and_return(ldap_user)
oauth_user.save oauth_user.save
end end
...@@ -269,7 +269,7 @@ describe Gitlab::Auth::OAuth::User do ...@@ -269,7 +269,7 @@ describe Gitlab::Auth::OAuth::User do
let!(:existing_user) { create(:omniauth_user, name: 'John Doe', email: 'john@example.com', extern_uid: dn, provider: 'ldapmain', username: 'john') } let!(:existing_user) { create(:omniauth_user, name: 'John Doe', email: 'john@example.com', extern_uid: dn, provider: 'ldapmain', username: 'john') }
it "adds the omniauth identity to the LDAP account" do it "adds the omniauth identity to the LDAP account" do
allow(Gitlab::Auth::LDAP::Person).to receive(:find_by_uid).and_return(ldap_user) allow(Gitlab::Auth::Ldap::Person).to receive(:find_by_uid).and_return(ldap_user)
oauth_user.save oauth_user.save
...@@ -290,8 +290,8 @@ describe Gitlab::Auth::OAuth::User do ...@@ -290,8 +290,8 @@ describe Gitlab::Auth::OAuth::User do
context 'when an LDAP person is not found by uid' do context 'when an LDAP person is not found by uid' do
it 'tries to find an LDAP person by email and adds the omniauth identity to the user' do it 'tries to find an LDAP person by email and adds the omniauth identity to the user' do
allow(Gitlab::Auth::LDAP::Person).to receive(:find_by_uid).and_return(nil) allow(Gitlab::Auth::Ldap::Person).to receive(:find_by_uid).and_return(nil)
allow(Gitlab::Auth::LDAP::Person).to receive(:find_by_email).and_return(ldap_user) allow(Gitlab::Auth::Ldap::Person).to receive(:find_by_email).and_return(ldap_user)
oauth_user.save oauth_user.save
...@@ -301,9 +301,9 @@ describe Gitlab::Auth::OAuth::User do ...@@ -301,9 +301,9 @@ describe Gitlab::Auth::OAuth::User do
context 'when also not found by email' do context 'when also not found by email' do
it 'tries to find an LDAP person by DN and adds the omniauth identity to the user' do it 'tries to find an LDAP person by DN and adds the omniauth identity to the user' do
allow(Gitlab::Auth::LDAP::Person).to receive(:find_by_uid).and_return(nil) allow(Gitlab::Auth::Ldap::Person).to receive(:find_by_uid).and_return(nil)
allow(Gitlab::Auth::LDAP::Person).to receive(:find_by_email).and_return(nil) allow(Gitlab::Auth::Ldap::Person).to receive(:find_by_email).and_return(nil)
allow(Gitlab::Auth::LDAP::Person).to receive(:find_by_dn).and_return(ldap_user) allow(Gitlab::Auth::Ldap::Person).to receive(:find_by_dn).and_return(ldap_user)
oauth_user.save oauth_user.save
...@@ -344,7 +344,7 @@ describe Gitlab::Auth::OAuth::User do ...@@ -344,7 +344,7 @@ describe Gitlab::Auth::OAuth::User do
context 'and no account for the LDAP user' do context 'and no account for the LDAP user' do
it 'creates a user favoring the LDAP username and strips email domain' do it 'creates a user favoring the LDAP username and strips email domain' do
allow(Gitlab::Auth::LDAP::Person).to receive(:find_by_uid).and_return(ldap_user) allow(Gitlab::Auth::Ldap::Person).to receive(:find_by_uid).and_return(ldap_user)
oauth_user.save oauth_user.save
...@@ -356,7 +356,7 @@ describe Gitlab::Auth::OAuth::User do ...@@ -356,7 +356,7 @@ describe Gitlab::Auth::OAuth::User do
context "and no corresponding LDAP person" do context "and no corresponding LDAP person" do
before do before do
allow(Gitlab::Auth::LDAP::Person).to receive(:find_by_uid).and_return(nil) allow(Gitlab::Auth::Ldap::Person).to receive(:find_by_uid).and_return(nil)
end end
include_examples "to verify compliance with allow_single_sign_on" include_examples "to verify compliance with allow_single_sign_on"
...@@ -405,13 +405,13 @@ describe Gitlab::Auth::OAuth::User do ...@@ -405,13 +405,13 @@ describe Gitlab::Auth::OAuth::User do
allow(ldap_user).to receive(:username) { uid } allow(ldap_user).to receive(:username) { uid }
allow(ldap_user).to receive(:email) { ['johndoe@example.com', 'john2@example.com'] } allow(ldap_user).to receive(:email) { ['johndoe@example.com', 'john2@example.com'] }
allow(ldap_user).to receive(:dn) { dn } allow(ldap_user).to receive(:dn) { dn }
allow(Gitlab::Auth::LDAP::Person).to receive(:find_by_uid).and_return(ldap_user) allow(Gitlab::Auth::Ldap::Person).to receive(:find_by_uid).and_return(ldap_user)
end end
context "and no account for the LDAP user" do context "and no account for the LDAP user" do
context 'dont block on create (LDAP)' do context 'dont block on create (LDAP)' do
before do before do
allow_next_instance_of(Gitlab::Auth::LDAP::Config) do |instance| allow_next_instance_of(Gitlab::Auth::Ldap::Config) do |instance|
allow(instance).to receive_messages(block_auto_created_users: false) allow(instance).to receive_messages(block_auto_created_users: false)
end end
end end
...@@ -425,7 +425,7 @@ describe Gitlab::Auth::OAuth::User do ...@@ -425,7 +425,7 @@ describe Gitlab::Auth::OAuth::User do
context 'block on create (LDAP)' do context 'block on create (LDAP)' do
before do before do
allow_next_instance_of(Gitlab::Auth::LDAP::Config) do |instance| allow_next_instance_of(Gitlab::Auth::Ldap::Config) do |instance|
allow(instance).to receive_messages(block_auto_created_users: true) allow(instance).to receive_messages(block_auto_created_users: true)
end end
end end
...@@ -443,7 +443,7 @@ describe Gitlab::Auth::OAuth::User do ...@@ -443,7 +443,7 @@ describe Gitlab::Auth::OAuth::User do
context 'dont block on create (LDAP)' do context 'dont block on create (LDAP)' do
before do before do
allow_next_instance_of(Gitlab::Auth::LDAP::Config) do |instance| allow_next_instance_of(Gitlab::Auth::Ldap::Config) do |instance|
allow(instance).to receive_messages(block_auto_created_users: false) allow(instance).to receive_messages(block_auto_created_users: false)
end end
end end
...@@ -457,7 +457,7 @@ describe Gitlab::Auth::OAuth::User do ...@@ -457,7 +457,7 @@ describe Gitlab::Auth::OAuth::User do
context 'block on create (LDAP)' do context 'block on create (LDAP)' do
before do before do
allow_next_instance_of(Gitlab::Auth::LDAP::Config) do |instance| allow_next_instance_of(Gitlab::Auth::Ldap::Config) do |instance|
allow(instance).to receive_messages(block_auto_created_users: true) allow(instance).to receive_messages(block_auto_created_users: true)
end end
end end
...@@ -503,7 +503,7 @@ describe Gitlab::Auth::OAuth::User do ...@@ -503,7 +503,7 @@ describe Gitlab::Auth::OAuth::User do
context 'dont block on create (LDAP)' do context 'dont block on create (LDAP)' do
before do before do
allow_next_instance_of(Gitlab::Auth::LDAP::Config) do |instance| allow_next_instance_of(Gitlab::Auth::Ldap::Config) do |instance|
allow(instance).to receive_messages(block_auto_created_users: false) allow(instance).to receive_messages(block_auto_created_users: false)
end end
end end
...@@ -517,7 +517,7 @@ describe Gitlab::Auth::OAuth::User do ...@@ -517,7 +517,7 @@ describe Gitlab::Auth::OAuth::User do
context 'block on create (LDAP)' do context 'block on create (LDAP)' do
before do before do
allow_next_instance_of(Gitlab::Auth::LDAP::Config) do |instance| allow_next_instance_of(Gitlab::Auth::Ldap::Config) do |instance|
allow(instance).to receive_messages(block_auto_created_users: true) allow(instance).to receive_messages(block_auto_created_users: true)
end end
end end
...@@ -806,7 +806,7 @@ describe Gitlab::Auth::OAuth::User do ...@@ -806,7 +806,7 @@ describe Gitlab::Auth::OAuth::User do
end end
it 'returns nil' do it 'returns nil' do
adapter = Gitlab::Auth::LDAP::Adapter.new('ldapmain') adapter = Gitlab::Auth::Ldap::Adapter.new('ldapmain')
hash = OmniAuth::AuthHash.new(uid: 'whatever', provider: 'ldapmain') hash = OmniAuth::AuthHash.new(uid: 'whatever', provider: 'ldapmain')
expect(oauth_user.send(:find_ldap_person, hash, adapter)).to be_nil expect(oauth_user.send(:find_ldap_person, hash, adapter)).to be_nil
......
...@@ -19,7 +19,7 @@ describe Gitlab::Auth::Saml::User do ...@@ -19,7 +19,7 @@ describe Gitlab::Auth::Saml::User do
email: 'john@mail.com' email: 'john@mail.com'
} }
end end
let(:ldap_user) { Gitlab::Auth::LDAP::Person.new(Net::LDAP::Entry.new, 'ldapmain') } let(:ldap_user) { Gitlab::Auth::Ldap::Person.new(Net::LDAP::Entry.new, 'ldapmain') }
describe '#save' do describe '#save' do
before do before do
...@@ -161,10 +161,10 @@ describe Gitlab::Auth::Saml::User do ...@@ -161,10 +161,10 @@ describe Gitlab::Auth::Saml::User do
allow(ldap_user).to receive(:username) { uid } allow(ldap_user).to receive(:username) { uid }
allow(ldap_user).to receive(:email) { %w(john@mail.com john2@example.com) } allow(ldap_user).to receive(:email) { %w(john@mail.com john2@example.com) }
allow(ldap_user).to receive(:dn) { dn } allow(ldap_user).to receive(:dn) { dn }
allow(Gitlab::Auth::LDAP::Adapter).to receive(:new).and_return(adapter) allow(Gitlab::Auth::Ldap::Adapter).to receive(:new).and_return(adapter)
allow(Gitlab::Auth::LDAP::Person).to receive(:find_by_uid).with(uid, adapter).and_return(ldap_user) allow(Gitlab::Auth::Ldap::Person).to receive(:find_by_uid).with(uid, adapter).and_return(ldap_user)
allow(Gitlab::Auth::LDAP::Person).to receive(:find_by_dn).with(dn, adapter).and_return(ldap_user) allow(Gitlab::Auth::Ldap::Person).to receive(:find_by_dn).with(dn, adapter).and_return(ldap_user)
allow(Gitlab::Auth::LDAP::Person).to receive(:find_by_email).with('john@mail.com', adapter).and_return(ldap_user) allow(Gitlab::Auth::Ldap::Person).to receive(:find_by_email).with('john@mail.com', adapter).and_return(ldap_user)
end end
context 'and no account for the LDAP user' do context 'and no account for the LDAP user' do
...@@ -212,10 +212,10 @@ describe Gitlab::Auth::Saml::User do ...@@ -212,10 +212,10 @@ describe Gitlab::Auth::Saml::User do
nil_types = uid_types - [uid_type] nil_types = uid_types - [uid_type]
nil_types.each do |type| nil_types.each do |type|
allow(Gitlab::Auth::LDAP::Person).to receive(:"find_by_#{type}").and_return(nil) allow(Gitlab::Auth::Ldap::Person).to receive(:"find_by_#{type}").and_return(nil)
end end
allow(Gitlab::Auth::LDAP::Person).to receive(:"find_by_#{uid_type}").and_return(ldap_user) allow(Gitlab::Auth::Ldap::Person).to receive(:"find_by_#{uid_type}").and_return(ldap_user)
end end
it 'adds the omniauth identity to the LDAP account' do it 'adds the omniauth identity to the LDAP account' do
...@@ -282,7 +282,7 @@ describe Gitlab::Auth::Saml::User do ...@@ -282,7 +282,7 @@ describe Gitlab::Auth::Saml::User do
it 'adds the LDAP identity to the existing SAML user' do it 'adds the LDAP identity to the existing SAML user' do
create(:omniauth_user, email: 'john@mail.com', extern_uid: dn, provider: 'saml', username: 'john') create(:omniauth_user, email: 'john@mail.com', extern_uid: dn, provider: 'saml', username: 'john')
allow(Gitlab::Auth::LDAP::Person).to receive(:find_by_uid).with(dn, adapter).and_return(ldap_user) allow(Gitlab::Auth::Ldap::Person).to receive(:find_by_uid).with(dn, adapter).and_return(ldap_user)
local_hash = OmniAuth::AuthHash.new(uid: dn, provider: provider, info: info_hash) local_hash = OmniAuth::AuthHash.new(uid: dn, provider: provider, info: info_hash)
local_saml_user = described_class.new(local_hash) local_saml_user = described_class.new(local_hash)
......
...@@ -590,23 +590,23 @@ describe Gitlab::Auth, :use_clean_rails_memory_store_caching do ...@@ -590,23 +590,23 @@ describe Gitlab::Auth, :use_clean_rails_memory_store_caching do
context "with ldap enabled" do context "with ldap enabled" do
before do before do
allow(Gitlab::Auth::LDAP::Config).to receive(:enabled?).and_return(true) allow(Gitlab::Auth::Ldap::Config).to receive(:enabled?).and_return(true)
end end
it "tries to autheticate with db before ldap" do it "tries to autheticate with db before ldap" do
expect(Gitlab::Auth::LDAP::Authentication).not_to receive(:login) expect(Gitlab::Auth::Ldap::Authentication).not_to receive(:login)
expect(gl_auth.find_with_user_password(username, password)).to eq(user) expect(gl_auth.find_with_user_password(username, password)).to eq(user)
end end
it "does not find user by using ldap as fallback to for authentication" do it "does not find user by using ldap as fallback to for authentication" do
expect(Gitlab::Auth::LDAP::Authentication).to receive(:login).and_return(nil) expect(Gitlab::Auth::Ldap::Authentication).to receive(:login).and_return(nil)
expect(gl_auth.find_with_user_password('ldap_user', 'password')).to be_nil expect(gl_auth.find_with_user_password('ldap_user', 'password')).to be_nil
end end
it "find new user by using ldap as fallback to for authentication" do it "find new user by using ldap as fallback to for authentication" do
expect(Gitlab::Auth::LDAP::Authentication).to receive(:login).and_return(user) expect(Gitlab::Auth::Ldap::Authentication).to receive(:login).and_return(user)
expect(gl_auth.find_with_user_password('ldap_user', 'password')).to eq(user) expect(gl_auth.find_with_user_password('ldap_user', 'password')).to eq(user)
end end
...@@ -623,7 +623,7 @@ describe Gitlab::Auth, :use_clean_rails_memory_store_caching do ...@@ -623,7 +623,7 @@ describe Gitlab::Auth, :use_clean_rails_memory_store_caching do
context "with ldap enabled" do context "with ldap enabled" do
before do before do
allow(Gitlab::Auth::LDAP::Config).to receive(:enabled?).and_return(true) allow(Gitlab::Auth::Ldap::Config).to receive(:enabled?).and_return(true)
end end
it "does not find non-ldap user by valid login/password" do it "does not find non-ldap user by valid login/password" do
......
...@@ -54,16 +54,15 @@ describe ::Gitlab::BareRepositoryImport::Repository do ...@@ -54,16 +54,15 @@ describe ::Gitlab::BareRepositoryImport::Repository do
end end
context 'hashed storage' do context 'hashed storage' do
let(:gitlab_shell) { Gitlab::Shell.new }
let(:repository_storage) { 'default' }
let(:root_path) { Gitlab.config.repositories.storages[repository_storage].legacy_disk_path }
let(:hash) { '6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b' } let(:hash) { '6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b' }
let(:hashed_path) { "@hashed/6b/86/6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b" } let(:hashed_path) { "@hashed/6b/86/6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b" }
let(:root_path) { TestEnv.repos_path }
let(:repo_path) { File.join(root_path, "#{hashed_path}.git") } let(:repo_path) { File.join(root_path, "#{hashed_path}.git") }
let(:wiki_path) { File.join(root_path, "#{hashed_path}.wiki.git") } let(:wiki_path) { File.join(root_path, "#{hashed_path}.wiki.git") }
before do before do
gitlab_shell.create_repository(repository_storage, hashed_path, 'group/project') TestEnv.create_bare_repository(repo_path)
Gitlab::GitalyClient::StorageSettings.allow_disk_access do Gitlab::GitalyClient::StorageSettings.allow_disk_access do
repository = Rugged::Repository.new(repo_path) repository = Rugged::Repository.new(repo_path)
repository.config['gitlab.fullpath'] = 'to/repo' repository.config['gitlab.fullpath'] = 'to/repo'
...@@ -71,7 +70,7 @@ describe ::Gitlab::BareRepositoryImport::Repository do ...@@ -71,7 +70,7 @@ describe ::Gitlab::BareRepositoryImport::Repository do
end end
after do after do
gitlab_shell.remove_repository(repository_storage, hashed_path) FileUtils.rm_rf(repo_path)
end end
subject { described_class.new(root_path, repo_path) } subject { described_class.new(root_path, repo_path) }
......
...@@ -500,11 +500,11 @@ describe Gitlab::Git::Repository, :seed_helper do ...@@ -500,11 +500,11 @@ describe Gitlab::Git::Repository, :seed_helper do
subject { new_repository.fetch_repository_as_mirror(repository) } subject { new_repository.fetch_repository_as_mirror(repository) }
before do before do
Gitlab::Shell.new.create_repository('default', 'my_project', 'group/project') new_repository.create_repository
end end
after do after do
Gitlab::Shell.new.remove_repository('default', 'my_project') new_repository.remove
end end
it 'fetches a repository as a mirror remote' do it 'fetches a repository as a mirror remote' do
......
...@@ -4197,7 +4197,7 @@ describe User, :do_not_mock_admin_mode do ...@@ -4197,7 +4197,7 @@ describe User, :do_not_mock_admin_mode do
describe '#read_only_attribute?' do describe '#read_only_attribute?' do
context 'when LDAP server is enabled' do context 'when LDAP server is enabled' do
before do before do
allow(Gitlab::Auth::LDAP::Config).to receive(:enabled?).and_return(true) allow(Gitlab::Auth::Ldap::Config).to receive(:enabled?).and_return(true)
end end
%i[name email location].each do |attribute| %i[name email location].each do |attribute|
......
...@@ -639,8 +639,8 @@ describe 'Git HTTP requests' do ...@@ -639,8 +639,8 @@ describe 'Git HTTP requests' do
context 'when LDAP is configured' do context 'when LDAP is configured' do
before do before do
allow(Gitlab::Auth::LDAP::Config).to receive(:enabled?).and_return(true) allow(Gitlab::Auth::Ldap::Config).to receive(:enabled?).and_return(true)
allow_any_instance_of(Gitlab::Auth::LDAP::Authentication) allow_any_instance_of(Gitlab::Auth::Ldap::Authentication)
.to receive(:login).and_return(nil) .to receive(:login).and_return(nil)
end end
...@@ -862,8 +862,8 @@ describe 'Git HTTP requests' do ...@@ -862,8 +862,8 @@ describe 'Git HTTP requests' do
before do before do
allow(Gitlab::Auth::OAuth::Provider).to receive(:enabled?).and_return(true) allow(Gitlab::Auth::OAuth::Provider).to receive(:enabled?).and_return(true)
allow_any_instance_of(Gitlab::Auth::LDAP::Authentication).to receive(:login).and_return(nil) allow_any_instance_of(Gitlab::Auth::Ldap::Authentication).to receive(:login).and_return(nil)
allow_any_instance_of(Gitlab::Auth::LDAP::Authentication).to receive(:login).with(user.username, user.password).and_return(user) allow_any_instance_of(Gitlab::Auth::Ldap::Authentication).to receive(:login).with(user.username, user.password).and_return(user)
end end
it_behaves_like 'pulls require Basic HTTP Authentication' it_behaves_like 'pulls require Basic HTTP Authentication'
......
...@@ -6,7 +6,6 @@ describe Projects::CreateService, '#execute' do ...@@ -6,7 +6,6 @@ describe Projects::CreateService, '#execute' do
include ExternalAuthorizationServiceHelpers include ExternalAuthorizationServiceHelpers
include GitHelpers include GitHelpers
let(:gitlab_shell) { Gitlab::Shell.new }
let(:user) { create :user } let(:user) { create :user }
let(:opts) do let(:opts) do
{ {
...@@ -264,8 +263,6 @@ describe Projects::CreateService, '#execute' do ...@@ -264,8 +263,6 @@ describe Projects::CreateService, '#execute' do
end end
context 'when another repository already exists on disk' do context 'when another repository already exists on disk' do
let(:repository_storage) { 'default' }
let(:opts) do let(:opts) do
{ {
name: 'Existing', name: 'Existing',
...@@ -274,13 +271,15 @@ describe Projects::CreateService, '#execute' do ...@@ -274,13 +271,15 @@ describe Projects::CreateService, '#execute' do
end end
context 'with legacy storage' do context 'with legacy storage' do
let(:fake_repo_path) { File.join(TestEnv.repos_path, user.namespace.full_path, 'existing.git') }
before do before do
stub_application_setting(hashed_storage_enabled: false) stub_application_setting(hashed_storage_enabled: false)
gitlab_shell.create_repository(repository_storage, "#{user.namespace.full_path}/existing", 'group/project') TestEnv.create_bare_repository(fake_repo_path)
end end
after do after do
gitlab_shell.remove_repository(repository_storage, "#{user.namespace.full_path}/existing") FileUtils.rm_rf(fake_repo_path)
end end
it 'does not allow to create a project when path matches existing repository on disk' do it 'does not allow to create a project when path matches existing repository on disk' do
...@@ -305,17 +304,15 @@ describe Projects::CreateService, '#execute' do ...@@ -305,17 +304,15 @@ describe Projects::CreateService, '#execute' do
context 'with hashed storage' do context 'with hashed storage' do
let(:hash) { '6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b' } let(:hash) { '6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b' }
let(:hashed_path) { '@hashed/6b/86/6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b' } let(:hashed_path) { '@hashed/6b/86/6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b' }
let(:fake_repo_path) { File.join(TestEnv.repos_path, "#{hashed_path}.git") }
before do before do
allow(Digest::SHA2).to receive(:hexdigest) { hash } allow(Digest::SHA2).to receive(:hexdigest) { hash }
end TestEnv.create_bare_repository(fake_repo_path)
before do
gitlab_shell.create_repository(repository_storage, hashed_path, 'group/project')
end end
after do after do
gitlab_shell.remove_repository(repository_storage, hashed_path) FileUtils.rm_rf(fake_repo_path)
end end
it 'does not allow to create a project when path matches existing repository on disk' do it 'does not allow to create a project when path matches existing repository on disk' do
......
...@@ -4,7 +4,6 @@ require 'spec_helper' ...@@ -4,7 +4,6 @@ require 'spec_helper'
describe Projects::ForkService do describe Projects::ForkService do
include ProjectForksHelper include ProjectForksHelper
include Gitlab::ShellAdapter
shared_examples 'forks count cache refresh' do shared_examples 'forks count cache refresh' do
it 'flushes the forks count cache of the source project', :clean_gitlab_redis_cache do it 'flushes the forks count cache of the source project', :clean_gitlab_redis_cache do
...@@ -135,17 +134,16 @@ describe Projects::ForkService do ...@@ -135,17 +134,16 @@ describe Projects::ForkService do
end end
context 'repository in legacy storage already exists' do context 'repository in legacy storage already exists' do
let(:repository_storage) { 'default' } let(:fake_repo_path) { File.join(TestEnv.repos_path, @to_user.namespace.full_path, "#{@from_project.path}.git") }
let(:repository_storage_path) { Gitlab.config.repositories.storages[repository_storage].legacy_disk_path }
let(:params) { { namespace: @to_user.namespace } } let(:params) { { namespace: @to_user.namespace } }
before do before do
stub_application_setting(hashed_storage_enabled: false) stub_application_setting(hashed_storage_enabled: false)
gitlab_shell.create_repository(repository_storage, "#{@to_user.namespace.full_path}/#{@from_project.path}", "#{@to_user.namespace.full_path}/#{@from_project.path}") TestEnv.create_bare_repository(fake_repo_path)
end end
after do after do
gitlab_shell.remove_repository(repository_storage, "#{@to_user.namespace.full_path}/#{@from_project.path}") FileUtils.rm_rf(fake_repo_path)
end end
subject { fork_project(@from_project, @to_user, params) } subject { fork_project(@from_project, @to_user, params) }
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment