Commit 8fb73dcc authored by Nick Thomas's avatar Nick Thomas

Merge remote-tracking branch 'ce/master' into ce-to-ee-2017-08-03

parents aef62b69 2f05a6a4
This diff is collapsed.
This diff is collapsed.
...@@ -351,8 +351,8 @@ group :development, :test do ...@@ -351,8 +351,8 @@ group :development, :test do
gem 'spring-commands-rspec', '~> 1.0.4' gem 'spring-commands-rspec', '~> 1.0.4'
gem 'spring-commands-spinach', '~> 1.1.0' gem 'spring-commands-spinach', '~> 1.1.0'
gem 'rubocop', '~> 0.47.1', require: false gem 'rubocop', '~> 0.49.1', require: false
gem 'rubocop-rspec', '~> 1.15.0', require: false gem 'rubocop-rspec', '~> 1.15.1', require: false
gem 'scss_lint', '~> 0.54.0', require: false gem 'scss_lint', '~> 0.54.0', require: false
gem 'haml_lint', '~> 0.21.0', require: false gem 'haml_lint', '~> 0.21.0', require: false
gem 'simplecov', '~> 0.14.0', require: false gem 'simplecov', '~> 0.14.0', require: false
......
...@@ -348,7 +348,7 @@ GEM ...@@ -348,7 +348,7 @@ GEM
multi_json (~> 1.10) multi_json (~> 1.10)
retriable (~> 1.4) retriable (~> 1.4)
signet (~> 0.6) signet (~> 0.6)
google-protobuf (3.2.0.2) google-protobuf (3.3.0)
googleauth (0.5.1) googleauth (0.5.1)
faraday (~> 0.9) faraday (~> 0.9)
jwt (~> 1.4) jwt (~> 1.4)
...@@ -574,6 +574,7 @@ GEM ...@@ -574,6 +574,7 @@ GEM
rubypants (~> 0.2) rubypants (~> 0.2)
orm_adapter (0.5.0) orm_adapter (0.5.0)
os (0.9.6) os (0.9.6)
parallel (1.11.2)
paranoia (2.3.1) paranoia (2.3.1)
activerecord (>= 4.0, < 5.2) activerecord (>= 4.0, < 5.2)
parser (2.4.0.0) parser (2.4.0.0)
...@@ -759,13 +760,14 @@ GEM ...@@ -759,13 +760,14 @@ GEM
pg pg
rails rails
sqlite3 sqlite3
rubocop (0.47.1) rubocop (0.49.1)
parallel (~> 1.10)
parser (>= 2.3.3.1, < 3.0) parser (>= 2.3.3.1, < 3.0)
powerpack (~> 0.1) powerpack (~> 0.1)
rainbow (>= 1.99.1, < 3.0) rainbow (>= 1.99.1, < 3.0)
ruby-progressbar (~> 1.7) ruby-progressbar (~> 1.7)
unicode-display_width (~> 1.0, >= 1.0.1) unicode-display_width (~> 1.0, >= 1.0.1)
rubocop-rspec (1.15.0) rubocop-rspec (1.15.1)
rubocop (>= 0.42.0) rubocop (>= 0.42.0)
ruby-fogbugz (0.2.1) ruby-fogbugz (0.2.1)
crack (~> 0.4) crack (~> 0.4)
...@@ -897,7 +899,7 @@ GEM ...@@ -897,7 +899,7 @@ GEM
unf (0.1.4) unf (0.1.4)
unf_ext unf_ext
unf_ext (0.0.7.2) unf_ext (0.0.7.2)
unicode-display_width (1.1.3) unicode-display_width (1.3.0)
unicorn (5.1.0) unicorn (5.1.0)
kgio (~> 2.6) kgio (~> 2.6)
raindrops (~> 0.7) raindrops (~> 0.7)
...@@ -1115,8 +1117,8 @@ DEPENDENCIES ...@@ -1115,8 +1117,8 @@ DEPENDENCIES
rspec-retry (~> 0.4.5) rspec-retry (~> 0.4.5)
rspec-set (~> 0.1.3) rspec-set (~> 0.1.3)
rspec_profiling (~> 0.0.5) rspec_profiling (~> 0.0.5)
rubocop (~> 0.47.1) rubocop (~> 0.49.1)
rubocop-rspec (~> 1.15.0) rubocop-rspec (~> 1.15.1)
ruby-fogbugz (~> 0.2.1) ruby-fogbugz (~> 0.2.1)
ruby-prof (~> 0.16.2) ruby-prof (~> 0.16.2)
ruby_parser (~> 3.8) ruby_parser (~> 3.8)
......
...@@ -128,7 +128,7 @@ information, see ...@@ -128,7 +128,7 @@ information, see
### After the 7th ### After the 7th
Once the stable branch is frozen, only fixes for regressions (bugs introduced in that same release) Once the stable branch is frozen, only fixes for [regressions](#regressions)
and security issues will be cherry-picked into the stable branch. and security issues will be cherry-picked into the stable branch.
Any merge requests cherry-picked into the stable branch for a previous release will also be picked into the latest stable branch. Any merge requests cherry-picked into the stable branch for a previous release will also be picked into the latest stable branch.
These fixes will be shipped in the next RC for that release if it is before the 22nd. These fixes will be shipped in the next RC for that release if it is before the 22nd.
...@@ -158,6 +158,24 @@ release should have the correct milestone assigned _and_ have the label ...@@ -158,6 +158,24 @@ release should have the correct milestone assigned _and_ have the label
Merge requests without a milestone and this label will Merge requests without a milestone and this label will
not be merged into any stable branches. not be merged into any stable branches.
### Regressions
A regression for a particular monthly release is a bug that exists in that
release, but wasn't present in the release before. This includes bugs in
features that were only added in that monthly release. Every regression **must**
have the milestone of the release it was introduced in - if a regression doesn't
have a milestone, it might be 'just' a bug!
For instance, if 10.5.0 adds a feature, and that feature doesn't work correctly,
then this is a regression in 10.5. If 10.5.1 then fixes that, but 10.5.3 somehow
reintroduces the bug, then this bug is still a regression in 10.5.
Because GitLab.com runs release candidates of new releases, a regression can be
reported in a release before its 'official' release date on the 22nd of the
month. When we say 'the most recent monthly release', this can refer to either
the version currently running on GitLab.com, or the most recent version
available in the package repositories.
## Release retrospective and kickoff ## Release retrospective and kickoff
### Retrospective ### Retrospective
......
...@@ -64,7 +64,7 @@ window.Build = (function () { ...@@ -64,7 +64,7 @@ window.Build = (function () {
$(window) $(window)
.off('scroll') .off('scroll')
.on('scroll', () => { .on('scroll', () => {
const contentHeight = this.$buildTraceOutput.prop('scrollHeight'); const contentHeight = this.$buildTraceOutput.height();
if (contentHeight > this.windowSize) { if (contentHeight > this.windowSize) {
// means the user did not scroll, the content was updated. // means the user did not scroll, the content was updated.
this.windowSize = contentHeight; this.windowSize = contentHeight;
...@@ -105,16 +105,17 @@ window.Build = (function () { ...@@ -105,16 +105,17 @@ window.Build = (function () {
}; };
Build.prototype.canScroll = function () { Build.prototype.canScroll = function () {
return document.body.scrollHeight > window.innerHeight; return $(document).height() > $(window).height();
}; };
Build.prototype.toggleScroll = function () { Build.prototype.toggleScroll = function () {
const currentPosition = document.body.scrollTop; const currentPosition = $(document).scrollTop();
const windowHeight = window.innerHeight; const scrollHeight = $(document).height();
const windowHeight = $(window).height();
if (this.canScroll()) { if (this.canScroll()) {
if (currentPosition > 0 && if (currentPosition > 0 &&
(document.body.scrollHeight - currentPosition !== windowHeight)) { (scrollHeight - currentPosition !== windowHeight)) {
// User is in the middle of the log // User is in the middle of the log
this.toggleDisableButton(this.$scrollTopBtn, false); this.toggleDisableButton(this.$scrollTopBtn, false);
...@@ -124,7 +125,7 @@ window.Build = (function () { ...@@ -124,7 +125,7 @@ window.Build = (function () {
this.toggleDisableButton(this.$scrollTopBtn, true); this.toggleDisableButton(this.$scrollTopBtn, true);
this.toggleDisableButton(this.$scrollBottomBtn, false); this.toggleDisableButton(this.$scrollBottomBtn, false);
} else if (document.body.scrollHeight - currentPosition === windowHeight) { } else if (scrollHeight - currentPosition === windowHeight) {
// User is at the bottom of the build log. // User is at the bottom of the build log.
this.toggleDisableButton(this.$scrollTopBtn, false); this.toggleDisableButton(this.$scrollTopBtn, false);
...@@ -137,7 +138,7 @@ window.Build = (function () { ...@@ -137,7 +138,7 @@ window.Build = (function () {
}; };
Build.prototype.scrollDown = function () { Build.prototype.scrollDown = function () {
document.body.scrollTop = document.body.scrollHeight; $(document).scrollTop($(document).height());
}; };
Build.prototype.scrollToBottom = function () { Build.prototype.scrollToBottom = function () {
...@@ -147,7 +148,7 @@ window.Build = (function () { ...@@ -147,7 +148,7 @@ window.Build = (function () {
}; };
Build.prototype.scrollToTop = function () { Build.prototype.scrollToTop = function () {
document.body.scrollTop = 0; $(document).scrollTop(0);
this.hasBeenScrolled = true; this.hasBeenScrolled = true;
this.toggleScroll(); this.toggleScroll();
}; };
...@@ -178,7 +179,7 @@ window.Build = (function () { ...@@ -178,7 +179,7 @@ window.Build = (function () {
this.state = log.state; this.state = log.state;
} }
this.windowSize = this.$buildTraceOutput.prop('scrollHeight'); this.windowSize = this.$buildTraceOutput.height();
if (log.append) { if (log.append) {
this.$buildTraceOutput.append(log.html); this.$buildTraceOutput.append(log.html);
......
...@@ -9,7 +9,10 @@ ...@@ -9,7 +9,10 @@
/* global MilestoneSelect */ /* global MilestoneSelect */
/* global Commit */ /* global Commit */
/* global CommitsList */ /* global CommitsList */
<<<<<<< HEAD
/* global NewCommitForm */ /* global NewCommitForm */
=======
>>>>>>> ce/master
/* global NewBranchForm */ /* global NewBranchForm */
/* global NotificationsForm */ /* global NotificationsForm */
/* global NotificationsDropdown */ /* global NotificationsDropdown */
...@@ -21,12 +24,17 @@ ...@@ -21,12 +24,17 @@
/* global Search */ /* global Search */
/* global Admin */ /* global Admin */
/* global NamespaceSelects */ /* global NamespaceSelects */
/* global NewCommitForm */
/* global NewBranchForm */
/* global Project */ /* global Project */
/* global ProjectAvatar */ /* global ProjectAvatar */
/* global MergeRequest */ /* global MergeRequest */
/* global Compare */ /* global Compare */
/* global CompareAutocomplete */ /* global CompareAutocomplete */
<<<<<<< HEAD
/* global PathLocks */ /* global PathLocks */
=======
>>>>>>> ce/master
/* global ProjectFindFile */ /* global ProjectFindFile */
/* global ProjectNew */ /* global ProjectNew */
/* global ProjectShow */ /* global ProjectShow */
...@@ -74,6 +82,9 @@ import initSettingsPanels from './settings_panels'; ...@@ -74,6 +82,9 @@ import initSettingsPanels from './settings_panels';
import initExperimentalFlags from './experimental_flags'; import initExperimentalFlags from './experimental_flags';
import OAuthRememberMe from './oauth_remember_me'; import OAuthRememberMe from './oauth_remember_me';
import PerformanceBar from './performance_bar'; import PerformanceBar from './performance_bar';
import initNotes from './init_notes';
import initLegacyFilters from './init_legacy_filters';
import initIssuableSidebar from './init_issuable_sidebar';
import GpgBadges from './gpg_badges'; import GpgBadges from './gpg_badges';
import initNotes from './init_notes'; import initNotes from './init_notes';
import initLegacyFilters from './init_legacy_filters'; import initLegacyFilters from './init_legacy_filters';
...@@ -216,7 +227,6 @@ import AuditLogs from './audit_logs'; ...@@ -216,7 +227,6 @@ import AuditLogs from './audit_logs';
break; break;
case 'explore:groups:index': case 'explore:groups:index':
new GroupsList(); new GroupsList();
const landingElement = document.querySelector('.js-explore-groups-landing'); const landingElement = document.querySelector('.js-explore-groups-landing');
if (!landingElement) break; if (!landingElement) break;
const exploreGroupsLanding = new Landing( const exploreGroupsLanding = new Landing(
...@@ -310,6 +320,10 @@ import AuditLogs from './audit_logs'; ...@@ -310,6 +320,10 @@ import AuditLogs from './audit_logs';
new gl.Diff(); new gl.Diff();
shortcut_handler = new ShortcutsIssuable(true); shortcut_handler = new ShortcutsIssuable(true);
new ZenMode(); new ZenMode();
initIssuableSidebar();
initNotes();
const mrShowNode = document.querySelector('.merge-request'); const mrShowNode = document.querySelector('.merge-request');
window.mergeRequest = new MergeRequest({ window.mergeRequest = new MergeRequest({
action: mrShowNode.dataset.mrAction, action: mrShowNode.dataset.mrAction,
...@@ -336,6 +350,7 @@ import AuditLogs from './audit_logs'; ...@@ -336,6 +350,7 @@ import AuditLogs from './audit_logs';
container: '.js-commit-pipeline-graph', container: '.js-commit-pipeline-graph',
}).bindEvents(); }).bindEvents();
$('.commit-info.branches').load(document.querySelector('.js-commit-box').dataset.commitPath); $('.commit-info.branches').load(document.querySelector('.js-commit-box').dataset.commitPath);
<<<<<<< HEAD
break; break;
case 'projects:activity': case 'projects:activity':
new gl.Activities(); new gl.Activities();
...@@ -343,15 +358,26 @@ import AuditLogs from './audit_logs'; ...@@ -343,15 +358,26 @@ import AuditLogs from './audit_logs';
break; break;
case 'projects:commits:show': case 'projects:commits:show':
CommitsList.init(document.querySelector('.js-project-commits-show').dataset.commitsLimit); CommitsList.init(document.querySelector('.js-project-commits-show').dataset.commitsLimit);
=======
break;
case 'projects:activity':
>>>>>>> ce/master
new gl.Activities(); new gl.Activities();
shortcut_handler = new ShortcutsNavigation(); shortcut_handler = new ShortcutsNavigation();
GpgBadges.fetch();
break; break;
<<<<<<< HEAD
case 'projects:edit': case 'projects:edit':
new UsersSelect(); new UsersSelect();
break; break;
case 'projects:imports:show': case 'projects:imports:show':
new ProjectImport(); new ProjectImport();
=======
case 'projects:commits:show':
CommitsList.init(document.querySelector('.js-project-commits-show').dataset.commitsLimit);
new gl.Activities();
shortcut_handler = new ShortcutsNavigation();
GpgBadges.fetch();
>>>>>>> ce/master
break; break;
case 'projects:show': case 'projects:show':
shortcut_handler = new ShortcutsNavigation(); shortcut_handler = new ShortcutsNavigation();
...@@ -366,6 +392,12 @@ import AuditLogs from './audit_logs'; ...@@ -366,6 +392,12 @@ import AuditLogs from './audit_logs';
case 'projects:edit': case 'projects:edit':
setupProjectEdit(); setupProjectEdit();
break; break;
<<<<<<< HEAD
=======
case 'projects:imports:show':
new ProjectImport();
break;
>>>>>>> ce/master
case 'projects:pipelines:new': case 'projects:pipelines:new':
new NewBranchForm($('.js-new-pipeline-form')); new NewBranchForm($('.js-new-pipeline-form'));
break; break;
...@@ -423,6 +455,7 @@ import AuditLogs from './audit_logs'; ...@@ -423,6 +455,7 @@ import AuditLogs from './audit_logs';
new TreeView(); new TreeView();
new BlobViewer(); new BlobViewer();
new NewCommitForm($('.js-create-dir-form')); new NewCommitForm($('.js-create-dir-form'));
<<<<<<< HEAD
if (document.querySelector('.js-tree-content').dataset.pathLocksAvailable === 'true') { if (document.querySelector('.js-tree-content').dataset.pathLocksAvailable === 'true') {
PathLocks.init( PathLocks.init(
...@@ -431,6 +464,8 @@ import AuditLogs from './audit_logs'; ...@@ -431,6 +464,8 @@ import AuditLogs from './audit_logs';
); );
} }
=======
>>>>>>> ce/master
$('#tree-slider').waitForImages(function() { $('#tree-slider').waitForImages(function() {
gl.utils.ajaxGet(document.querySelector('.js-tree-content').dataset.logsPath); gl.utils.ajaxGet(document.querySelector('.js-tree-content').dataset.logsPath);
}); });
......
...@@ -50,6 +50,66 @@ class DropdownUtils { ...@@ -50,6 +50,66 @@ class DropdownUtils {
return updatedItem; return updatedItem;
} }
static mergeDuplicateLabels(dataMap, newLabel) {
const updatedMap = dataMap;
const key = newLabel.title;
const hasKeyProperty = Object.prototype.hasOwnProperty.call(updatedMap, key);
if (!hasKeyProperty) {
updatedMap[key] = newLabel;
} else {
const existing = updatedMap[key];
if (!existing.multipleColors) {
existing.multipleColors = [existing.color];
}
existing.multipleColors.push(newLabel.color);
}
return updatedMap;
}
static duplicateLabelColor(labelColors) {
const colors = labelColors;
const spacing = 100 / colors.length;
// Reduce the colors to 4
colors.length = Math.min(colors.length, 4);
const color = colors.map((c, i) => {
const percentFirst = Math.floor(spacing * i);
const percentSecond = Math.floor(spacing * (i + 1));
return `${c} ${percentFirst}%, ${c} ${percentSecond}%`;
}).join(', ');
return `linear-gradient(${color})`;
}
static duplicateLabelPreprocessing(data) {
const results = [];
const dataMap = {};
data.forEach(DropdownUtils.mergeDuplicateLabels.bind(null, dataMap));
Object.keys(dataMap)
.forEach((key) => {
const label = dataMap[key];
if (label.multipleColors) {
label.color = DropdownUtils.duplicateLabelColor(label.multipleColors);
label.text_color = '#000000';
}
results.push(label);
});
results.preprocessed = true;
return results;
}
static filterHint(config, item) { static filterHint(config, item) {
const { input, allowedKeys } = config; const { input, allowedKeys } = config;
const updatedItem = item; const updatedItem = item;
......
...@@ -745,10 +745,10 @@ GitLabDropdown = (function() { ...@@ -745,10 +745,10 @@ GitLabDropdown = (function() {
GitLabDropdown.prototype.focusTextInput = function(triggerFocus = false) { GitLabDropdown.prototype.focusTextInput = function(triggerFocus = false) {
if (this.options.filterable) { if (this.options.filterable) {
$(':focus').blur();
this.dropdown.one('transitionend', () => { this.dropdown.one('transitionend', () => {
if (this.dropdown.is('.open')) {
this.filterInput.focus(); this.filterInput.focus();
}
}); });
if (triggerFocus) { if (triggerFocus) {
......
<script>
export default {
props: {
entityId: {
type: Number,
required: true,
},
entityName: {
type: String,
required: true,
},
},
computed: {
/**
* This method is based on app/helpers/application_helper.rb#project_identicon
*/
identiconStyles() {
const allowedColors = [
'#FFEBEE',
'#F3E5F5',
'#E8EAF6',
'#E3F2FD',
'#E0F2F1',
'#FBE9E7',
'#EEEEEE',
];
const backgroundColor = allowedColors[this.entityId % 7];
return `background-color: ${backgroundColor}; color: #555;`;
},
identiconTitle() {
return this.entityName.charAt(0).toUpperCase();
},
},
};
</script>
<template>
<div
class="avatar s40 identicon"
:style="identiconStyles">
{{identiconTitle}}
</div>
</template>
<script> <script>
import eventHub from '../event_hub'; import eventHub from '../event_hub';
import groupIdenticon from './group_identicon.vue';
export default { export default {
components: {
groupIdenticon,
},
props: { props: {
group: { group: {
type: Object, type: Object,
...@@ -92,6 +96,9 @@ export default { ...@@ -92,6 +96,9 @@ export default {
hasGroups() { hasGroups() {
return Object.keys(this.group.subGroups).length > 0; return Object.keys(this.group.subGroups).length > 0;
}, },
hasAvatar() {
return this.group.avatarUrl && this.group.avatarUrl.indexOf('/assets/no_group_avatar') === -1;
},
}, },
}; };
</script> </script>
...@@ -194,9 +201,15 @@ export default { ...@@ -194,9 +201,15 @@ export default {
<a <a
:href="group.groupPath"> :href="group.groupPath">
<img <img
v-if="hasAvatar"
class="avatar s40" class="avatar s40"
:src="group.avatarUrl" :src="group.avatarUrl"
/> />
<group-identicon
v-else
:entity-id=group.id
:entity-name="group.name"
/>
</a> </a>
</div> </div>
<div <div
......
/* eslint-disable no-new */ /* eslint-disable no-new */
/* global MilestoneSelect */ /* global MilestoneSelect */
/* global LabelsSelect */ /* global LabelsSelect */
<<<<<<< HEAD
/* global WeightSelect */ /* global WeightSelect */
=======
>>>>>>> ce/master
/* global IssuableContext */ /* global IssuableContext */
/* global Sidebar */ /* global Sidebar */
...@@ -12,7 +15,10 @@ export default () => { ...@@ -12,7 +15,10 @@ export default () => {
full_path: sidebarOptions.fullPath, full_path: sidebarOptions.fullPath,
}); });
new LabelsSelect(); new LabelsSelect();
<<<<<<< HEAD
new WeightSelect(); new WeightSelect();
=======
>>>>>>> ce/master
new IssuableContext(sidebarOptions.currentUser); new IssuableContext(sidebarOptions.currentUser);
gl.Subscription.bindAll('.subscription'); gl.Subscription.bindAll('.subscription');
new gl.DueDateSelectors(); new gl.DueDateSelectors();
......
...@@ -3,7 +3,10 @@ ...@@ -3,7 +3,10 @@
/* global MilestoneSelect */ /* global MilestoneSelect */
/* global IssueStatusSelect */ /* global IssueStatusSelect */
/* global SubscriptionSelect */ /* global SubscriptionSelect */
<<<<<<< HEAD
/* global WeightSelect */ /* global WeightSelect */
=======
>>>>>>> ce/master
import UsersSelect from './users_select'; import UsersSelect from './users_select';
...@@ -13,5 +16,8 @@ export default () => { ...@@ -13,5 +16,8 @@ export default () => {
new MilestoneSelect(); new MilestoneSelect();
new IssueStatusSelect(); new IssueStatusSelect();
new SubscriptionSelect(); new SubscriptionSelect();
<<<<<<< HEAD
new WeightSelect(); new WeightSelect();
=======
>>>>>>> ce/master
}; };
...@@ -529,6 +529,7 @@ export default class Notes { ...@@ -529,6 +529,7 @@ export default class Notes {
form.find('#note_line_code').remove(); form.find('#note_line_code').remove();
form.find('#note_position').remove(); form.find('#note_position').remove();
form.find('#note_type').val(''); form.find('#note_type').val('');
form.find('#note_project_id').remove();
form.find('#in_reply_to_discussion_id').remove(); form.find('#in_reply_to_discussion_id').remove();
form.find('.js-comment-resolve-button').closest('comment-and-resolve-btn').remove(); form.find('.js-comment-resolve-button').closest('comment-and-resolve-btn').remove();
this.parentTimeline = form.parents('.timeline'); this.parentTimeline = form.parents('.timeline');
...@@ -556,6 +557,7 @@ export default class Notes { ...@@ -556,6 +557,7 @@ export default class Notes {
form.find('#note_noteable_id').val(), form.find('#note_noteable_id').val(),
form.find('#note_commit_id').val(), form.find('#note_commit_id').val(),
form.find('#note_type').val(), form.find('#note_type').val(),
form.find('#note_project_id').val(),
form.find('#in_reply_to_discussion_id').val(), form.find('#in_reply_to_discussion_id').val(),
// LegacyDiffNote // LegacyDiffNote
...@@ -848,6 +850,8 @@ export default class Notes { ...@@ -848,6 +850,8 @@ export default class Notes {
form.find('#in_reply_to_discussion_id').val(discussionID); form.find('#in_reply_to_discussion_id').val(discussionID);
} }
form.find('#note_project_id').val(dataHolder.data('discussionProjectId'));
form.attr('data-line-code', dataHolder.data('lineCode')); form.attr('data-line-code', dataHolder.data('lineCode'));
form.find('#line_type').val(dataHolder.data('lineType')); form.find('#line_type').val(dataHolder.data('lineType'));
......
/* eslint-disable no-useless-escape, max-len, quotes, no-var, no-underscore-dangle, func-names, space-before-function-paren, no-unused-vars, no-return-assign, object-shorthand, one-var, one-var-declaration-per-line, comma-dangle, consistent-return, class-methods-use-this, new-parens */ /* eslint-disable no-useless-escape, max-len, quotes, no-var, no-underscore-dangle, func-names, space-before-function-paren, no-unused-vars, no-return-assign, object-shorthand, one-var, one-var-declaration-per-line, comma-dangle, consistent-return, class-methods-use-this, new-parens */
import 'vendor/cropper'; import 'cropper';
((global) => { ((global) => {
// Matches everything but the file name // Matches everything but the file name
......
...@@ -26,11 +26,14 @@ import Cookies from 'js-cookie'; ...@@ -26,11 +26,14 @@ import Cookies from 'js-cookie';
$projectCloneField.val(url); $projectCloneField.val(url);
$cloneBtnText.text($this.text()); $cloneBtnText.text($this.text());
<<<<<<< HEAD
$('#modal-geo-info').data({ $('#modal-geo-info').data({
cloneUrlSecondary: $this.attr('href'), cloneUrlSecondary: $this.attr('href'),
cloneUrlPrimary: $this.data('primaryUrl') || '' cloneUrlPrimary: $this.data('primaryUrl') || ''
}); });
=======
>>>>>>> ce/master
return $('.clone').text(url); return $('.clone').text(url);
}); });
// Ref switcher // Ref switcher
......
<<<<<<< HEAD
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
const importBtnTooltip = 'Please enter a valid project name.'; const importBtnTooltip = 'Please enter a valid project name.';
const $importBtnWrapper = $('.import_gitlab_project'); const $importBtnWrapper = $('.import_gitlab_project');
=======
let hasUserDefinedProjectPath = false;
const deriveProjectPathFromUrl = ($projectImportUrl, $projectPath) => {
if ($projectImportUrl.attr('disabled') || hasUserDefinedProjectPath) {
return;
}
let importUrl = $projectImportUrl.val().trim();
if (importUrl.length === 0) {
return;
}
/*
\/?: remove trailing slash
(\.git\/?)?: remove trailing .git (with optional trailing slash)
(\?.*)?: remove query string
(#.*)?: remove fragment identifier
*/
importUrl = importUrl.replace(/\/?(\.git\/?)?(\?.*)?(#.*)?$/, '');
// extract everything after the last slash
const pathMatch = /\/([^/]+)$/.exec(importUrl);
if (pathMatch) {
$projectPath.val(pathMatch[1]);
}
};
const bindEvents = () => {
const $newProjectForm = $('#new_project');
const importBtnTooltip = 'Please enter a valid project name.';
const $importBtnWrapper = $('.import_gitlab_project');
const $projectImportUrl = $('#project_import_url');
const $projectPath = $('#project_path');
if ($newProjectForm.length !== 1) {
return;
}
>>>>>>> ce/master
$('.how_to_import_link').on('click', (e) => { $('.how_to_import_link').on('click', (e) => {
e.preventDefault(); e.preventDefault();
...@@ -13,6 +53,7 @@ document.addEventListener('DOMContentLoaded', () => { ...@@ -13,6 +53,7 @@ document.addEventListener('DOMContentLoaded', () => {
$('.btn_import_gitlab_project').on('click', () => { $('.btn_import_gitlab_project').on('click', () => {
const importHref = $('a.btn_import_gitlab_project').attr('href'); const importHref = $('a.btn_import_gitlab_project').attr('href');
<<<<<<< HEAD
$('.btn_import_gitlab_project').attr('href', `${importHref}?namespace_id=${$('#project_namespace_id').val()}&path=${$('#project_path').val()}`); $('.btn_import_gitlab_project').attr('href', `${importHref}?namespace_id=${$('#project_namespace_id').val()}&path=${$('#project_path').val()}`);
}); });
...@@ -26,6 +67,21 @@ document.addEventListener('DOMContentLoaded', () => { ...@@ -26,6 +67,21 @@ document.addEventListener('DOMContentLoaded', () => {
$('#project_path').on('keyup', () => { $('#project_path').on('keyup', () => {
if ($('#project_path').val().trim().length) { if ($('#project_path').val().trim().length) {
=======
$('.btn_import_gitlab_project').attr('href', `${importHref}?namespace_id=${$('#project_namespace_id').val()}&path=${$projectPath.val()}`);
});
$('.btn_import_gitlab_project').attr('disabled', !$projectPath.val().trim().length);
$importBtnWrapper.attr('title', importBtnTooltip);
$newProjectForm.on('submit', () => {
$projectPath.val($projectPath.val().trim());
});
$projectPath.on('keyup', () => {
hasUserDefinedProjectPath = $projectPath.val().trim().length > 0;
if (hasUserDefinedProjectPath) {
>>>>>>> ce/master
$('.btn_import_gitlab_project').attr('disabled', false); $('.btn_import_gitlab_project').attr('disabled', false);
$importBtnWrapper.attr('title', ''); $importBtnWrapper.attr('title', '');
$importBtnWrapper.removeClass('has-tooltip'); $importBtnWrapper.removeClass('has-tooltip');
...@@ -35,9 +91,26 @@ document.addEventListener('DOMContentLoaded', () => { ...@@ -35,9 +91,26 @@ document.addEventListener('DOMContentLoaded', () => {
} }
}); });
<<<<<<< HEAD
$('#project_import_url').disable(); $('#project_import_url').disable();
$('.import_git').on('click', () => { $('.import_git').on('click', () => {
const $projectImportUrl = $('#project_import_url'); const $projectImportUrl = $('#project_import_url');
$projectImportUrl.attr('disabled', !$projectImportUrl.attr('disabled')); $projectImportUrl.attr('disabled', !$projectImportUrl.attr('disabled'));
}); });
}); });
=======
$projectImportUrl.disable();
$projectImportUrl.keyup(() => deriveProjectPathFromUrl($projectImportUrl, $projectPath));
$('.import_git').on('click', () => {
$projectImportUrl.attr('disabled', !$projectImportUrl.attr('disabled'));
});
};
document.addEventListener('DOMContentLoaded', bindEvents);
export default {
bindEvents,
deriveProjectPathFromUrl,
};
>>>>>>> ce/master
...@@ -92,6 +92,10 @@ ...@@ -92,6 +92,10 @@
overflow: hidden; overflow: hidden;
display: flex; display: flex;
a {
display: flex;
}
.avatar { .avatar {
border-radius: 0; border-radius: 0;
border: none; border: none;
......
...@@ -414,13 +414,16 @@ ...@@ -414,13 +414,16 @@
background-color: $dropdown-hover-color; background-color: $dropdown-hover-color;
color: $white-light; color: $white-light;
text-decoration: none; text-decoration: none;
outline: 0;
.avatar { .avatar {
border-color: $white-light; border-color: $white-light;
} }
} }
.filter-dropdown-item { .droplab-dropdown .dropdown-menu .filter-dropdown-item {
padding: 0;
.btn { .btn {
border: none; border: none;
width: 100%; width: 100%;
...@@ -455,14 +458,11 @@ ...@@ -455,14 +458,11 @@
} }
.dropdown-user { .dropdown-user {
display: -webkit-flex;
display: flex; display: flex;
} }
.dropdown-user-details { .dropdown-user-details {
display: -webkit-flex;
display: flex; display: flex;
-webkit-flex-direction: column;
flex-direction: column; flex-direction: column;
> span { > span {
......
...@@ -313,6 +313,29 @@ header { ...@@ -313,6 +313,29 @@ header {
.impersonation i { .impersonation i {
color: $red-500; color: $red-500;
} }
// TODO: fallback to global style
.dropdown-menu,
.dropdown-menu-nav {
li {
padding: 0 1px;
a {
border-radius: 0;
padding: 8px 16px;
&:hover,
&:active,
&:focus {
background-color: $gray-darker;
}
}
}
}
}
.with-performance-bar header.navbar-gitlab {
top: $performance-bar-height;
} }
.with-performance-bar header.navbar-gitlab { .with-performance-bar header.navbar-gitlab {
......
...@@ -375,6 +375,10 @@ ul.indent-list { ...@@ -375,6 +375,10 @@ ul.indent-list {
background-color: $row-hover; background-color: $row-hover;
cursor: pointer; cursor: pointer;
} }
.avatar-container > a {
width: 100%;
}
} }
} }
......
...@@ -185,3 +185,28 @@ ...@@ -185,3 +185,28 @@
text-overflow: ellipsis; text-overflow: ellipsis;
} }
} }
// TODO: fallback to global style
.atwho-view {
.atwho-view-ul {
padding: 8px 1px;
li {
padding: 8px 16px;
border: 0;
&.cur {
background-color: $gray-darker;
color: $gl-text-color;
small {
color: inherit;
}
}
strong {
color: $gl-text-color;
}
}
}
}
...@@ -19,9 +19,9 @@ ...@@ -19,9 +19,9 @@
} }
img.js-lazy-loaded { img.js-lazy-loaded {
min-width: none; min-width: inherit;
min-height: none; min-height: inherit;
background-color: none; background-color: inherit;
} }
p a:not(.no-attachment-icon) img { p a:not(.no-attachment-icon) img {
......
...@@ -206,10 +206,13 @@ $general-hover-transition-duration: 100ms; ...@@ -206,10 +206,13 @@ $general-hover-transition-duration: 100ms;
$general-hover-transition-curve: linear; $general-hover-transition-curve: linear;
$highlight-changes-color: rgb(235, 255, 232); $highlight-changes-color: rgb(235, 255, 232);
$performance-bar-height: 35px; $performance-bar-height: 35px;
<<<<<<< HEAD
$issue-box-upcoming-bg: #8f8f8f; $issue-box-upcoming-bg: #8f8f8f;
$pages-group-name-color: #4c4e54; $pages-group-name-color: #4c4e54;
$ldap-members-override-bg: $orange-50; $ldap-members-override-bg: $orange-50;
=======
>>>>>>> ce/master
/* /*
......
...@@ -309,6 +309,25 @@ header.navbar-gitlab-new { ...@@ -309,6 +309,25 @@ header.navbar-gitlab-new {
outline: 0; outline: 0;
} }
} }
// TODO: fallback to global style
.dropdown-menu {
li {
padding: 0 1px;
a {
border-radius: 0;
padding: 8px 16px;
&.is-focused,
&:hover,
&:active,
&:focus {
background-color: $gray-darker;
}
}
}
}
} }
.breadcrumbs-container { .breadcrumbs-container {
...@@ -325,6 +344,7 @@ header.navbar-gitlab-new { ...@@ -325,6 +344,7 @@ header.navbar-gitlab-new {
.breadcrumbs-links { .breadcrumbs-links {
flex: 1; flex: 1;
min-width: 0;
align-self: center; align-self: center;
color: $gl-text-color-quaternary; color: $gl-text-color-quaternary;
...@@ -343,7 +363,7 @@ header.navbar-gitlab-new { ...@@ -343,7 +363,7 @@ header.navbar-gitlab-new {
} }
.title { .title {
white-space: nowrap; display: inline-block;
> a { > a {
&:last-of-type:not(:first-child) { &:last-of-type:not(:first-child) {
......
...@@ -86,6 +86,7 @@ ...@@ -86,6 +86,7 @@
position: absolute; position: absolute;
right: 0; right: 0;
left: 0; left: 0;
top: 0;
} }
.truncated-info { .truncated-info {
...@@ -310,9 +311,7 @@ ...@@ -310,9 +311,7 @@
} }
.dropdown-menu { .dropdown-menu {
right: $gl-padding; margin-top: -$gl-padding;
left: $gl-padding;
width: auto;
} }
svg { svg {
......
...@@ -110,6 +110,10 @@ ...@@ -110,6 +110,10 @@
.js-ca-dropdown { .js-ca-dropdown {
top: $gl-padding-top; top: $gl-padding-top;
.dropdown-menu-align-right {
margin-top: 2px;
}
} }
.content-list { .content-list {
...@@ -442,6 +446,24 @@ ...@@ -442,6 +446,24 @@
margin-bottom: 20px; margin-bottom: 20px;
} }
} }
// TODO: fallback to global style
.dropdown-menu {
li {
padding: 0 1px;
a {
border-radius: 0;
padding: 8px 16px;
&:hover,
&:active,
&:focus {
background-color: $gray-darker;
}
}
}
}
} }
.cycle-analytics-overview { .cycle-analytics-overview {
......
...@@ -202,6 +202,28 @@ ...@@ -202,6 +202,28 @@
} }
} }
} }
// TODO: fallback to global style
.dropdown-menu:not(.dropdown-menu-selectable) {
li {
padding: 0 1px;
&.dropdown-header {
padding: 8px 16px;
}
a {
border-radius: 0;
padding: 8px 16px;
&:hover,
&:active,
&:focus {
background-color: $gray-darker;
}
}
}
}
} }
.blob-commit-info { .blob-commit-info {
......
...@@ -4,6 +4,7 @@ module NotesActions ...@@ -4,6 +4,7 @@ module NotesActions
included do included do
before_action :authorize_admin_note!, only: [:update, :destroy] before_action :authorize_admin_note!, only: [:update, :destroy]
before_action :note_project, only: [:create]
end end
def index def index
...@@ -28,7 +29,8 @@ module NotesActions ...@@ -28,7 +29,8 @@ module NotesActions
merge_request_diff_head_sha: params[:merge_request_diff_head_sha], merge_request_diff_head_sha: params[:merge_request_diff_head_sha],
in_reply_to_discussion_id: params[:in_reply_to_discussion_id] in_reply_to_discussion_id: params[:in_reply_to_discussion_id]
) )
@note = Notes::CreateService.new(project, current_user, create_params).execute
@note = Notes::CreateService.new(note_project, current_user, create_params).execute
if @note.is_a?(Note) if @note.is_a?(Note)
Banzai::NoteRenderer.render([@note], @project, current_user) Banzai::NoteRenderer.render([@note], @project, current_user)
...@@ -177,4 +179,22 @@ module NotesActions ...@@ -177,4 +179,22 @@ module NotesActions
def notes_finder def notes_finder
@notes_finder ||= NotesFinder.new(project, current_user, finder_params) @notes_finder ||= NotesFinder.new(project, current_user, finder_params)
end end
def note_project
return @note_project if defined?(@note_project)
return nil unless project
note_project_id = params[:note_project_id]
@note_project =
if note_project_id.present?
Project.find(note_project_id)
else
project
end
return access_denied! unless can?(current_user, :create_note, @note_project)
@note_project
end
end end
...@@ -66,7 +66,8 @@ module Projects ...@@ -66,7 +66,8 @@ module Projects
end end
def filter_params def filter_params
params.merge(board_id: params[:board_id], id: params[:list_id]).compact params.merge(board_id: params[:board_id], id: params[:list_id])
.reject { |_, value| value.nil? }
end end
def move_params def move_params
......
...@@ -8,7 +8,7 @@ class Projects::BranchesController < Projects::ApplicationController ...@@ -8,7 +8,7 @@ class Projects::BranchesController < Projects::ApplicationController
before_action :authorize_push_code!, only: [:new, :create, :destroy, :destroy_all_merged] before_action :authorize_push_code!, only: [:new, :create, :destroy, :destroy_all_merged]
def index def index
@sort = params[:sort].presence || sort_value_name @sort = params[:sort].presence || sort_value_recently_updated
@branches = BranchesFinder.new(@repository, params).execute @branches = BranchesFinder.new(@repository, params).execute
@branches = Kaminari.paginate_array(@branches).page(params[:page]) @branches = Kaminari.paginate_array(@branches).page(params[:page])
......
...@@ -15,7 +15,7 @@ module DiffHelper ...@@ -15,7 +15,7 @@ module DiffHelper
def diff_view def diff_view
@diff_view ||= begin @diff_view ||= begin
diff_views = %w(inline parallel) diff_views = %w(inline parallel)
diff_view = cookies[:diff_view] diff_view = params[:view] || cookies[:diff_view]
diff_view = diff_views.first unless diff_views.include?(diff_view) diff_view = diff_views.first unless diff_views.include?(diff_view)
diff_view.to_sym diff_view.to_sym
end end
......
...@@ -48,8 +48,12 @@ module GitlabRoutingHelper ...@@ -48,8 +48,12 @@ module GitlabRoutingHelper
end end
def milestone_path(entity, *args) def milestone_path(entity, *args)
if entity.is_group_milestone?
group_milestone_path(entity.group, entity, *args)
elsif entity.is_project_milestone?
project_milestone_path(entity.project, entity, *args) project_milestone_path(entity.project, entity, *args)
end end
end
def issue_url(entity, *args) def issue_url(entity, *args)
project_issue_url(entity.project, entity, *args) project_issue_url(entity.project, entity, *args)
...@@ -63,6 +67,14 @@ module GitlabRoutingHelper ...@@ -63,6 +67,14 @@ module GitlabRoutingHelper
project_pipeline_url(pipeline.project, pipeline.id, *args) project_pipeline_url(pipeline.project, pipeline.id, *args)
end end
def milestone_url(entity, *args)
if entity.is_group_milestone?
group_milestone_url(entity.group, entity, *args)
elsif entity.is_project_milestone?
project_milestone_url(entity.project, entity, *args)
end
end
def pipeline_job_url(pipeline, build, *args) def pipeline_job_url(pipeline, build, *args)
project_job_url(pipeline.project, build.id, *args) project_job_url(pipeline.project, build.id, *args)
end end
......
...@@ -62,7 +62,11 @@ module NotesHelper ...@@ -62,7 +62,11 @@ module NotesHelper
def link_to_reply_discussion(discussion, line_type = nil) def link_to_reply_discussion(discussion, line_type = nil)
return unless current_user return unless current_user
data = { discussion_id: discussion.reply_id, line_type: line_type } data = {
discussion_id: discussion.reply_id,
discussion_project_id: discussion.project&.id,
line_type: line_type
}
button_tag 'Reply...', class: 'btn btn-text-field js-discussion-reply-button', button_tag 'Reply...', class: 'btn btn-text-field js-discussion-reply-button',
data: data, title: 'Add a reply' data: data, title: 'Add a reply'
......
...@@ -34,6 +34,8 @@ module WebpackHelper ...@@ -34,6 +34,8 @@ module WebpackHelper
end end
def webpack_public_path def webpack_public_path
"#{webpack_public_host}/#{Rails.application.config.webpack.public_path}/" relative_path = Rails.application.config.relative_url_root
webpack_path = Rails.application.config.webpack.public_path
File.join(webpack_public_host.to_s, relative_path.to_s, webpack_path.to_s, '')
end end
end end
module ProtectedBranchAccess module ProtectedBranchAccess
extend ActiveSupport::Concern extend ActiveSupport::Concern
ALLOWED_ACCESS_LEVELS ||= [
Gitlab::Access::MASTER,
Gitlab::Access::DEVELOPER,
Gitlab::Access::NO_ACCESS
].freeze
included do included do
include ProtectedRefAccess include ProtectedRefAccess
include EE::ProtectedRefAccess include EE::ProtectedRefAccess
...@@ -10,11 +16,7 @@ module ProtectedBranchAccess ...@@ -10,11 +16,7 @@ module ProtectedBranchAccess
delegate :project, to: :protected_branch delegate :project, to: :protected_branch
validates :access_level, presence: true, inclusion: { validates :access_level, presence: true, inclusion: {
in: [ in: ALLOWED_ACCESS_LEVELS
Gitlab::Access::MASTER,
Gitlab::Access::DEVELOPER,
Gitlab::Access::NO_ACCESS
]
} }
def self.human_access_levels def self.human_access_levels
......
class NotificationSetting < ActiveRecord::Base class NotificationSetting < ActiveRecord::Base
include IgnorableColumn
ignore_column :events
enum level: { global: 3, watch: 2, mention: 4, participating: 1, disabled: 0, custom: 5 } enum level: { global: 3, watch: 2, mention: 4, participating: 1, disabled: 0, custom: 5 }
default_value_for :level, NotificationSetting.levels[:global] default_value_for :level, NotificationSetting.levels[:global]
...@@ -41,9 +45,6 @@ class NotificationSetting < ActiveRecord::Base ...@@ -41,9 +45,6 @@ class NotificationSetting < ActiveRecord::Base
:success_pipeline :success_pipeline
].freeze ].freeze
store :events, coder: JSON
before_save :convert_events
def self.find_or_create_for(source) def self.find_or_create_for(source)
setting = find_or_initialize_by(source: source) setting = find_or_initialize_by(source: source)
...@@ -54,42 +55,17 @@ class NotificationSetting < ActiveRecord::Base ...@@ -54,42 +55,17 @@ class NotificationSetting < ActiveRecord::Base
setting setting
end end
# 1. Check if this event has a value stored in its database column.
# 2. If it does, return that value.
# 3. If it doesn't (the value is nil), return the value from the serialized
# JSON hash in `events`.
(EMAIL_EVENTS - [:failed_pipeline]).each do |event|
define_method(event) do
bool = super()
bool.nil? ? !!events[event] : bool
end
alias_method :"#{event}?", event
end
# Allow people to receive failed pipeline notifications if they already have # Allow people to receive failed pipeline notifications if they already have
# custom notifications enabled, as these are more like mentions than the other # custom notifications enabled, as these are more like mentions than the other
# custom settings. # custom settings.
def failed_pipeline def failed_pipeline
bool = super bool = super
bool = events[:failed_pipeline] if bool.nil?
bool.nil? || bool bool.nil? || bool
end end
alias_method :failed_pipeline?, :failed_pipeline alias_method :failed_pipeline?, :failed_pipeline
def event_enabled?(event) def event_enabled?(event)
respond_to?(event) && public_send(event) respond_to?(event) && !!public_send(event)
end
def convert_events
return if events_before_type_cast.nil?
EMAIL_EVENTS.each do |event|
write_attribute(event, public_send(event))
end
write_attribute(:events, nil)
end end
end end
...@@ -18,9 +18,12 @@ class Project < ActiveRecord::Base ...@@ -18,9 +18,12 @@ class Project < ActiveRecord::Base
include SelectForProjectAuthorization include SelectForProjectAuthorization
include Routable include Routable
include Storage::LegacyProject include Storage::LegacyProject
<<<<<<< HEAD
# EE specific modules # EE specific modules
prepend EE::Project prepend EE::Project
=======
>>>>>>> ce/master
extend Gitlab::ConfigHelper extend Gitlab::ConfigHelper
...@@ -1206,7 +1209,18 @@ class Project < ActiveRecord::Base ...@@ -1206,7 +1209,18 @@ class Project < ActiveRecord::Base
end end
def remove_private_deploy_keys def remove_private_deploy_keys
deploy_keys.where(public: false).delete_all exclude_keys_linked_to_other_projects = <<-SQL
NOT EXISTS (
SELECT 1
FROM deploy_keys_projects dkp2
WHERE dkp2.deploy_key_id = deploy_keys_projects.deploy_key_id
AND dkp2.project_id != deploy_keys_projects.project_id
)
SQL
deploy_keys.where(public: false)
.where(exclude_keys_linked_to_other_projects)
.delete_all
end end
# TODO: what to do here when not using Legacy Storage? Do we still need to rename and delay removal? # TODO: what to do here when not using Legacy Storage? Do we still need to rename and delay removal?
......
class ProjectWiki class ProjectWiki
include Gitlab::ShellAdapter include Gitlab::ShellAdapter
<<<<<<< HEAD
include Elastic::WikiRepositoriesSearch include Elastic::WikiRepositoriesSearch
include Gitlab::CurrentSettings include Gitlab::CurrentSettings
=======
>>>>>>> ce/master
include Storage::LegacyProjectWiki include Storage::LegacyProjectWiki
MARKUPS = { MARKUPS = {
...@@ -50,11 +53,14 @@ class ProjectWiki ...@@ -50,11 +53,14 @@ class ProjectWiki
def http_url_to_repo def http_url_to_repo
"#{Gitlab.config.gitlab.url}/#{full_path}.git" "#{Gitlab.config.gitlab.url}/#{full_path}.git"
<<<<<<< HEAD
end end
# No need to have a Kerberos Web url. Kerberos URL will be used only to clone # No need to have a Kerberos Web url. Kerberos URL will be used only to clone
def kerberos_url_to_repo def kerberos_url_to_repo
[Gitlab.config.build_gitlab_kerberos_url, '/', full_path, '.git'].join('') [Gitlab.config.build_gitlab_kerberos_url, '/', full_path, '.git'].join('')
=======
>>>>>>> ce/master
end end
def wiki_base_path def wiki_base_path
......
...@@ -1018,7 +1018,7 @@ class Repository ...@@ -1018,7 +1018,7 @@ class Repository
if is_enabled if is_enabled
raw_repository.is_ancestor?(ancestor_id, descendant_id) raw_repository.is_ancestor?(ancestor_id, descendant_id)
else else
merge_base_commit(ancestor_id, descendant_id) == ancestor_id rugged_is_ancestor?(ancestor_id, descendant_id)
end end
end end
end end
......
...@@ -44,7 +44,7 @@ class GlobalPolicy < BasePolicy ...@@ -44,7 +44,7 @@ class GlobalPolicy < BasePolicy
prevent :log_in prevent :log_in
end end
rule { admin | ~restricted_public_level }.policy do rule { ~(anonymous & restricted_public_level) }.policy do
enable :read_users_list enable :read_users_list
end end
end end
...@@ -3,8 +3,11 @@ module Ci ...@@ -3,8 +3,11 @@ module Ci
def execute def execute
if trigger_from_token if trigger_from_token
create_pipeline_from_trigger(trigger_from_token) create_pipeline_from_trigger(trigger_from_token)
<<<<<<< HEAD
elsif job_from_token elsif job_from_token
create_pipeline_from_job(job_from_token) create_pipeline_from_job(job_from_token)
=======
>>>>>>> ce/master
end end
end end
...@@ -27,6 +30,7 @@ module Ci ...@@ -27,6 +30,7 @@ module Ci
end end
end end
<<<<<<< HEAD
def create_pipeline_from_job(job) def create_pipeline_from_job(job)
# this check is to not leak the presence of the project if user cannot read it # this check is to not leak the presence of the project if user cannot read it
return unless can?(job.user, :read_project, project) return unless can?(job.user, :read_project, project)
...@@ -51,18 +55,23 @@ module Ci ...@@ -51,18 +55,23 @@ module Ci
end end
end end
=======
>>>>>>> ce/master
def trigger_from_token def trigger_from_token
return @trigger if defined?(@trigger) return @trigger if defined?(@trigger)
@trigger = Ci::Trigger.find_by_token(params[:token].to_s) @trigger = Ci::Trigger.find_by_token(params[:token].to_s)
end end
<<<<<<< HEAD
def job_from_token def job_from_token
return @job if defined?(@job) return @job if defined?(@job)
@job = Ci::Build.find_by_token(params[:token].to_s) @job = Ci::Build.find_by_token(params[:token].to_s)
end end
=======
>>>>>>> ce/master
def create_pipeline_variables!(pipeline) def create_pipeline_variables!(pipeline)
return unless params[:variables] return unless params[:variables]
......
...@@ -11,7 +11,7 @@ class DeleteMergedBranchesService < BaseService ...@@ -11,7 +11,7 @@ class DeleteMergedBranchesService < BaseService
# Prevent deletion of branches relevant to open merge requests # Prevent deletion of branches relevant to open merge requests
branches -= merge_request_branch_names branches -= merge_request_branch_names
# Prevent deletion of protected branches # Prevent deletion of protected branches
branches -= project.protected_branches.pluck(:name) branches = branches.reject { |branch| project.protected_for?(branch) }
branches.each do |branch| branches.each do |branch|
DeleteBranchService.new(project, current_user).execute(branch) DeleteBranchService.new(project, current_user).execute(branch)
......
...@@ -45,6 +45,7 @@ class GitPushService < BaseService ...@@ -45,6 +45,7 @@ class GitPushService < BaseService
elsif push_to_existing_branch? elsif push_to_existing_branch?
# Collect data for this git push # Collect data for this git push
@push_commits = @project.repository.commits_between(params[:oldrev], params[:newrev]) @push_commits = @project.repository.commits_between(params[:oldrev], params[:newrev])
process_commit_messages process_commit_messages
# Update the bare repositories info/attributes file using the contents of the default branches # Update the bare repositories info/attributes file using the contents of the default branches
...@@ -71,15 +72,21 @@ class GitPushService < BaseService ...@@ -71,15 +72,21 @@ class GitPushService < BaseService
def update_caches def update_caches
if is_default_branch? if is_default_branch?
if push_to_new_branch?
# If this is the initial push into the default branch, the file type caches
# will already be reset as a result of `Project#change_head`.
types = []
else
paths = Set.new paths = Set.new
@push_commits.each do |commit| @push_commits.last(PROCESS_COMMIT_LIMIT).each do |commit|
commit.raw_deltas.each do |diff| commit.raw_deltas.each do |diff|
paths << diff.new_path paths << diff.new_path
end end
end end
types = Gitlab::FileDetector.types_in_paths(paths.to_a) types = Gitlab::FileDetector.types_in_paths(paths.to_a)
end
else else
types = [] types = []
end end
...@@ -97,7 +104,7 @@ class GitPushService < BaseService ...@@ -97,7 +104,7 @@ class GitPushService < BaseService
def process_commit_messages def process_commit_messages
default = is_default_branch? default = is_default_branch?
push_commits.last(PROCESS_COMMIT_LIMIT).each do |commit| @push_commits.last(PROCESS_COMMIT_LIMIT).each do |commit|
if commit.matches_cross_reference_regex? if commit.matches_cross_reference_regex?
ProcessCommitWorker ProcessCommitWorker
.perform_async(project.id, current_user.id, commit.to_hash, default) .perform_async(project.id, current_user.id, commit.to_hash, default)
...@@ -124,8 +131,13 @@ class GitPushService < BaseService ...@@ -124,8 +131,13 @@ class GitPushService < BaseService
mirror_update = @project.mirror? && @project.repository.up_to_date_with_upstream?(branch_name) mirror_update = @project.mirror? && @project.repository.up_to_date_with_upstream?(branch_name)
EventCreateService.new.push(@project, current_user, build_push_data) EventCreateService.new.push(@project, current_user, build_push_data)
<<<<<<< HEAD
Ci::CreatePipelineService.new(@project, current_user, build_push_data).execute(:push, mirror_update: mirror_update) Ci::CreatePipelineService.new(@project, current_user, build_push_data).execute(:push, mirror_update: mirror_update)
=======
Ci::CreatePipelineService.new(@project, current_user, build_push_data).execute(:push)
>>>>>>> ce/master
SystemHookPushWorker.perform_async(build_push_data.dup, :push_hooks) SystemHookPushWorker.perform_async(build_push_data.dup, :push_hooks)
@project.execute_hooks(build_push_data.dup, :push_hooks) @project.execute_hooks(build_push_data.dup, :push_hooks)
@project.execute_services(build_push_data.dup, :push_hooks) @project.execute_services(build_push_data.dup, :push_hooks)
...@@ -145,7 +157,10 @@ class GitPushService < BaseService ...@@ -145,7 +157,10 @@ class GitPushService < BaseService
end end
def process_default_branch def process_default_branch
@push_commits = project.repository.commits(params[:newrev]) @push_commits_count = project.repository.commit_count_for_ref(params[:ref])
offset = [@push_commits_count - PROCESS_COMMIT_LIMIT, 0].max
@push_commits = project.repository.commits(params[:newrev], offset: offset, limit: PROCESS_COMMIT_LIMIT)
# Ensure HEAD points to the default branch in case it is not master # Ensure HEAD points to the default branch in case it is not master
project.change_head(branch_name) project.change_head(branch_name)
...@@ -174,7 +189,8 @@ class GitPushService < BaseService ...@@ -174,7 +189,8 @@ class GitPushService < BaseService
params[:oldrev], params[:oldrev],
params[:newrev], params[:newrev],
params[:ref], params[:ref],
push_commits) @push_commits,
commits_count: @push_commits_count)
end end
def push_to_existing_branch? def push_to_existing_branch?
......
module MergeRequests module MergeRequests
class BaseService < ::IssuableBaseService class BaseService < ::IssuableBaseService
<<<<<<< HEAD
prepend EE::MergeRequests::BaseService prepend EE::MergeRequests::BaseService
=======
>>>>>>> ce/master
def create_note(merge_request, state = merge_request.state) def create_note(merge_request, state = merge_request.state)
SystemNoteService.change_status(merge_request, merge_request.target_project, current_user, state, nil) SystemNoteService.change_status(merge_request, merge_request.target_project, current_user, state, nil)
end end
......
...@@ -5,6 +5,9 @@ module QuickActions ...@@ -5,6 +5,9 @@ module QuickActions
attr_reader :issuable attr_reader :issuable
SHRUG = '¯\\_(ツ)_/¯'.freeze
TABLEFLIP = '(╯°□°)╯︵ ┻━┻'.freeze
# Takes a text and interprets the commands that are extracted from it. # Takes a text and interprets the commands that are extracted from it.
# Returns the content without commands, and hash of changes to be applied to a record. # Returns the content without commands, and hash of changes to be applied to a record.
def execute(content, issuable) def execute(content, issuable)
...@@ -15,6 +18,7 @@ module QuickActions ...@@ -15,6 +18,7 @@ module QuickActions
content, commands = extractor.extract_commands(content, context) content, commands = extractor.extract_commands(content, context)
extract_updates(commands, context) extract_updates(commands, context)
[content, @updates] [content, @updates]
end end
...@@ -424,6 +428,18 @@ module QuickActions ...@@ -424,6 +428,18 @@ module QuickActions
@updates[:spend_time] = { duration: :reset, user: current_user } @updates[:spend_time] = { duration: :reset, user: current_user }
end end
desc "Append the comment with #{SHRUG}"
params '<Comment>'
substitution :shrug do |comment|
"#{comment} #{SHRUG}"
end
desc "Append the comment with #{TABLEFLIP}"
params '<Comment>'
substitution :tableflip do |comment|
"#{comment} #{TABLEFLIP}"
end
# This is a dummy command, so that it appears in the autocomplete commands # This is a dummy command, so that it appears in the autocomplete commands
desc 'CC' desc 'CC'
params '@user' params '@user'
......
...@@ -44,7 +44,7 @@ class WebHookService ...@@ -44,7 +44,7 @@ class WebHookService
http_status: response.code, http_status: response.code,
message: response.to_s message: response.to_s
} }
rescue SocketError, OpenSSL::SSL::SSLError, Errno::ECONNRESET, Errno::ECONNREFUSED, Net::OpenTimeout => e rescue SocketError, OpenSSL::SSL::SSLError, Errno::ECONNRESET, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Net::OpenTimeout, Net::ReadTimeout => e
log_execution( log_execution(
trigger: hook_name, trigger: hook_name,
url: hook.url, url: hook.url,
...@@ -101,7 +101,7 @@ class WebHookService ...@@ -101,7 +101,7 @@ class WebHookService
request_headers: build_headers(hook_name), request_headers: build_headers(hook_name),
request_data: request_data, request_data: request_data,
response_headers: format_response_headers(response), response_headers: format_response_headers(response),
response_body: response.body, response_body: safe_response_body(response),
response_status: response.code, response_status: response.code,
internal_error_message: error_message internal_error_message: error_message
) )
...@@ -124,4 +124,10 @@ class WebHookService ...@@ -124,4 +124,10 @@ class WebHookService
def format_response_headers(response) def format_response_headers(response)
response.headers.each_capitalized.to_h response.headers.each_capitalized.to_h
end end
def safe_response_body(response)
return '' unless response.body
response.body.encode('UTF-8', invalid: :replace, undef: :replace, replace: '')
end
end end
...@@ -356,7 +356,7 @@ ...@@ -356,7 +356,7 @@
\. This setting requires a \. This setting requires a
= link_to 'restart', help_page_path('administration/restart_gitlab') = link_to 'restart', help_page_path('administration/restart_gitlab')
to take effect. to take effect.
= link_to icon('question-circle'), help_page_path('administration/monitoring/performance/introduction') = link_to icon('question-circle'), help_page_path('administration/monitoring/prometheus/index')
.form-group .form-group
.col-sm-offset-2.col-sm-10 .col-sm-offset-2.col-sm-10
.checkbox .checkbox
......
...@@ -7,7 +7,10 @@ ...@@ -7,7 +7,10 @@
- content_for :page_specific_javascripts do - content_for :page_specific_javascripts do
= webpack_bundle_tag 'common_vue' = webpack_bundle_tag 'common_vue'
= webpack_bundle_tag 'filtered_search' = webpack_bundle_tag 'filtered_search'
<<<<<<< HEAD
= webpack_bundle_tag 'issues' = webpack_bundle_tag 'issues'
=======
>>>>>>> ce/master
- if show_new_nav? && group_issues_exists - if show_new_nav? && group_issues_exists
- content_for :breadcrumbs_extra do - content_for :breadcrumbs_extra do
......
- @breadcrumb_title = "Help"
- page_title "Help" - page_title "Help"
- header_title "Help", help_path - header_title "Help", help_path
......
...@@ -109,6 +109,7 @@ ...@@ -109,6 +109,7 @@
%span.nav-item-name %span.nav-item-name
Abuse Reports Abuse Reports
%span.badge.count= number_with_delimiter(AbuseReport.count(:all)) %span.badge.count= number_with_delimiter(AbuseReport.count(:all))
<<<<<<< HEAD
= nav_link(controller: :licenses) do = nav_link(controller: :licenses) do
= link_to admin_license_path, title: 'License' do = link_to admin_license_path, title: 'License' do
...@@ -116,6 +117,8 @@ ...@@ -116,6 +117,8 @@
= custom_icon('license') = custom_icon('license')
%span %span
License License
=======
>>>>>>> ce/master
- if akismet_enabled? - if akismet_enabled?
= nav_link(controller: :spam_logs) do = nav_link(controller: :spam_logs) do
......
...@@ -67,7 +67,9 @@ ...@@ -67,7 +67,9 @@
SSH Keys SSH Keys
= nav_link(controller: :gpg_keys) do = nav_link(controller: :gpg_keys) do
= link_to profile_gpg_keys_path, title: 'GPG Keys' do = link_to profile_gpg_keys_path, title: 'GPG Keys' do
%span .nav-icon-container
= custom_icon('key_2')
%span.nav-item-name
GPG Keys GPG Keys
= nav_link(controller: :preferences) do = nav_link(controller: :preferences) do
= link_to profile_preferences_path, title: 'Preferences' do = link_to profile_preferences_path, title: 'Preferences' do
......
...@@ -95,6 +95,7 @@ ...@@ -95,6 +95,7 @@
= link_to project_issues_path(@project), title: 'Issues' do = link_to project_issues_path(@project), title: 'Issues' do
%span %span
List List
<<<<<<< HEAD
= nav_link(controller: :boards) do = nav_link(controller: :boards) do
= link_to project_boards_path(@project), title: 'Boards' do = link_to project_boards_path(@project), title: 'Boards' do
...@@ -104,6 +105,8 @@ ...@@ -104,6 +105,8 @@
= link_to project_issues_path(@project), title: 'Issues' do = link_to project_issues_path(@project), title: 'Issues' do
%span %span
List List
=======
>>>>>>> ce/master
= nav_link(controller: :boards) do = nav_link(controller: :boards) do
= link_to project_boards_path(@project), title: 'Board' do = link_to project_boards_path(@project), title: 'Board' do
......
...@@ -30,14 +30,21 @@ ...@@ -30,14 +30,21 @@
= link_to _("Create merge request"), create_mr_path(@repository.root_ref, @ref), class: 'btn btn-success' = link_to _("Create merge request"), create_mr_path(@repository.root_ref, @ref), class: 'btn btn-success'
.control .control
<<<<<<< HEAD
= form_tag(project_commits_path(@project, @id), method: :get, class: 'commits-search-form') do = form_tag(project_commits_path(@project, @id), method: :get, class: 'commits-search-form') do
=======
= form_tag(project_commits_path(@project, @id), method: :get, class: 'commits-search-form', data: { 'signatures-path' => namespace_project_signatures_path }) do
>>>>>>> ce/master
= search_field_tag :search, params[:search], { placeholder: _('Filter by commit message'), id: 'commits-search', class: 'form-control search-text-input input-short', spellcheck: false } = search_field_tag :search, params[:search], { placeholder: _('Filter by commit message'), id: 'commits-search', class: 'form-control search-text-input input-short', spellcheck: false }
.control .control
= link_to project_commits_path(@project, @ref, rss_url_options), title: _("Commits feed"), class: 'btn' do = link_to project_commits_path(@project, @ref, rss_url_options), title: _("Commits feed"), class: 'btn' do
= icon("rss") = icon("rss")
<<<<<<< HEAD
= render 'projects/commits/mirror_status' = render 'projects/commits/mirror_status'
=======
>>>>>>> ce/master
%div{ id: dom_id(@project) } %div{ id: dom_id(@project) }
%ol#commits-list.list-unstyled.content_list %ol#commits-list.list-unstyled.content_list
= render 'commits', project: @project, ref: @ref = render 'commits', project: @project, ref: @ref
......
<<<<<<< HEAD
.tree-content-holder.js-tree-content{ 'data-logs-path': @logs_path, 'data-path-locks-available': (@project.feature_available?(:file_locks) ? 'true' : 'false'), 'data-path-locks-toggle': toggle_project_path_locks_path(@project), 'data-path-locks-path': @path } .tree-content-holder.js-tree-content{ 'data-logs-path': @logs_path, 'data-path-locks-available': (@project.feature_available?(:file_locks) ? 'true' : 'false'), 'data-path-locks-toggle': toggle_project_path_locks_path(@project), 'data-path-locks-path': @path }
=======
.tree-content-holder.js-tree-content{ 'data-logs-path': @logs_path }
>>>>>>> ce/master
.table-holder .table-holder
%table.table#tree-slider{ class: "table_#{@hex_path} tree-table" } %table.table#tree-slider{ class: "table_#{@hex_path} tree-table" }
%thead %thead
......
...@@ -23,7 +23,10 @@ ...@@ -23,7 +23,10 @@
= text_field_tag :project_clone, default_url_to_repo(project), class: "js-select-on-focus form-control", readonly: true, aria: { label: 'Project clone URL' } = text_field_tag :project_clone, default_url_to_repo(project), class: "js-select-on-focus form-control", readonly: true, aria: { label: 'Project clone URL' }
.input-group-btn .input-group-btn
= clipboard_button(target: '#project_clone', title: _("Copy URL to clipboard"), class: "btn-default btn-clipboard") = clipboard_button(target: '#project_clone', title: _("Copy URL to clipboard"), class: "btn-default btn-clipboard")
<<<<<<< HEAD
= geo_button(modal_target: '#modal-geo-info') if Gitlab::Geo.secondary? = geo_button(modal_target: '#modal-geo-info') if Gitlab::Geo.secondary?
= render 'shared/geo_info_modal', project: project if Gitlab::Geo.secondary? = render 'shared/geo_info_modal', project: project if Gitlab::Geo.secondary?
=======
>>>>>>> ce/master
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M5.172 14.157l-.344.344-2.485.133a.462.462 0 0 1-.497-.503l.14-2.24a.599.599 0 0 1 .177-.382l5.155-5.155a4 4 0 1 1 2.828 2.828l-1.439 1.44-1.06-.354-.708.707.354 1.06-.707.708-1.06-.354-.708.707.354 1.06zm6.01-8.839a1 1 0 1 0 1.414-1.414 1 1 0 0 0-1.414 1.414z"/></svg>
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
= link_to 'Edit', '#', class: 'edit-link pull-right' = link_to 'Edit', '#', class: 'edit-link pull-right'
.value.hide-collapsed .value.hide-collapsed
- if issuable.milestone - if issuable.milestone
= link_to issuable.milestone.title, project_milestone_path(@project, issuable.milestone), class: "bold has-tooltip", title: milestone_remaining_days(issuable.milestone), data: { container: "body", html: 1 } = link_to issuable.milestone.title, milestone_path(issuable.milestone), class: "bold has-tooltip", title: milestone_remaining_days(issuable.milestone), data: { container: "body", html: 1 }
- else - else
%span.no-value None %span.no-value None
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
= hidden_field_tag :line_type = hidden_field_tag :line_type
= hidden_field_tag :merge_request_diff_head_sha, @note.noteable.try(:diff_head_sha) = hidden_field_tag :merge_request_diff_head_sha, @note.noteable.try(:diff_head_sha)
= hidden_field_tag :in_reply_to_discussion_id = hidden_field_tag :in_reply_to_discussion_id
= hidden_field_tag :note_project_id
= note_target_fields(@note) = note_target_fields(@note)
= f.hidden_field :noteable_type = f.hidden_field :noteable_type
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
- if avatar - if avatar
.avatar-container.s40 .avatar-container.s40
= link_to project_path(project), class: dom_class(project) do = link_to project_path(project), class: dom_class(project) do
- if use_creator_avatar - if project.creator && use_creator_avatar
= image_tag avatar_icon(project.creator.email, 40), class: "avatar s40", alt:'' = image_tag avatar_icon(project.creator.email, 40), class: "avatar s40", alt:''
- else - else
= project_icon(project, alt: '', class: 'avatar project-avatar s40') = project_icon(project, alt: '', class: 'avatar project-avatar s40')
......
...@@ -31,8 +31,6 @@ class EmailReceiverWorker ...@@ -31,8 +31,6 @@ class EmailReceiverWorker
when Gitlab::Email::EmptyEmailError when Gitlab::Email::EmptyEmailError
can_retry = true can_retry = true
"It appears that the email is blank. Make sure your reply is at the top of the email, we can't process inline replies." "It appears that the email is blank. Make sure your reply is at the top of the email, we can't process inline replies."
when Gitlab::Email::AutoGeneratedEmailError
"The email was marked as 'auto generated', which we can't accept. Please create your comment through the web interface."
when Gitlab::Email::UserNotFoundError when Gitlab::Email::UserNotFoundError
"We couldn't figure out what user corresponds to the email. Please create your comment through the web interface." "We couldn't figure out what user corresponds to the email. Please create your comment through the web interface."
when Gitlab::Email::UserBlockedError when Gitlab::Email::UserBlockedError
......
...@@ -5,6 +5,12 @@ class GitGarbageCollectWorker ...@@ -5,6 +5,12 @@ class GitGarbageCollectWorker
sidekiq_options retry: false sidekiq_options retry: false
GITALY_MIGRATED_TASKS = {
gc: :garbage_collect,
full_repack: :repack_full,
incremental_repack: :repack_incremental
}.freeze
def perform(project_id, task = :gc, lease_key = nil, lease_uuid = nil) def perform(project_id, task = :gc, lease_key = nil, lease_uuid = nil)
project = Project.find(project_id) project = Project.find(project_id)
task = task.to_sym task = task.to_sym
...@@ -15,8 +21,14 @@ class GitGarbageCollectWorker ...@@ -15,8 +21,14 @@ class GitGarbageCollectWorker
Gitlab::GitLogger.info(description) Gitlab::GitLogger.info(description)
gitaly_migrate(GITALY_MIGRATED_TASKS[task]) do |is_enabled|
if is_enabled
gitaly_call(task, project.repository.raw_repository)
else
output, status = Gitlab::Popen.popen(cmd, repo_path) output, status = Gitlab::Popen.popen(cmd, repo_path)
Gitlab::GitLogger.error("#{description} failed:\n#{output}") unless status.zero? Gitlab::GitLogger.error("#{description} failed:\n#{output}") unless status.zero?
end
end
# Refresh the branch cache in case garbage collection caused a ref lookup to fail # Refresh the branch cache in case garbage collection caused a ref lookup to fail
flush_ref_caches(project) if task == :gc flush_ref_caches(project) if task == :gc
...@@ -26,6 +38,19 @@ class GitGarbageCollectWorker ...@@ -26,6 +38,19 @@ class GitGarbageCollectWorker
private private
## `repository` has to be a Gitlab::Git::Repository
def gitaly_call(task, repository)
client = Gitlab::GitalyClient::RepositoryService.new(repository)
case task
when :gc
client.garbage_collect(bitmaps_enabled?)
when :full_repack
client.repack_full(bitmaps_enabled?)
when :incremental_repack
client.repack_incremental
end
end
def command(task) def command(task)
case task case task
when :gc when :gc
...@@ -55,4 +80,14 @@ class GitGarbageCollectWorker ...@@ -55,4 +80,14 @@ class GitGarbageCollectWorker
config_value = write_bitmaps ? 'true' : 'false' config_value = write_bitmaps ? 'true' : 'false'
%W[git -c repack.writeBitmaps=#{config_value}] %W[git -c repack.writeBitmaps=#{config_value}]
end end
def gitaly_migrate(method, &block)
Gitlab::GitalyClient.migrate(method, &block)
rescue GRPC::NotFound => e
Gitlab::GitLogger.error("#{method} failed:\nRepository not found")
raise Gitlab::Git::Repository::NoRepository.new(e)
rescue GRPC::BadStatus => e
Gitlab::GitLogger.error("#{method} failed:\n#{e}")
raise Gitlab::Git::CommandError.new(e)
end
end end
---
title: "Fix v3 api project_hooks POST and PUT operations for build_events"
merge_request: 12673
author: Richard Clamp
---
title: Expose target_iid in Events API
merge_request: 13247
author: sue445
---
title: Don't send rejection mails for all auto-generated mails
merge_request: 13254
author:
---
title: Add /shrug and /tableflip commands
merge_request: 10068
author: Alex Ives
---
title: Remove events column from notification settings table
merge_request:
author:
---
title: Use jQuery to control scroll behavior in job log for cross browser consistency
merge_request:
author:
---
title: Extend API for Group Secret Variable
merge_request: 12936
author:
---
title: Bump rubocop to 0.49.1 and rubocop-rspec to 1.15.1
merge_request:
author: Takuya Noguchi
---
title: Fix project logos that are not centered vertically on list pages
merge_request: 13124
author: Florian Lemaitre
---
title: Show auto-generated avatars for Groups without avatars
merge_request: 13188
author:
---
title: Fix creating merge request diffs when diff contains bytes that are invalid
in UTF-8
merge_request:
author:
---
title: Fix display of new diff comments after changing b between diff views
merge_request:
author:
---
title: Allow any logged in users to read_users_list even if it's restricted
merge_request: 13201
author:
---
title: Fix Issue board when using Ruby 2.4
merge_request: 13220
author:
---
title: Fix encoding error for WebHook logging
merge_request: 13230
author: Alexander Randa (@randaalex)
--- ---
title: Add LDAP SSL certificate verification option title: Add filtered search to group issue dashboard
merge_request: merge_request:
author: author:
--- ---
title: Ensure filesystem metrics test files are deleted title: Fixed breadcrumbs title aggressively collapsing
merge_request: merge_request:
author: author:
---
title: Improve performance of large (initial) push into default branch
merge_request:
author:
---
title: Add API for protected branches to allow for wildcard matching and no access
restrictions
merge_request: 12756
author: Eric Yu
---
title: Modify if condition to be more readable
merge_request:
author:
---
title: Fix links to group milestones from issue and merge request sidebar
merge_request:
author:
---
title: Fix replying to commit comments on merge requests created from forks
merge_request:
author:
---
title: Uniquify reserved word usernames on OAuth user creation
merge_request: 13244
author: Robin Bobbitt
---
title: Improve redirect route query performance
merge_request: 13062
author:
---
title: Fix deletion of deploy keys linked to other projects
merge_request: 13162
author:
---
title: Fix improperly skipped backups of wikis.
merge_request: 13096
author:
---
title: Add support for kube_namespace in Metrics queries
merge_request: 16169
author:
---
title: Fix Prometheus client PID reuse bug
merge_request: 13130
author:
---
title: Change project FK migration to skip existing FKs
merge_request:
author:
---
title: Fix search box losing focus when typing
merge_request:
author:
---
title: Make Delete Merged Branches handle wildcard protected branches correctly
merge_request: 13251
author:
---
title: Derive project path from import URL
merge_request: 13131
author:
...@@ -331,7 +331,7 @@ production: &base ...@@ -331,7 +331,7 @@ production: &base
# #
# Example: '/etc/ca.pem' # Example: '/etc/ca.pem'
# #
ca_cert: '' ca_file: ''
# Specifies the SSL version for OpenSSL to use, if the OpenSSL default # Specifies the SSL version for OpenSSL to use, if the OpenSSL default
# is not appropriate. # is not appropriate.
......
...@@ -257,7 +257,7 @@ Settings.gitlab['default_can_create_group'] = true if Settings.gitlab['default_c ...@@ -257,7 +257,7 @@ Settings.gitlab['default_can_create_group'] = true if Settings.gitlab['default_c
Settings.gitlab['host'] ||= ENV['GITLAB_HOST'] || 'localhost' Settings.gitlab['host'] ||= ENV['GITLAB_HOST'] || 'localhost'
Settings.gitlab['ssh_host'] ||= Settings.gitlab.host Settings.gitlab['ssh_host'] ||= Settings.gitlab.host
Settings.gitlab['https'] = false if Settings.gitlab['https'].nil? Settings.gitlab['https'] = false if Settings.gitlab['https'].nil?
Settings.gitlab['port'] ||= Settings.gitlab.https ? 443 : 80 Settings.gitlab['port'] ||= ENV['GITLAB_PORT'] || (Settings.gitlab.https ? 443 : 80)
Settings.gitlab['relative_url_root'] ||= ENV['RAILS_RELATIVE_URL_ROOT'] || '' Settings.gitlab['relative_url_root'] ||= ENV['RAILS_RELATIVE_URL_ROOT'] || ''
Settings.gitlab['protocol'] ||= Settings.gitlab.https ? "https" : "http" Settings.gitlab['protocol'] ||= Settings.gitlab.https ? "https" : "http"
Settings.gitlab['email_enabled'] ||= true if Settings.gitlab['email_enabled'].nil? Settings.gitlab['email_enabled'] ||= true if Settings.gitlab['email_enabled'].nil?
......
...@@ -62,8 +62,8 @@ class ProjectForeignKeysWithCascadingDeletes < ActiveRecord::Migration ...@@ -62,8 +62,8 @@ class ProjectForeignKeysWithCascadingDeletes < ActiveRecord::Migration
# These columns are not indexed yet, meaning a cascading delete would take # These columns are not indexed yet, meaning a cascading delete would take
# forever. # forever.
add_concurrent_index(:project_group_links, :project_id) add_index_if_not_exists(:project_group_links, :project_id)
add_concurrent_index(:pages_domains, :project_id) add_index_if_not_exists(:pages_domains, :project_id)
end end
def down def down
...@@ -71,15 +71,15 @@ class ProjectForeignKeysWithCascadingDeletes < ActiveRecord::Migration ...@@ -71,15 +71,15 @@ class ProjectForeignKeysWithCascadingDeletes < ActiveRecord::Migration
remove_foreign_key_without_error(source, column) remove_foreign_key_without_error(source, column)
end end
add_concurrent_foreign_key(:boards, :projects, column: :project_id) add_foreign_key_if_not_exists(:boards, :projects, column: :project_id)
add_concurrent_foreign_key(:lists, :labels, column: :label_id) add_foreign_key_if_not_exists(:lists, :labels, column: :label_id)
add_concurrent_foreign_key(:lists, :boards, column: :board_id) add_foreign_key_if_not_exists(:lists, :boards, column: :board_id)
add_concurrent_foreign_key(:protected_branch_merge_access_levels, add_foreign_key_if_not_exists(:protected_branch_merge_access_levels,
:protected_branches, :protected_branches,
column: :protected_branch_id) column: :protected_branch_id)
add_concurrent_foreign_key(:protected_branch_push_access_levels, add_foreign_key_if_not_exists(:protected_branch_push_access_levels,
:protected_branches, :protected_branches,
column: :protected_branch_id) column: :protected_branch_id)
...@@ -89,7 +89,7 @@ class ProjectForeignKeysWithCascadingDeletes < ActiveRecord::Migration ...@@ -89,7 +89,7 @@ class ProjectForeignKeysWithCascadingDeletes < ActiveRecord::Migration
def add_foreign_keys def add_foreign_keys
TABLES.each do |(source, target, column)| TABLES.each do |(source, target, column)|
add_concurrent_foreign_key(source, target, column: column) add_foreign_key_if_not_exists(source, target, column: column)
end end
end end
...@@ -153,6 +153,18 @@ class ProjectForeignKeysWithCascadingDeletes < ActiveRecord::Migration ...@@ -153,6 +153,18 @@ class ProjectForeignKeysWithCascadingDeletes < ActiveRecord::Migration
EOF EOF
end end
def add_foreign_key_if_not_exists(source, target, column:)
return if foreign_key_exists?(source, column)
add_concurrent_foreign_key(source, target, column: column)
end
def add_index_if_not_exists(table, column)
return if index_exists?(table, column)
add_concurrent_index(table, column)
end
def remove_foreign_key_without_error(table, column) def remove_foreign_key_without_error(table, column)
remove_foreign_key(table, column: column) remove_foreign_key(table, column: column)
rescue ArgumentError rescue ArgumentError
...@@ -163,6 +175,12 @@ class ProjectForeignKeysWithCascadingDeletes < ActiveRecord::Migration ...@@ -163,6 +175,12 @@ class ProjectForeignKeysWithCascadingDeletes < ActiveRecord::Migration
rescue ArgumentError rescue ArgumentError
end end
def foreign_key_exists?(table, column)
foreign_keys(table).any? do |key|
key.options[:column] == column.to_s
end
end
def connection def connection
# Rails memoizes connection objects, but this causes them to be shared # Rails memoizes connection objects, but this causes them to be shared
# amongst threads; we don't want that. # amongst threads; we don't want that.
......
class RemoveEventsFromNotificationSettings < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
remove_column :notification_settings, :events, :text
end
end
...@@ -11,7 +11,11 @@ ...@@ -11,7 +11,11 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
<<<<<<< HEAD
ActiveRecord::Schema.define(version: 20170726111039) do ActiveRecord::Schema.define(version: 20170726111039) do
=======
ActiveRecord::Schema.define(version: 20170728101014) do
>>>>>>> ce/master
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
...@@ -313,32 +317,32 @@ ActiveRecord::Schema.define(version: 20170726111039) do ...@@ -313,32 +317,32 @@ ActiveRecord::Schema.define(version: 20170726111039) do
add_index "ci_builds", ["updated_at"], name: "index_ci_builds_on_updated_at", using: :btree add_index "ci_builds", ["updated_at"], name: "index_ci_builds_on_updated_at", using: :btree
add_index "ci_builds", ["user_id"], name: "index_ci_builds_on_user_id", using: :btree add_index "ci_builds", ["user_id"], name: "index_ci_builds_on_user_id", using: :btree
create_table "ci_pipeline_schedule_variables", force: :cascade do |t| create_table "ci_group_variables", force: :cascade do |t|
t.string "key", null: false t.string "key", null: false
t.text "value" t.text "value"
t.text "encrypted_value" t.text "encrypted_value"
t.string "encrypted_value_salt" t.string "encrypted_value_salt"
t.string "encrypted_value_iv" t.string "encrypted_value_iv"
t.integer "pipeline_schedule_id", null: false t.integer "group_id", null: false
t.boolean "protected", default: false, null: false
t.datetime "created_at", null: false t.datetime "created_at", null: false
t.datetime "updated_at", null: false t.datetime "updated_at", null: false
end end
add_index "ci_pipeline_schedule_variables", ["pipeline_schedule_id", "key"], name: "index_ci_pipeline_schedule_variables_on_schedule_id_and_key", unique: true, using: :btree add_index "ci_group_variables", ["group_id", "key"], name: "index_ci_group_variables_on_group_id_and_key", unique: true, using: :btree
create_table "ci_group_variables", force: :cascade do |t| create_table "ci_pipeline_schedule_variables", force: :cascade do |t|
t.string "key", null: false t.string "key", null: false
t.text "value" t.text "value"
t.text "encrypted_value" t.text "encrypted_value"
t.string "encrypted_value_salt" t.string "encrypted_value_salt"
t.string "encrypted_value_iv" t.string "encrypted_value_iv"
t.integer "group_id", null: false t.integer "pipeline_schedule_id", null: false
t.boolean "protected", default: false, null: false t.datetime "created_at"
t.datetime "created_at", null: false t.datetime "updated_at"
t.datetime "updated_at", null: false
end end
add_index "ci_group_variables", ["group_id", "key"], name: "index_ci_group_variables_on_group_id_and_key", unique: true, using: :btree add_index "ci_pipeline_schedule_variables", ["pipeline_schedule_id", "key"], name: "index_ci_pipeline_schedule_variables_on_schedule_id_and_key", unique: true, using: :btree
create_table "ci_pipeline_schedules", force: :cascade do |t| create_table "ci_pipeline_schedules", force: :cascade do |t|
t.string "description" t.string "description"
...@@ -1195,7 +1199,6 @@ ActiveRecord::Schema.define(version: 20170726111039) do ...@@ -1195,7 +1199,6 @@ ActiveRecord::Schema.define(version: 20170726111039) do
t.integer "level", default: 0, null: false t.integer "level", default: 0, null: false
t.datetime "created_at", null: false t.datetime "created_at", null: false
t.datetime "updated_at", null: false t.datetime "updated_at", null: false
t.text "events"
t.boolean "new_note" t.boolean "new_note"
t.boolean "new_issue" t.boolean "new_issue"
t.boolean "reopen_issue" t.boolean "reopen_issue"
...@@ -1945,8 +1948,8 @@ ActiveRecord::Schema.define(version: 20170726111039) do ...@@ -1945,8 +1948,8 @@ ActiveRecord::Schema.define(version: 20170726111039) do
add_foreign_key "ci_builds", "ci_pipelines", column: "auto_canceled_by_id", name: "fk_a2141b1522", on_delete: :nullify add_foreign_key "ci_builds", "ci_pipelines", column: "auto_canceled_by_id", name: "fk_a2141b1522", on_delete: :nullify
add_foreign_key "ci_builds", "ci_stages", column: "stage_id", name: "fk_3a9eaa254d", on_delete: :cascade add_foreign_key "ci_builds", "ci_stages", column: "stage_id", name: "fk_3a9eaa254d", on_delete: :cascade
add_foreign_key "ci_builds", "projects", name: "fk_befce0568a", on_delete: :cascade add_foreign_key "ci_builds", "projects", name: "fk_befce0568a", on_delete: :cascade
add_foreign_key "ci_pipeline_schedule_variables", "ci_pipeline_schedules", column: "pipeline_schedule_id", name: "fk_41c35fda51", on_delete: :cascade
add_foreign_key "ci_group_variables", "namespaces", column: "group_id", name: "fk_33ae4d58d8", on_delete: :cascade add_foreign_key "ci_group_variables", "namespaces", column: "group_id", name: "fk_33ae4d58d8", on_delete: :cascade
add_foreign_key "ci_pipeline_schedule_variables", "ci_pipeline_schedules", column: "pipeline_schedule_id", name: "fk_41c35fda51", on_delete: :cascade
add_foreign_key "ci_pipeline_schedules", "projects", name: "fk_8ead60fcc4", on_delete: :cascade add_foreign_key "ci_pipeline_schedules", "projects", name: "fk_8ead60fcc4", on_delete: :cascade
add_foreign_key "ci_pipeline_schedules", "users", column: "owner_id", name: "fk_9ea99f58d2", on_delete: :nullify add_foreign_key "ci_pipeline_schedules", "users", column: "owner_id", name: "fk_9ea99f58d2", on_delete: :nullify
add_foreign_key "ci_pipeline_variables", "ci_pipelines", column: "pipeline_id", name: "fk_f29c5f4380", on_delete: :cascade add_foreign_key "ci_pipeline_variables", "ci_pipelines", column: "pipeline_id", name: "fk_f29c5f4380", on_delete: :cascade
......
...@@ -44,20 +44,29 @@ Shortcuts to GitLab's most visited docs: ...@@ -44,20 +44,29 @@ Shortcuts to GitLab's most visited docs:
### Projects and groups ### Projects and groups
- [Create a project](gitlab-basics/create-project.md) - [Projects](user/project/index.md):
- [Fork a project](gitlab-basics/fork-project.md) - [Create a project](gitlab-basics/create-project.md)
- [Importing and exporting projects between instances](user/project/settings/import_export.md). - [Fork a project](gitlab-basics/fork-project.md)
- [Project access](public_access/public_access.md): Setting up your project's visibility to public, internal, or private. - [Importing and exporting projects between instances](user/project/settings/import_export.md).
- [Project access](public_access/public_access.md): Setting up your project's visibility to public, internal, or private.
- [GitLab Pages](user/project/pages/index.md): Build, test, and deploy your static website with GitLab Pages.
- [Groups](user/group/index.md): Organize your projects in groups. - [Groups](user/group/index.md): Organize your projects in groups.
<<<<<<< HEAD
- [Subgroups](user/group/subgroups/index.md): nest groups in subgroups. - [Subgroups](user/group/subgroups/index.md): nest groups in subgroups.
=======
- [Subgroups](user/group/subgroups/index.md)
>>>>>>> ce/master
- [Search through GitLab](user/search/index.md): Search for issues, merge requests, projects, groups, todos, and issues in Issue Boards. - [Search through GitLab](user/search/index.md): Search for issues, merge requests, projects, groups, todos, and issues in Issue Boards.
- **(EES/EEP)** [Advanced Global Search](user/search/advanced_global_search.md): Leverage Elasticsearch for faster, more advanced code search across your entire GitLab instance. - **(EES/EEP)** [Advanced Global Search](user/search/advanced_global_search.md): Leverage Elasticsearch for faster, more advanced code search across your entire GitLab instance.
- **(EES/EEP)** [Advanced Syntax Search](user/search/advanced_search_syntax.md): Use advanced queries for more targeted search results. - **(EES/EEP)** [Advanced Syntax Search](user/search/advanced_search_syntax.md): Use advanced queries for more targeted search results.
- [Snippets](user/snippets.md): Snippets allow you to create little bits of code. - [Snippets](user/snippets.md): Snippets allow you to create little bits of code.
- [Wikis](user/project/wiki/index.md): Enhance your repository documentation with built-in wikis. - [Wikis](user/project/wiki/index.md): Enhance your repository documentation with built-in wikis.
<<<<<<< HEAD
- [GitLab Pages](user/project/pages/index.md): Build, test, and deploy your static website with GitLab Pages. - [GitLab Pages](user/project/pages/index.md): Build, test, and deploy your static website with GitLab Pages.
- **(EEP)** [GitLab Service Desk](user/project/service_desk.md): A simple way to allow people to create issues in your GitLab instance without needing their own user account. - **(EEP)** [GitLab Service Desk](user/project/service_desk.md): A simple way to allow people to create issues in your GitLab instance without needing their own user account.
- **(EES/EEP)** [Contribution Analytics](analytics/contribution_analytics.md): See detailed statistics of projects' contributors. - **(EES/EEP)** [Contribution Analytics](analytics/contribution_analytics.md): See detailed statistics of projects' contributors.
=======
>>>>>>> ce/master
### Repository ### Repository
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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