Merge branch 'avatar-vue' into auto-pipelines-vue
This commit is contained in:
commit
2b198ee808
136 changed files with 948 additions and 382 deletions
|
@ -61,9 +61,10 @@ update-knapsack:
|
|||
- scripts/merge-reports knapsack/spinach_report.json knapsack/spinach_node_*.json
|
||||
- rm -f knapsack/*_node_*.json
|
||||
only:
|
||||
- master
|
||||
|
||||
# Execute all testing suites
|
||||
- master@gitlab-org/gitlab-ce
|
||||
- master@gitlab-org/gitlab-ee
|
||||
- master@gitlab/gitlabhq
|
||||
- master@gitlab/gitlab-ee
|
||||
|
||||
.use-db: &use-db
|
||||
services:
|
||||
|
@ -143,7 +144,10 @@ spinach 9 10: *spinach-knapsack
|
|||
image: "dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.1-git-2.7-phantomjs-2.1"
|
||||
<<: *use-db
|
||||
only:
|
||||
- master
|
||||
- master@gitlab-org/gitlab-ce
|
||||
- master@gitlab-org/gitlab-ee
|
||||
- master@gitlab/gitlabhq
|
||||
- master@gitlab/gitlab-ee
|
||||
cache:
|
||||
key: "ruby21"
|
||||
paths:
|
||||
|
@ -286,7 +290,10 @@ bundler:audit:
|
|||
stage: test
|
||||
<<: *ruby-static-analysis
|
||||
only:
|
||||
- master
|
||||
- master@gitlab-org/gitlab-ce
|
||||
- master@gitlab-org/gitlab-ee
|
||||
- master@gitlab/gitlabhq
|
||||
- master@gitlab/gitlab-ee
|
||||
script:
|
||||
- "bundle exec bundle-audit check --update --ignore OSVDB-115941"
|
||||
|
||||
|
@ -297,6 +304,9 @@ migration paths:
|
|||
SETUP_DB: "false"
|
||||
only:
|
||||
- master@gitlab-org/gitlab-ce
|
||||
- master@gitlab-org/gitlab-ee
|
||||
- master@gitlab/gitlabhq
|
||||
- master@gitlab/gitlab-ee
|
||||
script:
|
||||
- git checkout HEAD .
|
||||
- git fetch --tags
|
||||
|
|
|
@ -55,4 +55,36 @@
|
|||
</svg>
|
||||
`,
|
||||
});
|
||||
|
||||
gl.VueCanceledIcon = Vue.extend({
|
||||
template: `
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" class="ci-status-icon-canceled" viewBox="0 0 14 14">
|
||||
<g fill="#5C5C5C" fill-rule="evenodd">
|
||||
<path d="M12.5,7 C12.5,3.96243388 10.0375661,1.5 7,1.5 C3.96243388,1.5 1.5,3.96243388 1.5,7 C1.5,10.0375661 3.96243388,12.5 7,12.5 C10.0375661,12.5 12.5,10.0375661 12.5,7 Z M0,7 C0,3.13400675 3.13400675,0 7,0 C10.8659932,0 14,3.13400675 14,7 C14,10.8659932 10.8659932,14 7,14 C3.13400675,14 0,10.8659932 0,7 Z"></path>
|
||||
<rect width="8" height="2" x="3" y="6" transform="rotate(45 7 7)" rx=".5"></rect>
|
||||
</g>
|
||||
</svg>
|
||||
`,
|
||||
});
|
||||
|
||||
gl.VueSkippedIcon = Vue.extend({
|
||||
template: `
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 40 40">
|
||||
<g fill="#8F8F8F" fill-rule="evenodd">
|
||||
<path d="M29.513 10.134A15.922 15.922 0 0 0 23 7.28V6h2.993C26.55 6 27 5.552 27 5V2a1 1 0 0 0-1.007-1H14.007C13.45 1 13 1.448 13 2v3a1 1 0 0 0 1.007 1H17v1.28C9.597 8.686 4 15.19 4 23c0 8.837 7.163 16 16 16s16-7.163 16-16c0-3.461-1.099-6.665-2.967-9.283l1.327-1.58a2.498 2.498 0 0 0-.303-3.53 2.499 2.499 0 0 0-3.528.315l-1.016 1.212zM20 34c6.075 0 11-4.925 11-11s-4.925-11-11-11S9 16.925 9 23s4.925 11 11 11z"/><path d="M19 21h-4.002c-.552 0-.998.452-.998 1.01v1.98c0 .567.447 1.01.998 1.01h7.004c.274 0 .521-.111.701-.291a.979.979 0 0 0 .297-.704v-8.01c0-.54-.452-.995-1.01-.995h-1.98a.997.997 0 0 0-1.01.995V21z"/>
|
||||
</g>
|
||||
</svg>
|
||||
`,
|
||||
});
|
||||
|
||||
gl.VueUnstableIcon = Vue.extend({
|
||||
template: `
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14">
|
||||
<g fill="#FF8A24" fill-rule="evenodd">
|
||||
<path d="M12.5,7 C12.5,3.96243388 10.0375661,1.5 7,1.5 C3.96243388,1.5 1.5,3.96243388 1.5,7 C1.5,10.0375661 3.96243388,12.5 7,12.5 C10.0375661,12.5 12.5,10.0375661 12.5,7 Z M0,7 C0,3.13400675 3.13400675,0 7,0 C10.8659932,0 14,3.13400675 14,7 C14,10.8659932 10.8659932,14 7,14 C3.13400675,14 0,10.8659932 0,7 Z"/>
|
||||
<path d="M6,3.49769878 C6,3.22282734 6.21403503,3 6.50468445,3 L7.49531555,3 C7.77404508,3 8,3.21484375 8,3.49769878 L8,7.50230122 C8,7.77717266 7.78596497,8 7.49531555,8 L6.50468445,8 C6.22595492,8 6,7.78515625 6,7.50230122 L6,3.49769878 Z M6,9.50468445 C6,9.22595492 6.21403503,9 6.50468445,9 L7.49531555,9 C7.77404508,9 8,9.21403503 8,9.50468445 L8,10.4953156 C8,10.7740451 7.78596497,11 7.49531555,11 L6.50468445,11 C6.22595492,11 6,10.785965 6,10.4953156 L6,9.50468445 Z"/>
|
||||
</g>
|
||||
</svg
|
||||
`,
|
||||
});
|
||||
})(window.gl || (window.gl = {}));
|
||||
|
|
|
@ -11,13 +11,17 @@
|
|||
alt() {
|
||||
return `${this.pipeline.commit.author_name}'s avatar`;
|
||||
},
|
||||
avatarUrl() {
|
||||
const author = this.pipeline.commit.author;
|
||||
if (author) return author.avatar_url;
|
||||
return this.pipeline.commit.author_gravatar_url;
|
||||
},
|
||||
},
|
||||
template: `
|
||||
<td class="branch-commit">
|
||||
<div class="icon-container">
|
||||
<i class="fa fa-code-fork"></i>
|
||||
</div>
|
||||
<!-- ** will need branch_url for this branch ** -->
|
||||
<a
|
||||
class="monospace branch-name"
|
||||
:href='pipeline.ref.url'
|
||||
|
@ -45,7 +49,7 @@
|
|||
:alt='alt'
|
||||
:title='pipeline.commit.author_name'
|
||||
data-container="body"
|
||||
src="http://www.gravatar.com/avatar/80d3b651b4be1f1db39435c2d11f1f23?s=40&d=identicon"
|
||||
:src='avatarUrl'
|
||||
>
|
||||
</a>
|
||||
<a
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* global Vue, VueResource, gl */
|
||||
/* eslint-disable no-bitwise*/
|
||||
/* eslint-disable no-bitwise, no-plusplus*/
|
||||
|
||||
//= require vue-resource
|
||||
|
||||
|
|
|
@ -10,14 +10,6 @@
|
|||
download(name) {
|
||||
return `Download ${name} artifacts`;
|
||||
},
|
||||
// retry(e) {
|
||||
// e.preventDefault();
|
||||
// this.$http.post(this.pipeline.retry_url, {
|
||||
// pipeline: { id: this.pipeline.id },
|
||||
// })
|
||||
// .then(() => {})
|
||||
// .catch(() => new Flash('Something went wrong on our end.'));
|
||||
// },
|
||||
},
|
||||
template: `
|
||||
<td class="pipeline-actions hidden-xs">
|
||||
|
@ -41,7 +33,7 @@
|
|||
</a>
|
||||
<ul class="dropdown-menu dropdown-menu-align-right">
|
||||
<li v-for='action in pipeline.details.manual_actions'>
|
||||
<a rel="nofollow" data-method="post" :href='action.url'>
|
||||
<a rel="nofollow" data-method="post" :href='action.url' title="Manual build">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 11" class="icon-play">
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
|
@ -78,9 +70,8 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="cancel-retry-btns inline">
|
||||
<!-- @click='retry($event)' -->
|
||||
<a
|
||||
v-if='!pipeline.cancel_url || pipeline.details.status !== "cancelled"'
|
||||
v-if='pipeline.retry_url'
|
||||
class="btn has-tooltip"
|
||||
title="Retry"
|
||||
rel="nofollow"
|
||||
|
@ -92,7 +83,7 @@
|
|||
<a
|
||||
v-if='pipeline.cancel_url'
|
||||
class="btn btn-remove has-tooltip"
|
||||
title=""
|
||||
title="Cancel"
|
||||
rel="nofollow"
|
||||
data-method="post"
|
||||
:href='pipeline.cancel_url'
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
'failed-icon': gl.VueFailedIcon,
|
||||
'success-icon': gl.VueSuccessIcon,
|
||||
'created-icon': gl.VueCreatedIcon,
|
||||
'canceled-icon': gl.VueCanceledIcon,
|
||||
},
|
||||
props: ['stage'],
|
||||
computed: {
|
||||
|
@ -30,6 +31,7 @@
|
|||
<failed-icon v-if='stage.status === "failed"'></failed-icon>
|
||||
<pending-icon v-if='stage.status === "pending"'></pending-icon>
|
||||
<created-icon v-if='stage.status === "created"'></created-icon>
|
||||
<canceled-icon v-if='stage.status === "canceled"'></canceled-icon>
|
||||
</a>
|
||||
`,
|
||||
});
|
||||
|
|
|
@ -28,6 +28,15 @@
|
|||
|
||||
gl.PipelineStore = class {
|
||||
fetchDataLoop(Vue, pageNum, url) {
|
||||
Vue.activeResources = 0;
|
||||
const resourceChecker = () => {
|
||||
if (Vue.activeResources === 0) {
|
||||
Vue.activeResources = 1;
|
||||
} else {
|
||||
Vue.activeResources += 1;
|
||||
}
|
||||
};
|
||||
|
||||
const goFetch = () =>
|
||||
this.$http.get(`${url}?page=${pageNum}`)
|
||||
.then((response) => {
|
||||
|
@ -36,6 +45,7 @@
|
|||
Vue.set(this, 'pipelines', res.pipelines);
|
||||
Vue.set(this, 'count', res.count);
|
||||
this.pageRequest = false;
|
||||
Vue.activeResources -= 1;
|
||||
}, () => new Flash(
|
||||
'Something went wrong on our end.'
|
||||
));
|
||||
|
@ -45,15 +55,22 @@
|
|||
.then((response) => {
|
||||
const res = JSON.parse(response.body);
|
||||
const p = new PipelineUpdater(this.pipelines);
|
||||
Vue.set(this, 'updatedAt', res.updated_at);
|
||||
Vue.set(this, 'pipelines', p.updatePipelines(res));
|
||||
Vue.set(this, 'count', res.count);
|
||||
Vue.activeResources -= 1;
|
||||
}, () => new Flash(
|
||||
'Something went wrong on our end.'
|
||||
));
|
||||
|
||||
resourceChecker();
|
||||
goFetch();
|
||||
|
||||
this.intervalId = setInterval(() => {
|
||||
if (this.updatedAt) goUpdate();
|
||||
if (this.updatedAt) {
|
||||
resourceChecker();
|
||||
goUpdate();
|
||||
}
|
||||
}, 3000);
|
||||
|
||||
window.onbeforeunload = function removePipelineInterval() {
|
||||
|
|
|
@ -19,15 +19,12 @@
|
|||
seconds(date) {
|
||||
return this.formatSection(date.getSeconds());
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
// need started_at or created_at for finish and running
|
||||
finishdate() {
|
||||
const date = new Date(
|
||||
new Date(
|
||||
this.pipeline.details.finished_at
|
||||
).getTime() - new Date(
|
||||
this.pipeline.started_at
|
||||
this.pipeline.created_at
|
||||
).getTime()
|
||||
);
|
||||
return (
|
||||
|
@ -36,7 +33,7 @@
|
|||
},
|
||||
runningdate() {
|
||||
const date = new Date(
|
||||
new Date().getTime() - new Date(this.pipeline.started_at).getTime()
|
||||
new Date().getTime() - new Date(this.pipeline.created_at).getTime()
|
||||
);
|
||||
return (
|
||||
`${this.hours(date)}:${this.minutes(date)}:${this.seconds(date)}`
|
||||
|
@ -61,8 +58,8 @@
|
|||
};
|
||||
},
|
||||
duration() {
|
||||
if (this.timeStopped) return this.finishdate;
|
||||
return this.runningdate;
|
||||
if (this.timeStopped()) return this.finishdate();
|
||||
return this.runningdate();
|
||||
},
|
||||
},
|
||||
template: `
|
||||
|
@ -78,9 +75,9 @@
|
|||
<path d="M29.513 10.134A15.922 15.922 0 0 0 23 7.28V6h2.993C26.55 6 27 5.552 27 5V2a1 1 0 0 0-1.007-1H14.007C13.45 1 13 1.448 13 2v3a1 1 0 0 0 1.007 1H17v1.28C9.597 8.686 4 15.19 4 23c0 8.837 7.163 16 16 16s16-7.163 16-16c0-3.461-1.099-6.665-2.967-9.283l1.327-1.58a2.498 2.498 0 0 0-.303-3.53 2.499 2.499 0 0 0-3.528.315l-1.016 1.212zM20 34c6.075 0 11-4.925 11-11s-4.925-11-11-11S9 16.925 9 23s4.925 11 11 11z"></path><path d="M19 21h-4.002c-.552 0-.998.452-.998 1.01v1.98c0 .567.447 1.01.998 1.01h7.004c.274 0 .521-.111.701-.291a.979.979 0 0 0 .297-.704v-8.01c0-.54-.452-.995-1.01-.995h-1.98a.997.997 0 0 0-1.01.995V21z"></path>
|
||||
</g>
|
||||
</svg>
|
||||
{{duration}}
|
||||
{{duration()}}
|
||||
</p>
|
||||
<p class="finished-at" v-if='timeStopped'>
|
||||
<p class="finished-at" v-if='timeStopped()'>
|
||||
<i class="fa fa-calendar"></i>
|
||||
<time
|
||||
data-toggle="tooltip"
|
||||
|
@ -88,7 +85,7 @@
|
|||
data-container="body"
|
||||
:data-original-title='9 + 9'
|
||||
>
|
||||
{{timeStopped.words}}
|
||||
{{timeStopped().words}}
|
||||
</time>
|
||||
</p>
|
||||
</td>
|
||||
|
|
23
app/assets/javascripts/vue_pipelines_status/canceled.js.es6
Normal file
23
app/assets/javascripts/vue_pipelines_status/canceled.js.es6
Normal file
|
@ -0,0 +1,23 @@
|
|||
/* global Vue, gl */
|
||||
/* eslint-disable no-param-reassign */
|
||||
|
||||
((gl) => {
|
||||
gl.VueCanceledScope = Vue.extend({
|
||||
components: {
|
||||
'vue-canceled-icon': gl.VueCanceledIcon,
|
||||
},
|
||||
props: [
|
||||
'pipeline',
|
||||
],
|
||||
template: `
|
||||
<td class="commit-link">
|
||||
<a :href='pipeline.url'>
|
||||
<span class="ci-status ci-canceled">
|
||||
<vue-canceled-icon></vue-canceled-icon>
|
||||
canceled
|
||||
</span>
|
||||
</a>
|
||||
</td>
|
||||
`,
|
||||
});
|
||||
})(window.gl || (window.gl = {}));
|
|
@ -1,4 +1,7 @@
|
|||
//= require ./pending.js.es6
|
||||
//= require ./failed.js.es6
|
||||
//= require ./running.js.es6
|
||||
//= require ./canceled.js.es6
|
||||
//= require ./status.js.es6
|
||||
//= require ./unstable.js.es6
|
||||
//= require ./skipped.js.es6
|
||||
|
|
23
app/assets/javascripts/vue_pipelines_status/skipped.js.es6
Normal file
23
app/assets/javascripts/vue_pipelines_status/skipped.js.es6
Normal file
|
@ -0,0 +1,23 @@
|
|||
/* global Vue, gl */
|
||||
/* eslint-disable no-param-reassign */
|
||||
|
||||
((gl) => {
|
||||
gl.VueSkippedScope = Vue.extend({
|
||||
components: {
|
||||
'vue-skipped-icon': gl.VueSkippedIcon,
|
||||
},
|
||||
props: [
|
||||
'pipeline',
|
||||
],
|
||||
template: `
|
||||
<td class="commit-link">
|
||||
<a :href='pipeline.url'>
|
||||
<span class="ci-status ci-skipped">
|
||||
<vue-skipped-icon></vue-skipped-icon>
|
||||
skipped
|
||||
</span>
|
||||
</a>
|
||||
</td>
|
||||
`,
|
||||
});
|
||||
})(window.gl || (window.gl = {}));
|
|
@ -8,6 +8,8 @@
|
|||
'vue-pending-scope': gl.VuePendingScope,
|
||||
'vue-failed-scope': gl.VueFailedScope,
|
||||
'vue-created-scope': gl.VueCreatedScope,
|
||||
'vue-canceled-scope': gl.VueCanceledScope,
|
||||
'vue-unstable-scope': gl.VueUnstableScope,
|
||||
},
|
||||
props: [
|
||||
'pipeline',
|
||||
|
@ -34,6 +36,16 @@
|
|||
:pipeline='pipeline'
|
||||
>
|
||||
</vue-created-scope>
|
||||
<vue-canceled-scope
|
||||
v-if="pipeline.details.status === 'canceled'"
|
||||
:pipeline='pipeline'
|
||||
>
|
||||
</vue-canceled-scope>
|
||||
<vue-unstable-scope
|
||||
v-if="pipeline.details.status === 'unstable'"
|
||||
:pipeline='pipeline'
|
||||
>
|
||||
</vue-unstable-scope>
|
||||
</td>
|
||||
`,
|
||||
});
|
||||
|
|
23
app/assets/javascripts/vue_pipelines_status/unstable.js.es6
Normal file
23
app/assets/javascripts/vue_pipelines_status/unstable.js.es6
Normal file
|
@ -0,0 +1,23 @@
|
|||
/* global Vue, gl */
|
||||
/* eslint-disable no-param-reassign */
|
||||
|
||||
((gl) => {
|
||||
gl.VueUnstableScope = Vue.extend({
|
||||
components: {
|
||||
'vue-unstable-icon': gl.VueUnstableIcon,
|
||||
},
|
||||
props: [
|
||||
'pipeline',
|
||||
],
|
||||
template: `
|
||||
<td class="commit-link">
|
||||
<a :href='pipeline.url'>
|
||||
<span class="ci-status ci-unstable">
|
||||
<vue-unstable-icon></vue-unstable-icon>
|
||||
unstable
|
||||
</span>
|
||||
</a>
|
||||
</td>
|
||||
`,
|
||||
});
|
||||
})(window.gl || (window.gl = {}));
|
|
@ -63,6 +63,7 @@ header {
|
|||
&:focus,
|
||||
&:active {
|
||||
background-color: $background-color;
|
||||
color: darken($gl-icon-color, 50%);
|
||||
}
|
||||
|
||||
.fa-caret-down {
|
||||
|
@ -191,6 +192,10 @@ header {
|
|||
font-size: 10px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: darken($color: $gl-text-color, $amount: 50%);
|
||||
}
|
||||
}
|
||||
|
||||
.project-item-select {
|
||||
|
|
|
@ -84,7 +84,8 @@
|
|||
font-weight: 600;
|
||||
}
|
||||
|
||||
.commit {
|
||||
.commit,
|
||||
.generic_commit_status {
|
||||
padding: 10px 0;
|
||||
position: relative;
|
||||
|
||||
|
@ -102,7 +103,6 @@
|
|||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
|
||||
.avatar {
|
||||
margin-left: -46px;
|
||||
}
|
||||
|
|
|
@ -109,10 +109,6 @@
|
|||
float: none;
|
||||
}
|
||||
|
||||
.api {
|
||||
color: $code-color;
|
||||
}
|
||||
|
||||
.branch-commit {
|
||||
|
||||
.branch-name {
|
||||
|
|
|
@ -21,6 +21,11 @@
|
|||
padding: 4px;
|
||||
width: $search-input-width;
|
||||
line-height: 24px;
|
||||
|
||||
&:hover {
|
||||
border-color: lighten($dropdown-input-focus-border, 20%);
|
||||
box-shadow: 0 0 4px lighten($search-input-focus-shadow-color, 20%);
|
||||
}
|
||||
}
|
||||
|
||||
.location-text {
|
||||
|
@ -153,6 +158,7 @@
|
|||
width: 68%;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.search-holder {
|
||||
|
@ -229,4 +235,5 @@
|
|||
&:focus {
|
||||
color: $gl-link-color;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,8 +7,8 @@ class HelpController < ApplicationController
|
|||
@help_index = File.read(Rails.root.join('doc', 'README.md'))
|
||||
|
||||
# Prefix Markdown links with `help/` unless they already have been
|
||||
# See http://rubular.com/r/nwwhzH6Z8X
|
||||
@help_index.gsub!(/(\]\()(?!help\/)([^\)\(]+)(\))/, '\1help/\2\3')
|
||||
# See http://rubular.com/r/ie2MlpdUMq
|
||||
@help_index.gsub!(/(\]\()(\/?help\/)?([^\)\(]+\))/, '\1/help/\3')
|
||||
end
|
||||
|
||||
def show
|
||||
|
|
|
@ -507,6 +507,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
|
|||
@merge_request.close
|
||||
end
|
||||
|
||||
labels
|
||||
define_pipelines_vars
|
||||
end
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ module AuthHelper
|
|||
FORM_BASED_PROVIDERS = [/\Aldap/, 'crowd'].freeze
|
||||
|
||||
def ldap_enabled?
|
||||
Gitlab.config.ldap.enabled
|
||||
Gitlab::LDAP::Config.enabled?
|
||||
end
|
||||
|
||||
def omniauth_enabled?
|
||||
|
|
|
@ -82,6 +82,10 @@ module GitlabRoutingHelper
|
|||
namespace_project_merge_request_path(entity.project.namespace, entity.project, entity, *args)
|
||||
end
|
||||
|
||||
def pipeline_path(pipeline, *args)
|
||||
namespace_project_pipeline_path(pipeline.project.namespace, pipeline.project, pipeline.id, *args)
|
||||
end
|
||||
|
||||
def milestone_path(entity, *args)
|
||||
namespace_project_milestone_path(entity.project.namespace, entity.project, entity, *args)
|
||||
end
|
||||
|
|
|
@ -203,6 +203,10 @@ class ApplicationSetting < ActiveRecord::Base
|
|||
ActiveRecord::Base.connection.column_exists?(:application_settings, :home_page_url)
|
||||
end
|
||||
|
||||
def sidekiq_throttling_column_exists?
|
||||
ActiveRecord::Base.connection.column_exists?(:application_settings, :sidekiq_throttling_enabled)
|
||||
end
|
||||
|
||||
def domain_whitelist_raw
|
||||
self.domain_whitelist.join("\n") unless self.domain_whitelist.nil?
|
||||
end
|
||||
|
@ -256,6 +260,12 @@ class ApplicationSetting < ActiveRecord::Base
|
|||
ensure_health_check_access_token!
|
||||
end
|
||||
|
||||
def sidekiq_throttling_enabled?
|
||||
return false unless sidekiq_throttling_column_exists?
|
||||
|
||||
sidekiq_throttling_enabled
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def check_repository_storages
|
||||
|
|
|
@ -266,7 +266,7 @@ class Issue < ActiveRecord::Base
|
|||
|
||||
def as_json(options = {})
|
||||
super(options).tap do |json|
|
||||
json[:subscribed] = subscribed?(options[:user]) if options.has_key?(:user)
|
||||
json[:subscribed] = subscribed?(options[:user]) if options.has_key?(:user) && options[:user]
|
||||
|
||||
if options.has_key?(:labels)
|
||||
json[:labels] = labels.as_json(
|
||||
|
|
|
@ -7,6 +7,7 @@ class Note < ActiveRecord::Base
|
|||
include Importable
|
||||
include FasterCacheKeys
|
||||
include CacheMarkdownField
|
||||
include AfterCommitQueue
|
||||
|
||||
cache_markdown_field :note, pipeline: :note
|
||||
|
||||
|
|
|
@ -1334,6 +1334,10 @@ class Project < ActiveRecord::Base
|
|||
end
|
||||
end
|
||||
|
||||
def only_allow_merge_if_all_discussions_are_resolved
|
||||
super || false
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def pushes_since_gc_redis_key
|
||||
|
|
|
@ -49,20 +49,14 @@ class ProjectFeature < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def builds_enabled?
|
||||
return true unless builds_access_level
|
||||
|
||||
builds_access_level > DISABLED
|
||||
end
|
||||
|
||||
def wiki_enabled?
|
||||
return true unless wiki_access_level
|
||||
|
||||
wiki_access_level > DISABLED
|
||||
end
|
||||
|
||||
def merge_requests_enabled?
|
||||
return true unless merge_requests_access_level
|
||||
|
||||
merge_requests_access_level > DISABLED
|
||||
end
|
||||
|
||||
|
|
|
@ -26,9 +26,12 @@ module Notes
|
|||
note.note = content
|
||||
end
|
||||
|
||||
if !only_commands && note.save
|
||||
note.run_after_commit do
|
||||
# Finish the harder work in the background
|
||||
NewNoteWorker.perform_in(2.seconds, note.id, params)
|
||||
NewNoteWorker.perform_async(note.id)
|
||||
end
|
||||
|
||||
if !only_commands && note.save
|
||||
todo_service.new_note(note, current_user)
|
||||
end
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%board-sidebar{ "inline-template" => true,
|
||||
":current-user" => "#{current_user.to_json(only: [:username, :id, :name], methods: [:avatar_url]) if current_user}" }
|
||||
":current-user" => "#{current_user ? current_user.to_json(only: [:username, :id, :name], methods: [:avatar_url]) : {}}" }
|
||||
%aside.right-sidebar.right-sidebar-expanded.issue-boards-sidebar{ "v-show" => "showSidebar" }
|
||||
.issuable-sidebar
|
||||
.block.issuable-sidebar-header
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
.block.assignee
|
||||
.title.hide-collapsed
|
||||
Assignee
|
||||
= icon("spinner spin", class: "block-loading")
|
||||
- if can?(current_user, :admin_issue, @project)
|
||||
= icon("spinner spin", class: "block-loading")
|
||||
= link_to "Edit", "#", class: "edit-link pull-right"
|
||||
.value.hide-collapsed
|
||||
%span.assign-yourself.no-value{ "v-if" => "!issue.assignee" }
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
.block.due_date
|
||||
.title
|
||||
Due date
|
||||
= icon("spinner spin", class: "block-loading")
|
||||
- if can?(current_user, :admin_issue, @project)
|
||||
= icon("spinner spin", class: "block-loading")
|
||||
= link_to "Edit", "#", class: "edit-link pull-right"
|
||||
.value
|
||||
.value-content
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
.block.labels
|
||||
.title
|
||||
Labels
|
||||
= icon("spinner spin", class: "block-loading")
|
||||
- if can?(current_user, :admin_issue, @project)
|
||||
= icon("spinner spin", class: "block-loading")
|
||||
= link_to "Edit", "#", class: "edit-link pull-right"
|
||||
.value.issuable-show-labels
|
||||
%span.no-value{ "v-if" => "issue.labels && issue.labels.length === 0" }
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
.block.milestone
|
||||
.title
|
||||
Milestone
|
||||
= icon("spinner spin", class: "block-loading")
|
||||
- if can?(current_user, :admin_issue, @project)
|
||||
= icon("spinner spin", class: "block-loading")
|
||||
= link_to "Edit", "#", class: "edit-link pull-right"
|
||||
.value
|
||||
%span.no-value{ "v-if" => "!issue.milestone" }
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
= ci_status_with_icon(@build.status)
|
||||
Build
|
||||
%strong ##{@build.id}
|
||||
in pipeline
|
||||
= link_to pipeline_path(@build.pipeline) do
|
||||
%strong ##{@build.pipeline.id}
|
||||
for commit
|
||||
= link_to ci_status_path(@build.pipeline) do
|
||||
%strong= @build.pipeline.short_sha
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
%tr
|
||||
%th Status
|
||||
%th Build
|
||||
%th Pipeline
|
||||
- if admin
|
||||
%th Project
|
||||
%th Runner
|
||||
|
@ -19,6 +20,6 @@
|
|||
%th Coverage
|
||||
%th
|
||||
|
||||
= render partial: "projects/ci/builds/build", collection: builds, as: :build, locals: { commit_sha: true, ref: true, stage: true, allow_retry: true, coverage: admin || project.build_coverage_enabled?, admin: admin }
|
||||
= render partial: "projects/ci/builds/build", collection: builds, as: :build, locals: { commit_sha: true, ref: true, pipeline_link: true, stage: true, allow_retry: true, coverage: admin || project.build_coverage_enabled?, admin: admin }
|
||||
|
||||
= paginate builds, theme: 'gitlab'
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
- if !project.empty_repo? && can?(current_user, :download_code, project)
|
||||
%span{class: 'hidden-xs hidden-sm download-button'}
|
||||
%span{class: 'download-button'}
|
||||
.dropdown.inline
|
||||
%button.btn{ 'data-toggle' => 'dropdown' }
|
||||
= icon('download')
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
- ref = local_assigns.fetch(:ref, nil)
|
||||
- commit_sha = local_assigns.fetch(:commit_sha, nil)
|
||||
- retried = local_assigns.fetch(:retried, false)
|
||||
- pipeline_link = local_assigns.fetch(:pipeline_link, false)
|
||||
- stage = local_assigns.fetch(:stage, false)
|
||||
- coverage = local_assigns.fetch(:coverage, false)
|
||||
- allow_retry = local_assigns.fetch(:allow_retry, false)
|
||||
|
@ -51,6 +52,16 @@
|
|||
- if build.manual?
|
||||
%span.label.label-info manual
|
||||
|
||||
- if pipeline_link
|
||||
%td
|
||||
= link_to pipeline_path(build.pipeline) do
|
||||
%span.pipeline-id ##{build.pipeline.id}
|
||||
%span by
|
||||
- if build.pipeline.user
|
||||
= user_avatar(user: build.pipeline.user, size: 20)
|
||||
- else
|
||||
%span.monospace API
|
||||
|
||||
- if admin
|
||||
%td
|
||||
- if build.project
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
- if stage
|
||||
|
||||
= stage.titleize
|
||||
= render statuses.latest_ci_stages, coverage: @project.build_coverage_enabled?, stage: false, ref: false, allow_retry: true
|
||||
= render statuses.retried_ci_stages, coverage: @project.build_coverage_enabled?, stage: false, ref: false, retried: true
|
||||
%tr
|
||||
%td{colspan: 10}
|
||||
|
||||
= render statuses.latest_ci_stages, coverage: @project.build_coverage_enabled?, stage: false, ref: false, pipeline_link: false, allow_retry: true
|
||||
= render statuses.retried_ci_stages, coverage: @project.build_coverage_enabled?, stage: false, ref: false, pipeline_link: false, retried: true
|
||||
%tr
|
||||
%td{colspan: 10}
|
||||
|
||||
|
|
|
@ -15,6 +15,16 @@
|
|||
- if defined?(retried) && retried
|
||||
= icon('warning', class: 'text-warning has-tooltip', title: 'Status was retried.')
|
||||
|
||||
- if defined?(pipeline_link) && pipeline_link
|
||||
%td
|
||||
= link_to pipeline_path(generic_commit_status.pipeline) do
|
||||
%span.pipeline-id ##{generic_commit_status.pipeline.id}
|
||||
%span by
|
||||
- if generic_commit_status.pipeline.user
|
||||
= user_avatar(user: generic_commit_status.pipeline.user, size: 20)
|
||||
- else
|
||||
%span.monospace API
|
||||
|
||||
- if defined?(commit_sha) && commit_sha
|
||||
%td
|
||||
= link_to generic_commit_status.short_sha, namespace_project_commit_path(generic_commit_status.project.namespace, generic_commit_status.project, generic_commit_status.sha), class: "monospace"
|
||||
|
|
|
@ -90,7 +90,8 @@
|
|||
= f.label :visibility_level, class: 'label-light' do
|
||||
Visibility Level
|
||||
= link_to "(?)", help_page_path("public_access/public_access")
|
||||
= render('shared/visibility_radios', model_method: :visibility_level, form: f, selected_level: @project.visibility_level, form_model: @project)
|
||||
= render 'shared/visibility_level', f: f, visibility_level: default_project_visibility, can_change_visibility_level: true, form_model: @project
|
||||
|
||||
|
||||
= f.submit 'Create project', class: "btn btn-create project-submit", tabindex: 4
|
||||
= link_to 'Cancel', dashboard_projects_path, class: 'btn btn-cancel'
|
||||
|
|
|
@ -2,10 +2,12 @@ class NewNoteWorker
|
|||
include Sidekiq::Worker
|
||||
include DedicatedSidekiqQueue
|
||||
|
||||
def perform(note_id, note_params)
|
||||
note = Note.find(note_id)
|
||||
|
||||
NotificationService.new.new_note(note)
|
||||
Notes::PostProcessService.new(note).execute
|
||||
def perform(note_id)
|
||||
if note = Note.find_by(id: note_id)
|
||||
NotificationService.new.new_note(note)
|
||||
Notes::PostProcessService.new(note).execute
|
||||
else
|
||||
Rails.logger.error("NewNoteWorker: couldn't find note with ID=#{note_id}, skipping job")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
title: Add link to build pipeline within individual build pages
|
||||
merge_request: 7082
|
||||
author:
|
4
changelogs/unreleased/24397-load-labels-on-mr-tabs.yml
Normal file
4
changelogs/unreleased/24397-load-labels-on-mr-tabs.yml
Normal file
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
title: Fix issue causing Labels not to appear in sidebar on MR page
|
||||
merge_request: 7416
|
||||
author: Alex Sanford
|
4
changelogs/unreleased/always-show-download-button.yml
Normal file
4
changelogs/unreleased/always-show-download-button.yml
Normal file
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
title: Project download buttons always show
|
||||
merge_request: 7405
|
||||
author: Philip Karpiak
|
4
changelogs/unreleased/fix-help-page-links.yml
Normal file
4
changelogs/unreleased/fix-help-page-links.yml
Normal file
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
title: Fix error links in help index page
|
||||
merge_request: 7396
|
||||
author: Fu Xu
|
4
changelogs/unreleased/issue_20245.yml
Normal file
4
changelogs/unreleased/issue_20245.yml
Normal file
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
title: Fix project Visibility Level selector not using default values
|
||||
merge_request:
|
||||
author:
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
title: Fix record not found error on NewNoteWorker processing
|
||||
merge_request: 6863
|
||||
author: Oswaldo Ferreira
|
4
changelogs/unreleased/repository-name-emojis
Normal file
4
changelogs/unreleased/repository-name-emojis
Normal file
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
title: Added ability to put emojis into repository name
|
||||
merge_request: 7420
|
||||
author: Vincent Composieux
|
4
changelogs/unreleased/user_filter_auth.yml
Normal file
4
changelogs/unreleased/user_filter_auth.yml
Normal file
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
title: Centralize LDAP config/filter logic
|
||||
merge_request: 6606
|
||||
author:
|
|
@ -3,8 +3,8 @@
|
|||
#
|
||||
production:
|
||||
adapter: mysql2
|
||||
encoding: utf8
|
||||
collation: utf8_general_ci
|
||||
encoding: utf8mb4
|
||||
collation: utf8mb4_general_ci
|
||||
reconnect: false
|
||||
database: gitlabhq_production
|
||||
pool: 10
|
||||
|
@ -18,8 +18,8 @@ production:
|
|||
#
|
||||
development:
|
||||
adapter: mysql2
|
||||
encoding: utf8
|
||||
collation: utf8_general_ci
|
||||
encoding: utf8mb4
|
||||
collation: utf8mb4_general_ci
|
||||
reconnect: false
|
||||
database: gitlabhq_development
|
||||
pool: 5
|
||||
|
@ -32,8 +32,8 @@ development:
|
|||
# Do not set this db to the same as development or production.
|
||||
test: &test
|
||||
adapter: mysql2
|
||||
encoding: utf8
|
||||
collation: utf8_general_ci
|
||||
encoding: utf8mb4
|
||||
collation: utf8mb4_general_ci
|
||||
reconnect: false
|
||||
database: gitlabhq_test
|
||||
pool: 5
|
||||
|
|
|
@ -213,22 +213,9 @@ Devise.setup do |config|
|
|||
end
|
||||
|
||||
if Gitlab::LDAP::Config.enabled?
|
||||
Gitlab.config.ldap.servers.values.each do |server|
|
||||
if server['allow_username_or_email_login']
|
||||
email_stripping_proc = ->(name) {name.gsub(/@.*\z/, '')}
|
||||
else
|
||||
email_stripping_proc = ->(name) {name}
|
||||
end
|
||||
|
||||
config.omniauth server['provider_name'],
|
||||
host: server['host'],
|
||||
base: server['base'],
|
||||
uid: server['uid'],
|
||||
port: server['port'],
|
||||
method: server['method'],
|
||||
bind_dn: server['bind_dn'],
|
||||
password: server['password'],
|
||||
name_proc: email_stripping_proc
|
||||
Gitlab::LDAP::Config.providers.each do |provider|
|
||||
ldap_config = Gitlab::LDAP::Config.new(provider)
|
||||
config.omniauth(provider, ldap_config.omniauth_options)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ listen "127.0.0.1:8080", :tcp_nopush => true
|
|||
# nuke workers after 30 seconds instead of 60 seconds (the default)
|
||||
#
|
||||
# NOTICE: git push over http depends on this value.
|
||||
# If you want be able to push huge amount of data to git repository over http
|
||||
# If you want to be able to push huge amount of data to git repository over http
|
||||
# you will have to increase this value too.
|
||||
#
|
||||
# Example of output if you try to push 1GB repo to GitLab over http.
|
||||
|
@ -82,7 +82,7 @@ GC.respond_to?(:copy_on_write_friendly=) and
|
|||
check_client_connection false
|
||||
|
||||
before_fork do |server, worker|
|
||||
# the following is highly recomended for Rails + "preload_app true"
|
||||
# the following is highly recommended for Rails + "preload_app true"
|
||||
# as there's no need for the master process to hold a connection
|
||||
defined?(ActiveRecord::Base) and
|
||||
ActiveRecord::Base.connection.disconnect!
|
||||
|
|
|
@ -5,10 +5,7 @@ class OnlyAllowMergeIfAllDiscussionsAreResolved < ActiveRecord::Migration
|
|||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
add_column_with_default(:projects,
|
||||
:only_allow_merge_if_all_discussions_are_resolved,
|
||||
:boolean,
|
||||
default: false)
|
||||
add_column :projects, :only_allow_merge_if_all_discussions_are_resolved, :boolean
|
||||
end
|
||||
|
||||
def down
|
||||
|
|
|
@ -915,7 +915,7 @@ ActiveRecord::Schema.define(version: 20161109150329) do
|
|||
t.boolean "has_external_wiki"
|
||||
t.boolean "lfs_enabled"
|
||||
t.text "description_html"
|
||||
t.boolean "only_allow_merge_if_all_discussions_are_resolved", default: false, null: false
|
||||
t.boolean "only_allow_merge_if_all_discussions_are_resolved"
|
||||
end
|
||||
|
||||
add_index "projects", ["ci_id"], name: "index_projects_on_ci_id", using: :btree
|
||||
|
|
|
@ -76,7 +76,7 @@ configuration to move each data location to a subdirectory:
|
|||
user['home'] = '/gitlab-data/home'
|
||||
git_data_dir '/gitlab-data/git-data'
|
||||
gitlab_rails['shared_path'] = '/gitlab-data/shared'
|
||||
gitlab_rails['uploads_directory'] = "/gitlab-data/uploads"
|
||||
gitlab_rails['uploads_directory'] = '/gitlab-data/uploads'
|
||||
gitlab_ci['builds_directory'] = '/gitlab-data/builds'
|
||||
```
|
||||
|
||||
|
|
|
@ -48,15 +48,15 @@ Redis.
|
|||
redis['password'] = 'Redis Password'
|
||||
```
|
||||
|
||||
1. Run `sudo gitlab-ctl reconfigure` to install and configure PostgreSQL.
|
||||
1. Run `sudo touch /etc/gitlab/skip-auto-migrations` to prevent database migrations
|
||||
from running on upgrade. Only the primary GitLab application server should
|
||||
handle migrations.
|
||||
|
||||
1. Run `sudo gitlab-ctl reconfigure` to install and configure Redis.
|
||||
|
||||
> **Note**: This `reconfigure` step will result in some errors.
|
||||
That's OK - don't be alarmed.
|
||||
|
||||
1. Run `touch /etc/gitlab/skip-auto-migrations` to prevent database migrations
|
||||
from running on upgrade. Only the primary GitLab application server should
|
||||
handle migrations.
|
||||
|
||||
## Experimental Redis Sentinel support
|
||||
|
||||
> [Introduced][ce-1877] in GitLab 8.11.
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
contributing to documentation.
|
||||
- [SQL Migration Style Guide](migration_style_guide.md) for creating safe SQL migrations
|
||||
- [Testing standards and style guidelines](testing.md)
|
||||
- [UX guide](ux_guide/README.md) for building GitLab with existing CSS styles and elements
|
||||
- [UX guide](ux_guide/index.md) for building GitLab with existing CSS styles and elements
|
||||
- [Frontend guidelines](frontend.md)
|
||||
- [SQL guidelines](sql.md) for working with SQL queries
|
||||
- [Sidekiq guidelines](sidekiq_style_guide.md) for working with Sidekiq workers
|
||||
|
|
|
@ -14,8 +14,8 @@ There are two ways to create a new project in GitLab.
|
|||
|
||||
1. Fill out the information:
|
||||
|
||||
1. "Project name" is the name of your project (you can't use spaces, but you
|
||||
can use hyphens or underscores).
|
||||
1. "Project name" is the name of your project (you can't use special characters,
|
||||
but you can use spaces, hyphens, underscores or even emojis).
|
||||
1. The "Project description" is optional and will be shown in your project's
|
||||
dashboard so others can briefly understand what your project is about.
|
||||
1. Select a [visibility level](../public_access/public_access.md).
|
||||
|
|
|
@ -44,7 +44,7 @@ This [resource](http://kb.kerio.com/product/kerio-connect/server-configuration/s
|
|||
has all the information you need to add a certificate to the main trusted chain.
|
||||
|
||||
This [answer](http://superuser.com/questions/437330/how-do-you-add-a-certificate-authority-ca-to-ubuntu)
|
||||
at SuperUser also has relevant information.
|
||||
at Super User also has relevant information.
|
||||
|
||||
**Omnibus Trusted Chain**
|
||||
|
||||
|
|
|
@ -590,7 +590,7 @@ Quote break.
|
|||
|
||||
You can also use raw HTML in your Markdown, and it'll mostly work pretty well.
|
||||
|
||||
See the documentation for HTML::Pipeline's [SanitizationFilter](http://www.rubydoc.info/gems/html-pipeline/HTML/Pipeline/SanitizationFilter#WHITELIST-constant) class for the list of allowed HTML tags and attributes. In addition to the default `SanitizationFilter` whitelist, GitLab allows `span` elements.
|
||||
See the documentation for HTML::Pipeline's [SanitizationFilter](http://www.rubydoc.info/gems/html-pipeline/1.11.0/HTML/Pipeline/SanitizationFilter#WHITELIST-constant) class for the list of allowed HTML tags and attributes. In addition to the default `SanitizationFilter` whitelist, GitLab allows `span` elements.
|
||||
|
||||
```no-highlight
|
||||
<dl>
|
||||
|
|
|
@ -23,6 +23,11 @@ module API
|
|||
warden.try(:authenticate) if %w[GET HEAD].include?(env['REQUEST_METHOD'])
|
||||
end
|
||||
|
||||
def declared_params(options = {})
|
||||
options = { include_parent_namespaces: false }.merge(options)
|
||||
declared(params, options).to_h.symbolize_keys
|
||||
end
|
||||
|
||||
def find_user_by_private_token
|
||||
token = private_token
|
||||
return nil unless token.present?
|
||||
|
|
|
@ -62,9 +62,8 @@ module API
|
|||
end
|
||||
post ":id/milestones" do
|
||||
authorize! :admin_milestone, user_project
|
||||
milestone_params = declared(params, include_parent_namespaces: false)
|
||||
|
||||
milestone = ::Milestones::CreateService.new(user_project, current_user, milestone_params).execute
|
||||
milestone = ::Milestones::CreateService.new(user_project, current_user, declared_params).execute
|
||||
|
||||
if milestone.valid?
|
||||
present milestone, with: Entities::Milestone
|
||||
|
@ -86,9 +85,9 @@ module API
|
|||
end
|
||||
put ":id/milestones/:milestone_id" do
|
||||
authorize! :admin_milestone, user_project
|
||||
milestone_params = declared(params, include_parent_namespaces: false, include_missing: false)
|
||||
milestone = user_project.milestones.find(params.delete(:milestone_id))
|
||||
|
||||
milestone = user_project.milestones.find(milestone_params.delete(:milestone_id))
|
||||
milestone_params = declared_params(include_missing: false)
|
||||
milestone = ::Milestones::UpdateService.new(user_project, current_user, milestone_params).execute(milestone)
|
||||
|
||||
if milestone.valid?
|
||||
|
|
|
@ -57,9 +57,7 @@ module API
|
|||
runner = get_runner(params.delete(:id))
|
||||
authenticate_update_runner!(runner)
|
||||
|
||||
runner_params = declared(params, include_missing: false)
|
||||
|
||||
if runner.update(runner_params)
|
||||
if runner.update(declared_params(include_missing: false))
|
||||
present runner, with: Entities::RunnerDetails, current_user: current_user
|
||||
else
|
||||
render_validation_error!(runner)
|
||||
|
|
|
@ -9,23 +9,20 @@ module API
|
|||
'labels' => proc { |id| find_project_label(id) },
|
||||
}
|
||||
|
||||
params do
|
||||
requires :id, type: String, desc: 'The ID of a project'
|
||||
requires :subscribable_id, type: String, desc: 'The ID of a resource'
|
||||
end
|
||||
resource :projects do
|
||||
subscribable_types.each do |type, finder|
|
||||
type_singularized = type.singularize
|
||||
type_id_str = :"#{type_singularized}_id"
|
||||
entity_class = Entities.const_get(type_singularized.camelcase)
|
||||
|
||||
# Subscribe to a resource
|
||||
#
|
||||
# Parameters:
|
||||
# id (required) - The ID of a project
|
||||
# subscribable_id (required) - The ID of a resource
|
||||
# Example Request:
|
||||
# POST /projects/:id/labels/:subscribable_id/subscription
|
||||
# POST /projects/:id/issues/:subscribable_id/subscription
|
||||
# POST /projects/:id/merge_requests/:subscribable_id/subscription
|
||||
post ":id/#{type}/:#{type_id_str}/subscription" do
|
||||
resource = instance_exec(params[type_id_str], &finder)
|
||||
desc 'Subscribe to a resource' do
|
||||
success entity_class
|
||||
end
|
||||
post ":id/#{type}/:subscribable_id/subscription" do
|
||||
resource = instance_exec(params[:subscribable_id], &finder)
|
||||
|
||||
if resource.subscribed?(current_user)
|
||||
not_modified!
|
||||
|
@ -35,17 +32,11 @@ module API
|
|||
end
|
||||
end
|
||||
|
||||
# Unsubscribe from a resource
|
||||
#
|
||||
# Parameters:
|
||||
# id (required) - The ID of a project
|
||||
# subscribable_id (required) - The ID of a resource
|
||||
# Example Request:
|
||||
# DELETE /projects/:id/labels/:subscribable_id/subscription
|
||||
# DELETE /projects/:id/issues/:subscribable_id/subscription
|
||||
# DELETE /projects/:id/merge_requests/:subscribable_id/subscription
|
||||
delete ":id/#{type}/:#{type_id_str}/subscription" do
|
||||
resource = instance_exec(params[type_id_str], &finder)
|
||||
desc 'Unsubscribe from a resource' do
|
||||
success entity_class
|
||||
end
|
||||
delete ":id/#{type}/:subscribable_id/subscription" do
|
||||
resource = instance_exec(params[:subscribable_id], &finder)
|
||||
|
||||
if !resource.subscribed?(current_user)
|
||||
not_modified!
|
||||
|
|
|
@ -2,7 +2,7 @@ module Ci
|
|||
class GitlabCiYamlProcessor
|
||||
class ValidationError < StandardError; end
|
||||
|
||||
include Gitlab::Ci::Config::Node::LegacyValidationHelpers
|
||||
include Gitlab::Ci::Config::Entry::LegacyValidationHelpers
|
||||
|
||||
attr_reader :path, :cache, :stages, :jobs
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ module Gitlab
|
|||
def initialize(config)
|
||||
@config = Loader.new(config).load!
|
||||
|
||||
@global = Node::Global.new(@config)
|
||||
@global = Entry::Global.new(@config)
|
||||
@global.compose!
|
||||
end
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
module Gitlab
|
||||
module Ci
|
||||
class Config
|
||||
module Node
|
||||
module Entry
|
||||
##
|
||||
# Entry that represents a configuration of job artifacts.
|
||||
#
|
||||
class Artifacts < Entry
|
||||
class Artifacts < Node
|
||||
include Validatable
|
||||
include Attributable
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
module Gitlab
|
||||
module Ci
|
||||
class Config
|
||||
module Node
|
||||
module Entry
|
||||
module Attributable
|
||||
extend ActiveSupport::Concern
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
module Gitlab
|
||||
module Ci
|
||||
class Config
|
||||
module Node
|
||||
module Entry
|
||||
##
|
||||
# Entry that represents a boolean value.
|
||||
#
|
||||
class Boolean < Entry
|
||||
class Boolean < Node
|
||||
include Validatable
|
||||
|
||||
validations do
|
|
@ -1,11 +1,11 @@
|
|||
module Gitlab
|
||||
module Ci
|
||||
class Config
|
||||
module Node
|
||||
module Entry
|
||||
##
|
||||
# Entry that represents a cache configuration
|
||||
#
|
||||
class Cache < Entry
|
||||
class Cache < Node
|
||||
include Configurable
|
||||
|
||||
ALLOWED_KEYS = %i[key untracked paths]
|
||||
|
@ -14,13 +14,13 @@ module Gitlab
|
|||
validates :config, allowed_keys: ALLOWED_KEYS
|
||||
end
|
||||
|
||||
node :key, Node::Key,
|
||||
entry :key, Entry::Key,
|
||||
description: 'Cache key used to define a cache affinity.'
|
||||
|
||||
node :untracked, Node::Boolean,
|
||||
entry :untracked, Entry::Boolean,
|
||||
description: 'Cache all untracked files.'
|
||||
|
||||
node :paths, Node::Paths,
|
||||
entry :paths, Entry::Paths,
|
||||
description: 'Specify which paths should be cached across builds.'
|
||||
end
|
||||
end
|
|
@ -1,11 +1,11 @@
|
|||
module Gitlab
|
||||
module Ci
|
||||
class Config
|
||||
module Node
|
||||
module Entry
|
||||
##
|
||||
# Entry that represents a job script.
|
||||
#
|
||||
class Commands < Entry
|
||||
class Commands < Node
|
||||
include Validatable
|
||||
|
||||
validations do
|
|
@ -1,7 +1,7 @@
|
|||
module Gitlab
|
||||
module Ci
|
||||
class Config
|
||||
module Node
|
||||
module Entry
|
||||
##
|
||||
# This mixin is responsible for adding DSL, which purpose is to
|
||||
# simplifly process of adding child nodes.
|
||||
|
@ -48,8 +48,8 @@ module Gitlab
|
|||
|
||||
private # rubocop:disable Lint/UselessAccessModifier
|
||||
|
||||
def node(key, node, metadata)
|
||||
factory = Node::Factory.new(node)
|
||||
def entry(key, entry, metadata)
|
||||
factory = Entry::Factory.new(entry)
|
||||
.with(description: metadata[:description])
|
||||
|
||||
(@nodes ||= {}).merge!(key.to_sym => factory)
|
|
@ -1,11 +1,11 @@
|
|||
module Gitlab
|
||||
module Ci
|
||||
class Config
|
||||
module Node
|
||||
module Entry
|
||||
##
|
||||
# Entry that represents an environment.
|
||||
#
|
||||
class Environment < Entry
|
||||
class Environment < Node
|
||||
include Validatable
|
||||
|
||||
ALLOWED_KEYS = %i[name url action on_stop]
|
|
@ -1,15 +1,15 @@
|
|||
module Gitlab
|
||||
module Ci
|
||||
class Config
|
||||
module Node
|
||||
module Entry
|
||||
##
|
||||
# Factory class responsible for fabricating node entry objects.
|
||||
# Factory class responsible for fabricating entry objects.
|
||||
#
|
||||
class Factory
|
||||
class InvalidFactory < StandardError; end
|
||||
|
||||
def initialize(node)
|
||||
@node = node
|
||||
def initialize(entry)
|
||||
@entry = entry
|
||||
@metadata = {}
|
||||
@attributes = {}
|
||||
end
|
||||
|
@ -37,11 +37,11 @@ module Gitlab
|
|||
# See issue #18775.
|
||||
#
|
||||
if @value.nil?
|
||||
Node::Unspecified.new(
|
||||
Entry::Unspecified.new(
|
||||
fabricate_unspecified
|
||||
)
|
||||
else
|
||||
fabricate(@node, @value)
|
||||
fabricate(@entry, @value)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -49,21 +49,21 @@ module Gitlab
|
|||
|
||||
def fabricate_unspecified
|
||||
##
|
||||
# If node has a default value we fabricate concrete node
|
||||
# If entry has a default value we fabricate concrete node
|
||||
# with default value.
|
||||
#
|
||||
if @node.default.nil?
|
||||
fabricate(Node::Undefined)
|
||||
if @entry.default.nil?
|
||||
fabricate(Entry::Undefined)
|
||||
else
|
||||
fabricate(@node, @node.default)
|
||||
fabricate(@entry, @entry.default)
|
||||
end
|
||||
end
|
||||
|
||||
def fabricate(node, value = nil)
|
||||
node.new(value, @metadata).tap do |entry|
|
||||
entry.key = @attributes[:key]
|
||||
entry.parent = @attributes[:parent]
|
||||
entry.description = @attributes[:description]
|
||||
def fabricate(entry, value = nil)
|
||||
entry.new(value, @metadata).tap do |node|
|
||||
node.key = @attributes[:key]
|
||||
node.parent = @attributes[:parent]
|
||||
node.description = @attributes[:description]
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,36 +1,36 @@
|
|||
module Gitlab
|
||||
module Ci
|
||||
class Config
|
||||
module Node
|
||||
module Entry
|
||||
##
|
||||
# This class represents a global entry - root node for entire
|
||||
# This class represents a global entry - root Entry for entire
|
||||
# GitLab CI Configuration file.
|
||||
#
|
||||
class Global < Entry
|
||||
class Global < Node
|
||||
include Configurable
|
||||
|
||||
node :before_script, Node::Script,
|
||||
entry :before_script, Entry::Script,
|
||||
description: 'Script that will be executed before each job.'
|
||||
|
||||
node :image, Node::Image,
|
||||
entry :image, Entry::Image,
|
||||
description: 'Docker image that will be used to execute jobs.'
|
||||
|
||||
node :services, Node::Services,
|
||||
entry :services, Entry::Services,
|
||||
description: 'Docker images that will be linked to the container.'
|
||||
|
||||
node :after_script, Node::Script,
|
||||
entry :after_script, Entry::Script,
|
||||
description: 'Script that will be executed after each job.'
|
||||
|
||||
node :variables, Node::Variables,
|
||||
entry :variables, Entry::Variables,
|
||||
description: 'Environment variables that will be used.'
|
||||
|
||||
node :stages, Node::Stages,
|
||||
entry :stages, Entry::Stages,
|
||||
description: 'Configuration of stages for this pipeline.'
|
||||
|
||||
node :types, Node::Stages,
|
||||
entry :types, Entry::Stages,
|
||||
description: 'Deprecated: stages for this pipeline.'
|
||||
|
||||
node :cache, Node::Cache,
|
||||
entry :cache, Entry::Cache,
|
||||
description: 'Configure caching between build jobs.'
|
||||
|
||||
helpers :before_script, :image, :services, :after_script,
|
||||
|
@ -46,7 +46,7 @@ module Gitlab
|
|||
private
|
||||
|
||||
def compose_jobs!
|
||||
factory = Node::Factory.new(Node::Jobs)
|
||||
factory = Entry::Factory.new(Entry::Jobs)
|
||||
.value(@config.except(*self.class.nodes.keys))
|
||||
.with(key: :jobs, parent: self,
|
||||
description: 'Jobs definition for this pipeline')
|
|
@ -1,11 +1,11 @@
|
|||
module Gitlab
|
||||
module Ci
|
||||
class Config
|
||||
module Node
|
||||
module Entry
|
||||
##
|
||||
# Entry that represents a hidden CI/CD job.
|
||||
# Entry that represents a hidden CI/CD key.
|
||||
#
|
||||
class Hidden < Entry
|
||||
class Hidden < Node
|
||||
include Validatable
|
||||
|
||||
validations do
|
|
@ -1,11 +1,11 @@
|
|||
module Gitlab
|
||||
module Ci
|
||||
class Config
|
||||
module Node
|
||||
module Entry
|
||||
##
|
||||
# Entry that represents a Docker image.
|
||||
#
|
||||
class Image < Entry
|
||||
class Image < Node
|
||||
include Validatable
|
||||
|
||||
validations do
|
|
@ -1,11 +1,11 @@
|
|||
module Gitlab
|
||||
module Ci
|
||||
class Config
|
||||
module Node
|
||||
module Entry
|
||||
##
|
||||
# Entry that represents a concrete CI/CD job.
|
||||
#
|
||||
class Job < Entry
|
||||
class Job < Node
|
||||
include Configurable
|
||||
include Attributable
|
||||
|
||||
|
@ -34,43 +34,43 @@ module Gitlab
|
|||
end
|
||||
end
|
||||
|
||||
node :before_script, Node::Script,
|
||||
entry :before_script, Entry::Script,
|
||||
description: 'Global before script overridden in this job.'
|
||||
|
||||
node :script, Node::Commands,
|
||||
entry :script, Entry::Commands,
|
||||
description: 'Commands that will be executed in this job.'
|
||||
|
||||
node :stage, Node::Stage,
|
||||
entry :stage, Entry::Stage,
|
||||
description: 'Pipeline stage this job will be executed into.'
|
||||
|
||||
node :type, Node::Stage,
|
||||
entry :type, Entry::Stage,
|
||||
description: 'Deprecated: stage this job will be executed into.'
|
||||
|
||||
node :after_script, Node::Script,
|
||||
entry :after_script, Entry::Script,
|
||||
description: 'Commands that will be executed when finishing job.'
|
||||
|
||||
node :cache, Node::Cache,
|
||||
entry :cache, Entry::Cache,
|
||||
description: 'Cache definition for this job.'
|
||||
|
||||
node :image, Node::Image,
|
||||
entry :image, Entry::Image,
|
||||
description: 'Image that will be used to execute this job.'
|
||||
|
||||
node :services, Node::Services,
|
||||
entry :services, Entry::Services,
|
||||
description: 'Services that will be used to execute this job.'
|
||||
|
||||
node :only, Node::Trigger,
|
||||
entry :only, Entry::Trigger,
|
||||
description: 'Refs policy this job will be executed for.'
|
||||
|
||||
node :except, Node::Trigger,
|
||||
entry :except, Entry::Trigger,
|
||||
description: 'Refs policy this job will be executed for.'
|
||||
|
||||
node :variables, Node::Variables,
|
||||
entry :variables, Entry::Variables,
|
||||
description: 'Environment variables available for this job.'
|
||||
|
||||
node :artifacts, Node::Artifacts,
|
||||
entry :artifacts, Entry::Artifacts,
|
||||
description: 'Artifacts configuration for this job.'
|
||||
|
||||
node :environment, Node::Environment,
|
||||
entry :environment, Entry::Environment,
|
||||
description: 'Environment configuration for this job.'
|
||||
|
||||
helpers :before_script, :script, :stage, :type, :after_script,
|
|
@ -1,11 +1,11 @@
|
|||
module Gitlab
|
||||
module Ci
|
||||
class Config
|
||||
module Node
|
||||
module Entry
|
||||
##
|
||||
# Entry that represents a set of jobs.
|
||||
#
|
||||
class Jobs < Entry
|
||||
class Jobs < Node
|
||||
include Validatable
|
||||
|
||||
validations do
|
||||
|
@ -29,9 +29,9 @@ module Gitlab
|
|||
def compose!(deps = nil)
|
||||
super do
|
||||
@config.each do |name, config|
|
||||
node = hidden?(name) ? Node::Hidden : Node::Job
|
||||
node = hidden?(name) ? Entry::Hidden : Entry::Job
|
||||
|
||||
factory = Node::Factory.new(node)
|
||||
factory = Entry::Factory.new(node)
|
||||
.value(config || {})
|
||||
.metadata(name: name)
|
||||
.with(key: name, parent: self,
|
|
@ -1,11 +1,11 @@
|
|||
module Gitlab
|
||||
module Ci
|
||||
class Config
|
||||
module Node
|
||||
module Entry
|
||||
##
|
||||
# Entry that represents a key.
|
||||
#
|
||||
class Key < Entry
|
||||
class Key < Node
|
||||
include Validatable
|
||||
|
||||
validations do
|
|
@ -1,7 +1,7 @@
|
|||
module Gitlab
|
||||
module Ci
|
||||
class Config
|
||||
module Node
|
||||
module Entry
|
||||
module LegacyValidationHelpers
|
||||
private
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
module Gitlab
|
||||
module Ci
|
||||
class Config
|
||||
module Node
|
||||
module Entry
|
||||
##
|
||||
# Base abstract class for each configuration entry node.
|
||||
#
|
||||
class Entry
|
||||
class Node
|
||||
class InvalidError < StandardError; end
|
||||
|
||||
attr_reader :config, :metadata
|
||||
|
@ -21,7 +21,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def [](key)
|
||||
@entries[key] || Node::Undefined.new
|
||||
@entries[key] || Entry::Undefined.new
|
||||
end
|
||||
|
||||
def compose!(deps = nil)
|
|
@ -1,11 +1,11 @@
|
|||
module Gitlab
|
||||
module Ci
|
||||
class Config
|
||||
module Node
|
||||
module Entry
|
||||
##
|
||||
# Entry that represents an array of paths.
|
||||
#
|
||||
class Paths < Entry
|
||||
class Paths < Node
|
||||
include Validatable
|
||||
|
||||
validations do
|
|
@ -1,11 +1,11 @@
|
|||
module Gitlab
|
||||
module Ci
|
||||
class Config
|
||||
module Node
|
||||
module Entry
|
||||
##
|
||||
# Entry that represents a script.
|
||||
#
|
||||
class Script < Entry
|
||||
class Script < Node
|
||||
include Validatable
|
||||
|
||||
validations do
|
|
@ -1,11 +1,11 @@
|
|||
module Gitlab
|
||||
module Ci
|
||||
class Config
|
||||
module Node
|
||||
module Entry
|
||||
##
|
||||
# Entry that represents a configuration of Docker services.
|
||||
#
|
||||
class Services < Entry
|
||||
class Services < Node
|
||||
include Validatable
|
||||
|
||||
validations do
|
|
@ -1,11 +1,11 @@
|
|||
module Gitlab
|
||||
module Ci
|
||||
class Config
|
||||
module Node
|
||||
module Entry
|
||||
##
|
||||
# Entry that represents a stage for a job.
|
||||
#
|
||||
class Stage < Entry
|
||||
class Stage < Node
|
||||
include Validatable
|
||||
|
||||
validations do
|
|
@ -1,11 +1,11 @@
|
|||
module Gitlab
|
||||
module Ci
|
||||
class Config
|
||||
module Node
|
||||
module Entry
|
||||
##
|
||||
# Entry that represents a configuration for pipeline stages.
|
||||
#
|
||||
class Stages < Entry
|
||||
class Stages < Node
|
||||
include Validatable
|
||||
|
||||
validations do
|
|
@ -1,11 +1,11 @@
|
|||
module Gitlab
|
||||
module Ci
|
||||
class Config
|
||||
module Node
|
||||
module Entry
|
||||
##
|
||||
# Entry that represents a trigger policy for the job.
|
||||
#
|
||||
class Trigger < Entry
|
||||
class Trigger < Node
|
||||
include Validatable
|
||||
|
||||
validations do
|
|
@ -1,13 +1,11 @@
|
|||
module Gitlab
|
||||
module Ci
|
||||
class Config
|
||||
module Node
|
||||
module Entry
|
||||
##
|
||||
# This class represents an undefined node.
|
||||
# This class represents an undefined entry.
|
||||
#
|
||||
# Implements the Null Object pattern.
|
||||
#
|
||||
class Undefined < Entry
|
||||
class Undefined < Node
|
||||
def initialize(*)
|
||||
super(nil)
|
||||
end
|
|
@ -1,9 +1,9 @@
|
|||
module Gitlab
|
||||
module Ci
|
||||
class Config
|
||||
module Node
|
||||
module Entry
|
||||
##
|
||||
# This class represents an unspecified entry node.
|
||||
# This class represents an unspecified entry.
|
||||
#
|
||||
# It decorates original entry adding method that indicates it is
|
||||
# unspecified.
|
|
@ -1,13 +1,13 @@
|
|||
module Gitlab
|
||||
module Ci
|
||||
class Config
|
||||
module Node
|
||||
module Entry
|
||||
module Validatable
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
class_methods do
|
||||
def validator
|
||||
@validator ||= Class.new(Node::Validator).tap do |validator|
|
||||
@validator ||= Class.new(Entry::Validator).tap do |validator|
|
||||
if defined?(@validations)
|
||||
@validations.each { |rules| validator.class_eval(&rules) }
|
||||
end
|
|
@ -1,14 +1,14 @@
|
|||
module Gitlab
|
||||
module Ci
|
||||
class Config
|
||||
module Node
|
||||
module Entry
|
||||
class Validator < SimpleDelegator
|
||||
include ActiveModel::Validations
|
||||
include Node::Validators
|
||||
include Entry::Validators
|
||||
|
||||
def initialize(node)
|
||||
super(node)
|
||||
@node = node
|
||||
def initialize(entry)
|
||||
super(entry)
|
||||
@entry = entry
|
||||
end
|
||||
|
||||
def messages
|
||||
|
@ -30,7 +30,7 @@ module Gitlab
|
|||
|
||||
def key_name
|
||||
if key.blank?
|
||||
@node.class.name.demodulize.underscore.humanize
|
||||
@entry.class.name.demodulize.underscore.humanize
|
||||
else
|
||||
key
|
||||
end
|
|
@ -1,7 +1,7 @@
|
|||
module Gitlab
|
||||
module Ci
|
||||
class Config
|
||||
module Node
|
||||
module Entry
|
||||
module Validators
|
||||
class AllowedKeysValidator < ActiveModel::EachValidator
|
||||
def validate_each(record, attribute, value)
|
|
@ -1,11 +1,11 @@
|
|||
module Gitlab
|
||||
module Ci
|
||||
class Config
|
||||
module Node
|
||||
module Entry
|
||||
##
|
||||
# Entry that represents environment variables.
|
||||
#
|
||||
class Variables < Entry
|
||||
class Variables < Node
|
||||
include Validatable
|
||||
|
||||
validations do
|
|
@ -24,7 +24,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def sidekiq_throttling_enabled?
|
||||
current_application_settings.sidekiq_throttling_enabled
|
||||
current_application_settings.sidekiq_throttling_enabled?
|
||||
end
|
||||
|
||||
def fake_application_settings
|
||||
|
|
|
@ -89,9 +89,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def user_filter(filter = nil)
|
||||
if config.user_filter.present?
|
||||
user_filter = Net::LDAP::Filter.construct(config.user_filter)
|
||||
end
|
||||
user_filter = config.constructed_user_filter if config.user_filter.present?
|
||||
|
||||
if user_filter && filter
|
||||
Net::LDAP::Filter.join(filter, user_filter)
|
||||
|
|
|
@ -54,11 +54,9 @@ module Gitlab
|
|||
|
||||
# Apply LDAP user filter if present
|
||||
if config.user_filter.present?
|
||||
filter = Net::LDAP::Filter.join(
|
||||
filter,
|
||||
Net::LDAP::Filter.construct(config.user_filter)
|
||||
)
|
||||
filter = Net::LDAP::Filter.join(filter, config.constructed_user_filter)
|
||||
end
|
||||
|
||||
filter
|
||||
end
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def self.providers
|
||||
servers.map {|server| server['provider_name'] }
|
||||
servers.map { |server| server['provider_name'] }
|
||||
end
|
||||
|
||||
def self.valid_provider?(provider)
|
||||
|
@ -38,13 +38,31 @@ module Gitlab
|
|||
end
|
||||
|
||||
def adapter_options
|
||||
{
|
||||
host: options['host'],
|
||||
port: options['port'],
|
||||
encryption: encryption
|
||||
}.tap do |options|
|
||||
options.merge!(auth_options) if has_auth?
|
||||
opts = base_options.merge(
|
||||
encryption: encryption,
|
||||
)
|
||||
|
||||
opts.merge!(auth_options) if has_auth?
|
||||
|
||||
opts
|
||||
end
|
||||
|
||||
def omniauth_options
|
||||
opts = base_options.merge(
|
||||
base: base,
|
||||
method: options['method'],
|
||||
filter: omniauth_user_filter,
|
||||
name_proc: name_proc
|
||||
)
|
||||
|
||||
if has_auth?
|
||||
opts.merge!(
|
||||
bind_dn: options['bind_dn'],
|
||||
password: options['password']
|
||||
)
|
||||
end
|
||||
|
||||
opts
|
||||
end
|
||||
|
||||
def base
|
||||
|
@ -68,6 +86,10 @@ module Gitlab
|
|||
options['user_filter']
|
||||
end
|
||||
|
||||
def constructed_user_filter
|
||||
@constructed_user_filter ||= Net::LDAP::Filter.construct(user_filter)
|
||||
end
|
||||
|
||||
def group_base
|
||||
options['group_base']
|
||||
end
|
||||
|
@ -96,8 +118,27 @@ module Gitlab
|
|||
options['password'] || options['bind_dn']
|
||||
end
|
||||
|
||||
def allow_username_or_email_login
|
||||
options['allow_username_or_email_login']
|
||||
end
|
||||
|
||||
def name_proc
|
||||
if allow_username_or_email_login
|
||||
Proc.new { |name| name.gsub(/@.*\z/, '') }
|
||||
else
|
||||
Proc.new { |name| name }
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def base_options
|
||||
{
|
||||
host: options['host'],
|
||||
port: options['port']
|
||||
}
|
||||
end
|
||||
|
||||
def base_config
|
||||
Gitlab.config.ldap
|
||||
end
|
||||
|
@ -126,6 +167,16 @@ module Gitlab
|
|||
}
|
||||
}
|
||||
end
|
||||
|
||||
def omniauth_user_filter
|
||||
uid_filter = Net::LDAP::Filter.eq(uid, '%{username}')
|
||||
|
||||
if user_filter.present?
|
||||
Net::LDAP::Filter.join(uid_filter, constructed_user_filter).to_s
|
||||
else
|
||||
uid_filter.to_s
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -26,12 +26,12 @@ module Gitlab
|
|||
end
|
||||
|
||||
def project_name_regex
|
||||
@project_name_regex ||= /\A[\p{Alnum}_][\p{Alnum}\p{Pd}_\. ]*\z/.freeze
|
||||
@project_name_regex ||= /\A[\p{Alnum}\u{00A9}-\u{1f9c0}_][\p{Alnum}\p{Pd}\u{00A9}-\u{1f9c0}_\. ]*\z/.freeze
|
||||
end
|
||||
|
||||
def project_name_regex_message
|
||||
"can contain only letters, digits, '_', '.', dash and space. " \
|
||||
"It must start with letter, digit or '_'."
|
||||
"can contain only letters, digits, emojis, '_', '.', dash, space. " \
|
||||
"It must start with letter, digit, emoji or '_'."
|
||||
end
|
||||
|
||||
def project_path_regex
|
||||
|
|
|
@ -7,6 +7,40 @@ describe HelpController do
|
|||
sign_in(user)
|
||||
end
|
||||
|
||||
describe 'GET #index' do
|
||||
context 'when url prefixed without /help/' do
|
||||
it 'has correct url prefix' do
|
||||
stub_readme("[API](api/README.md)")
|
||||
get :index
|
||||
expect(assigns[:help_index]).to eq '[API](/help/api/README.md)'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when url prefixed with help/' do
|
||||
it 'will be an absolute path' do
|
||||
stub_readme("[API](help/api/README.md)")
|
||||
get :index
|
||||
expect(assigns[:help_index]).to eq '[API](/help/api/README.md)'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when url prefixed with help' do
|
||||
it 'will be an absolute path' do
|
||||
stub_readme("[API](helpful_hints/README.md)")
|
||||
get :index
|
||||
expect(assigns[:help_index]).to eq '[API](/help/helpful_hints/README.md)'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when url prefixed with /help/' do
|
||||
it 'will not be changed' do
|
||||
stub_readme("[API](/help/api/README.md)")
|
||||
get :index
|
||||
expect(assigns[:help_index]).to eq '[API](/help/api/README.md)'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET #show' do
|
||||
context 'for Markdown formats' do
|
||||
context 'when requested file exists' do
|
||||
|
@ -72,4 +106,8 @@ describe HelpController do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
def stub_readme(content)
|
||||
allow(File).to receive(:read).and_return(content)
|
||||
end
|
||||
end
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue