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
gem 'spring-commands-rspec', '~> 1.0.4'
gem 'spring-commands-spinach', '~> 1.1.0'
gem 'rubocop', '~> 0.47.1', require: false
gem 'rubocop-rspec', '~> 1.15.0', require: false
gem 'rubocop', '~> 0.49.1', require: false
gem 'rubocop-rspec', '~> 1.15.1', require: false
gem 'scss_lint', '~> 0.54.0', require: false
gem 'haml_lint', '~> 0.21.0', require: false
gem 'simplecov', '~> 0.14.0', require: false
......
......@@ -348,7 +348,7 @@ GEM
multi_json (~> 1.10)
retriable (~> 1.4)
signet (~> 0.6)
google-protobuf (3.2.0.2)
google-protobuf (3.3.0)
googleauth (0.5.1)
faraday (~> 0.9)
jwt (~> 1.4)
......@@ -574,6 +574,7 @@ GEM
rubypants (~> 0.2)
orm_adapter (0.5.0)
os (0.9.6)
parallel (1.11.2)
paranoia (2.3.1)
activerecord (>= 4.0, < 5.2)
parser (2.4.0.0)
......@@ -759,13 +760,14 @@ GEM
pg
rails
sqlite3
rubocop (0.47.1)
rubocop (0.49.1)
parallel (~> 1.10)
parser (>= 2.3.3.1, < 3.0)
powerpack (~> 0.1)
rainbow (>= 1.99.1, < 3.0)
ruby-progressbar (~> 1.7)
unicode-display_width (~> 1.0, >= 1.0.1)
rubocop-rspec (1.15.0)
rubocop-rspec (1.15.1)
rubocop (>= 0.42.0)
ruby-fogbugz (0.2.1)
crack (~> 0.4)
......@@ -897,7 +899,7 @@ GEM
unf (0.1.4)
unf_ext
unf_ext (0.0.7.2)
unicode-display_width (1.1.3)
unicode-display_width (1.3.0)
unicorn (5.1.0)
kgio (~> 2.6)
raindrops (~> 0.7)
......@@ -1115,8 +1117,8 @@ DEPENDENCIES
rspec-retry (~> 0.4.5)
rspec-set (~> 0.1.3)
rspec_profiling (~> 0.0.5)
rubocop (~> 0.47.1)
rubocop-rspec (~> 1.15.0)
rubocop (~> 0.49.1)
rubocop-rspec (~> 1.15.1)
ruby-fogbugz (~> 0.2.1)
ruby-prof (~> 0.16.2)
ruby_parser (~> 3.8)
......
......@@ -128,7 +128,7 @@ information, see
### 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.
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.
......@@ -158,6 +158,24 @@ release should have the correct milestone assigned _and_ have the label
Merge requests without a milestone and this label will
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
### Retrospective
......
......@@ -64,7 +64,7 @@ window.Build = (function () {
$(window)
.off('scroll')
.on('scroll', () => {
const contentHeight = this.$buildTraceOutput.prop('scrollHeight');
const contentHeight = this.$buildTraceOutput.height();
if (contentHeight > this.windowSize) {
// means the user did not scroll, the content was updated.
this.windowSize = contentHeight;
......@@ -105,16 +105,17 @@ window.Build = (function () {
};
Build.prototype.canScroll = function () {
return document.body.scrollHeight > window.innerHeight;
return $(document).height() > $(window).height();
};
Build.prototype.toggleScroll = function () {
const currentPosition = document.body.scrollTop;
const windowHeight = window.innerHeight;
const currentPosition = $(document).scrollTop();
const scrollHeight = $(document).height();
const windowHeight = $(window).height();
if (this.canScroll()) {
if (currentPosition > 0 &&
(document.body.scrollHeight - currentPosition !== windowHeight)) {
(scrollHeight - currentPosition !== windowHeight)) {
// User is in the middle of the log
this.toggleDisableButton(this.$scrollTopBtn, false);
......@@ -124,7 +125,7 @@ window.Build = (function () {
this.toggleDisableButton(this.$scrollTopBtn, true);
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.
this.toggleDisableButton(this.$scrollTopBtn, false);
......@@ -137,7 +138,7 @@ window.Build = (function () {
};
Build.prototype.scrollDown = function () {
document.body.scrollTop = document.body.scrollHeight;
$(document).scrollTop($(document).height());
};
Build.prototype.scrollToBottom = function () {
......@@ -147,7 +148,7 @@ window.Build = (function () {
};
Build.prototype.scrollToTop = function () {
document.body.scrollTop = 0;
$(document).scrollTop(0);
this.hasBeenScrolled = true;
this.toggleScroll();
};
......@@ -178,7 +179,7 @@ window.Build = (function () {
this.state = log.state;
}
this.windowSize = this.$buildTraceOutput.prop('scrollHeight');
this.windowSize = this.$buildTraceOutput.height();
if (log.append) {
this.$buildTraceOutput.append(log.html);
......
......@@ -9,7 +9,10 @@
/* global MilestoneSelect */
/* global Commit */
/* global CommitsList */
<<<<<<< HEAD
/* global NewCommitForm */
=======
>>>>>>> ce/master
/* global NewBranchForm */
/* global NotificationsForm */
/* global NotificationsDropdown */
......@@ -21,12 +24,17 @@
/* global Search */
/* global Admin */
/* global NamespaceSelects */
/* global NewCommitForm */
/* global NewBranchForm */
/* global Project */
/* global ProjectAvatar */
/* global MergeRequest */
/* global Compare */
/* global CompareAutocomplete */
<<<<<<< HEAD
/* global PathLocks */
=======
>>>>>>> ce/master
/* global ProjectFindFile */
/* global ProjectNew */
/* global ProjectShow */
......@@ -74,6 +82,9 @@ import initSettingsPanels from './settings_panels';
import initExperimentalFlags from './experimental_flags';
import OAuthRememberMe from './oauth_remember_me';
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 initNotes from './init_notes';
import initLegacyFilters from './init_legacy_filters';
......@@ -216,7 +227,6 @@ import AuditLogs from './audit_logs';
break;
case 'explore:groups:index':
new GroupsList();
const landingElement = document.querySelector('.js-explore-groups-landing');
if (!landingElement) break;
const exploreGroupsLanding = new Landing(
......@@ -310,6 +320,10 @@ import AuditLogs from './audit_logs';
new gl.Diff();
shortcut_handler = new ShortcutsIssuable(true);
new ZenMode();
initIssuableSidebar();
initNotes();
const mrShowNode = document.querySelector('.merge-request');
window.mergeRequest = new MergeRequest({
action: mrShowNode.dataset.mrAction,
......@@ -336,6 +350,7 @@ import AuditLogs from './audit_logs';
container: '.js-commit-pipeline-graph',
}).bindEvents();
$('.commit-info.branches').load(document.querySelector('.js-commit-box').dataset.commitPath);
<<<<<<< HEAD
break;
case 'projects:activity':
new gl.Activities();
......@@ -343,15 +358,26 @@ import AuditLogs from './audit_logs';
break;
case 'projects:commits:show':
CommitsList.init(document.querySelector('.js-project-commits-show').dataset.commitsLimit);
=======
break;
case 'projects:activity':
>>>>>>> ce/master
new gl.Activities();
shortcut_handler = new ShortcutsNavigation();
GpgBadges.fetch();
break;
<<<<<<< HEAD
case 'projects:edit':
new UsersSelect();
break;
case 'projects:imports:show':
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;
case 'projects:show':
shortcut_handler = new ShortcutsNavigation();
......@@ -366,6 +392,12 @@ import AuditLogs from './audit_logs';
case 'projects:edit':
setupProjectEdit();
break;
<<<<<<< HEAD
=======
case 'projects:imports:show':
new ProjectImport();
break;
>>>>>>> ce/master
case 'projects:pipelines:new':
new NewBranchForm($('.js-new-pipeline-form'));
break;
......@@ -423,6 +455,7 @@ import AuditLogs from './audit_logs';
new TreeView();
new BlobViewer();
new NewCommitForm($('.js-create-dir-form'));
<<<<<<< HEAD
if (document.querySelector('.js-tree-content').dataset.pathLocksAvailable === 'true') {
PathLocks.init(
......@@ -431,6 +464,8 @@ import AuditLogs from './audit_logs';
);
}
=======
>>>>>>> ce/master
$('#tree-slider').waitForImages(function() {
gl.utils.ajaxGet(document.querySelector('.js-tree-content').dataset.logsPath);
});
......
......@@ -50,6 +50,66 @@ class DropdownUtils {
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) {
const { input, allowedKeys } = config;
const updatedItem = item;
......
......@@ -745,10 +745,10 @@ GitLabDropdown = (function() {
GitLabDropdown.prototype.focusTextInput = function(triggerFocus = false) {
if (this.options.filterable) {
$(':focus').blur();
this.dropdown.one('transitionend', () => {
if (this.dropdown.is('.open')) {
this.filterInput.focus();
}
});
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>
import eventHub from '../event_hub';
import groupIdenticon from './group_identicon.vue';
export default {
components: {
groupIdenticon,
},
props: {
group: {
type: Object,
......@@ -92,6 +96,9 @@ export default {
hasGroups() {
return Object.keys(this.group.subGroups).length > 0;
},
hasAvatar() {
return this.group.avatarUrl && this.group.avatarUrl.indexOf('/assets/no_group_avatar') === -1;
},
},
};
</script>
......@@ -194,9 +201,15 @@ export default {
<a
:href="group.groupPath">
<img
v-if="hasAvatar"
class="avatar s40"
:src="group.avatarUrl"
/>
<group-identicon
v-else
:entity-id=group.id
:entity-name="group.name"
/>
</a>
</div>
<div
......
/* eslint-disable no-new */
/* global MilestoneSelect */
/* global LabelsSelect */
<<<<<<< HEAD
/* global WeightSelect */
=======
>>>>>>> ce/master
/* global IssuableContext */
/* global Sidebar */
......@@ -12,7 +15,10 @@ export default () => {
full_path: sidebarOptions.fullPath,
});
new LabelsSelect();
<<<<<<< HEAD
new WeightSelect();
=======
>>>>>>> ce/master
new IssuableContext(sidebarOptions.currentUser);
gl.Subscription.bindAll('.subscription');
new gl.DueDateSelectors();
......
......@@ -3,7 +3,10 @@
/* global MilestoneSelect */
/* global IssueStatusSelect */
/* global SubscriptionSelect */
<<<<<<< HEAD
/* global WeightSelect */
=======
>>>>>>> ce/master
import UsersSelect from './users_select';
......@@ -13,5 +16,8 @@ export default () => {
new MilestoneSelect();
new IssueStatusSelect();
new SubscriptionSelect();
<<<<<<< HEAD
new WeightSelect();
=======
>>>>>>> ce/master
};
......@@ -529,6 +529,7 @@ export default class Notes {
form.find('#note_line_code').remove();
form.find('#note_position').remove();
form.find('#note_type').val('');
form.find('#note_project_id').remove();
form.find('#in_reply_to_discussion_id').remove();
form.find('.js-comment-resolve-button').closest('comment-and-resolve-btn').remove();
this.parentTimeline = form.parents('.timeline');
......@@ -556,6 +557,7 @@ export default class Notes {
form.find('#note_noteable_id').val(),
form.find('#note_commit_id').val(),
form.find('#note_type').val(),
form.find('#note_project_id').val(),
form.find('#in_reply_to_discussion_id').val(),
// LegacyDiffNote
......@@ -848,6 +850,8 @@ export default class Notes {
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.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 */
import 'vendor/cropper';
import 'cropper';
((global) => {
// Matches everything but the file name
......
......@@ -26,11 +26,14 @@ import Cookies from 'js-cookie';
$projectCloneField.val(url);
$cloneBtnText.text($this.text());
<<<<<<< HEAD
$('#modal-geo-info').data({
cloneUrlSecondary: $this.attr('href'),
cloneUrlPrimary: $this.data('primaryUrl') || ''
});
=======
>>>>>>> ce/master
return $('.clone').text(url);
});
// Ref switcher
......
<<<<<<< HEAD
document.addEventListener('DOMContentLoaded', () => {
const importBtnTooltip = 'Please enter a valid project name.';
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) => {
e.preventDefault();
......@@ -13,6 +53,7 @@ document.addEventListener('DOMContentLoaded', () => {
$('.btn_import_gitlab_project').on('click', () => {
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()}`);
});
......@@ -26,6 +67,21 @@ document.addEventListener('DOMContentLoaded', () => {
$('#project_path').on('keyup', () => {
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);
$importBtnWrapper.attr('title', '');
$importBtnWrapper.removeClass('has-tooltip');
......@@ -35,9 +91,26 @@ document.addEventListener('DOMContentLoaded', () => {
}
});
<<<<<<< HEAD
$('#project_import_url').disable();
$('.import_git').on('click', () => {
const $projectImportUrl = $('#project_import_url');
$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 @@
overflow: hidden;
display: flex;
a {
display: flex;
}
.avatar {
border-radius: 0;
border: none;
......
......@@ -414,13 +414,16 @@
background-color: $dropdown-hover-color;
color: $white-light;
text-decoration: none;
outline: 0;
.avatar {
border-color: $white-light;
}
}
.filter-dropdown-item {
.droplab-dropdown .dropdown-menu .filter-dropdown-item {
padding: 0;
.btn {
border: none;
width: 100%;
......@@ -455,14 +458,11 @@
}
.dropdown-user {
display: -webkit-flex;
display: flex;
}
.dropdown-user-details {
display: -webkit-flex;
display: flex;
-webkit-flex-direction: column;
flex-direction: column;
> span {
......
......@@ -313,6 +313,29 @@ header {
.impersonation i {
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 {
......
......@@ -375,6 +375,10 @@ ul.indent-list {
background-color: $row-hover;
cursor: pointer;
}
.avatar-container > a {
width: 100%;
}
}
}
......
......@@ -185,3 +185,28 @@
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 @@
}
img.js-lazy-loaded {
min-width: none;
min-height: none;
background-color: none;
min-width: inherit;
min-height: inherit;
background-color: inherit;
}
p a:not(.no-attachment-icon) img {
......
......@@ -206,10 +206,13 @@ $general-hover-transition-duration: 100ms;
$general-hover-transition-curve: linear;
$highlight-changes-color: rgb(235, 255, 232);
$performance-bar-height: 35px;
<<<<<<< HEAD
$issue-box-upcoming-bg: #8f8f8f;
$pages-group-name-color: #4c4e54;
$ldap-members-override-bg: $orange-50;
=======
>>>>>>> ce/master
/*
......
......@@ -309,6 +309,25 @@ header.navbar-gitlab-new {
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 {
......@@ -325,6 +344,7 @@ header.navbar-gitlab-new {
.breadcrumbs-links {
flex: 1;
min-width: 0;
align-self: center;
color: $gl-text-color-quaternary;
......@@ -343,7 +363,7 @@ header.navbar-gitlab-new {
}
.title {
white-space: nowrap;
display: inline-block;
> a {
&:last-of-type:not(:first-child) {
......
......@@ -86,6 +86,7 @@
position: absolute;
right: 0;
left: 0;
top: 0;
}
.truncated-info {
......@@ -310,9 +311,7 @@
}
.dropdown-menu {
right: $gl-padding;
left: $gl-padding;
width: auto;
margin-top: -$gl-padding;
}
svg {
......
......@@ -110,6 +110,10 @@
.js-ca-dropdown {
top: $gl-padding-top;
.dropdown-menu-align-right {
margin-top: 2px;
}
}
.content-list {
......@@ -442,6 +446,24 @@
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 {
......
......@@ -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 {
......
......@@ -4,6 +4,7 @@ module NotesActions
included do
before_action :authorize_admin_note!, only: [:update, :destroy]
before_action :note_project, only: [:create]
end
def index
......@@ -28,7 +29,8 @@ module NotesActions
merge_request_diff_head_sha: params[:merge_request_diff_head_sha],
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)
Banzai::NoteRenderer.render([@note], @project, current_user)
......@@ -177,4 +179,22 @@ module NotesActions
def notes_finder
@notes_finder ||= NotesFinder.new(project, current_user, finder_params)
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
......@@ -66,7 +66,8 @@ module Projects
end
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
def move_params
......
......@@ -8,7 +8,7 @@ class Projects::BranchesController < Projects::ApplicationController
before_action :authorize_push_code!, only: [:new, :create, :destroy, :destroy_all_merged]
def index
@sort = params[:sort].presence || sort_value_name
@sort = params[:sort].presence || sort_value_recently_updated
@branches = BranchesFinder.new(@repository, params).execute
@branches = Kaminari.paginate_array(@branches).page(params[:page])
......
......@@ -15,7 +15,7 @@ module DiffHelper
def diff_view
@diff_view ||= begin
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.to_sym
end
......
......@@ -48,8 +48,12 @@ module GitlabRoutingHelper
end
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)
end
end
def issue_url(entity, *args)
project_issue_url(entity.project, entity, *args)
......@@ -63,6 +67,14 @@ module GitlabRoutingHelper
project_pipeline_url(pipeline.project, pipeline.id, *args)
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)
project_job_url(pipeline.project, build.id, *args)
end
......
......@@ -62,7 +62,11 @@ module NotesHelper
def link_to_reply_discussion(discussion, line_type = nil)
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',
data: data, title: 'Add a reply'
......
......@@ -34,6 +34,8 @@ module WebpackHelper
end
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
module ProtectedBranchAccess
extend ActiveSupport::Concern
ALLOWED_ACCESS_LEVELS ||= [
Gitlab::Access::MASTER,
Gitlab::Access::DEVELOPER,
Gitlab::Access::NO_ACCESS
].freeze
included do
include ProtectedRefAccess
include EE::ProtectedRefAccess
......@@ -10,11 +16,7 @@ module ProtectedBranchAccess
delegate :project, to: :protected_branch
validates :access_level, presence: true, inclusion: {
in: [
Gitlab::Access::MASTER,
Gitlab::Access::DEVELOPER,
Gitlab::Access::NO_ACCESS
]
in: ALLOWED_ACCESS_LEVELS
}
def self.human_access_levels
......
class NotificationSetting < ActiveRecord::Base
include IgnorableColumn
ignore_column :events
enum level: { global: 3, watch: 2, mention: 4, participating: 1, disabled: 0, custom: 5 }
default_value_for :level, NotificationSetting.levels[:global]
......@@ -41,9 +45,6 @@ class NotificationSetting < ActiveRecord::Base
:success_pipeline
].freeze
store :events, coder: JSON
before_save :convert_events
def self.find_or_create_for(source)
setting = find_or_initialize_by(source: source)
......@@ -54,42 +55,17 @@ class NotificationSetting < ActiveRecord::Base
setting
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
# custom notifications enabled, as these are more like mentions than the other
# custom settings.
def failed_pipeline
bool = super
bool = events[:failed_pipeline] if bool.nil?
bool.nil? || bool
end
alias_method :failed_pipeline?, :failed_pipeline
def event_enabled?(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)
respond_to?(event) && !!public_send(event)
end
end
......@@ -18,9 +18,12 @@ class Project < ActiveRecord::Base
include SelectForProjectAuthorization
include Routable
include Storage::LegacyProject
<<<<<<< HEAD
# EE specific modules
prepend EE::Project
=======
>>>>>>> ce/master
extend Gitlab::ConfigHelper
......@@ -1206,7 +1209,18 @@ class Project < ActiveRecord::Base
end
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
# TODO: what to do here when not using Legacy Storage? Do we still need to rename and delay removal?
......
class ProjectWiki
include Gitlab::ShellAdapter
<<<<<<< HEAD
include Elastic::WikiRepositoriesSearch
include Gitlab::CurrentSettings
=======
>>>>>>> ce/master
include Storage::LegacyProjectWiki
MARKUPS = {
......@@ -50,11 +53,14 @@ class ProjectWiki
def http_url_to_repo
"#{Gitlab.config.gitlab.url}/#{full_path}.git"
<<<<<<< HEAD
end
# No need to have a Kerberos Web url. Kerberos URL will be used only to clone
def kerberos_url_to_repo
[Gitlab.config.build_gitlab_kerberos_url, '/', full_path, '.git'].join('')
=======
>>>>>>> ce/master
end
def wiki_base_path
......
......@@ -1018,7 +1018,7 @@ class Repository
if is_enabled
raw_repository.is_ancestor?(ancestor_id, descendant_id)
else
merge_base_commit(ancestor_id, descendant_id) == ancestor_id
rugged_is_ancestor?(ancestor_id, descendant_id)
end
end
end
......
......@@ -44,7 +44,7 @@ class GlobalPolicy < BasePolicy
prevent :log_in
end
rule { admin | ~restricted_public_level }.policy do
rule { ~(anonymous & restricted_public_level) }.policy do
enable :read_users_list
end
end
......@@ -3,8 +3,11 @@ module Ci
def execute
if trigger_from_token
create_pipeline_from_trigger(trigger_from_token)
<<<<<<< HEAD
elsif job_from_token
create_pipeline_from_job(job_from_token)
=======
>>>>>>> ce/master
end
end
......@@ -27,6 +30,7 @@ module Ci
end
end
<<<<<<< HEAD
def create_pipeline_from_job(job)
# this check is to not leak the presence of the project if user cannot read it
return unless can?(job.user, :read_project, project)
......@@ -51,18 +55,23 @@ module Ci
end
end
=======
>>>>>>> ce/master
def trigger_from_token
return @trigger if defined?(@trigger)
@trigger = Ci::Trigger.find_by_token(params[:token].to_s)
end
<<<<<<< HEAD
def job_from_token
return @job if defined?(@job)
@job = Ci::Build.find_by_token(params[:token].to_s)
end
=======
>>>>>>> ce/master
def create_pipeline_variables!(pipeline)
return unless params[:variables]
......
......@@ -11,7 +11,7 @@ class DeleteMergedBranchesService < BaseService
# Prevent deletion of branches relevant to open merge requests
branches -= merge_request_branch_names
# Prevent deletion of protected branches
branches -= project.protected_branches.pluck(:name)
branches = branches.reject { |branch| project.protected_for?(branch) }
branches.each do |branch|
DeleteBranchService.new(project, current_user).execute(branch)
......
......@@ -45,6 +45,7 @@ class GitPushService < BaseService
elsif push_to_existing_branch?
# Collect data for this git push
@push_commits = @project.repository.commits_between(params[:oldrev], params[:newrev])
process_commit_messages
# Update the bare repositories info/attributes file using the contents of the default branches
......@@ -71,15 +72,21 @@ class GitPushService < BaseService
def update_caches
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
@push_commits.each do |commit|
@push_commits.last(PROCESS_COMMIT_LIMIT).each do |commit|
commit.raw_deltas.each do |diff|
paths << diff.new_path
end
end
types = Gitlab::FileDetector.types_in_paths(paths.to_a)
end
else
types = []
end
......@@ -97,7 +104,7 @@ class GitPushService < BaseService
def process_commit_messages
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?
ProcessCommitWorker
.perform_async(project.id, current_user.id, commit.to_hash, default)
......@@ -124,8 +131,13 @@ class GitPushService < BaseService
mirror_update = @project.mirror? && @project.repository.up_to_date_with_upstream?(branch_name)
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)
>>>>>>> ce/master
SystemHookPushWorker.perform_async(build_push_data.dup, :push_hooks)
@project.execute_hooks(build_push_data.dup, :push_hooks)
@project.execute_services(build_push_data.dup, :push_hooks)
......@@ -145,7 +157,10 @@ class GitPushService < BaseService
end
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
project.change_head(branch_name)
......@@ -174,7 +189,8 @@ class GitPushService < BaseService
params[:oldrev],
params[:newrev],
params[:ref],
push_commits)
@push_commits,
commits_count: @push_commits_count)
end
def push_to_existing_branch?
......
module MergeRequests
class BaseService < ::IssuableBaseService
<<<<<<< HEAD
prepend EE::MergeRequests::BaseService
=======
>>>>>>> ce/master
def create_note(merge_request, state = merge_request.state)
SystemNoteService.change_status(merge_request, merge_request.target_project, current_user, state, nil)
end
......
......@@ -5,6 +5,9 @@ module QuickActions
attr_reader :issuable
SHRUG = '¯\\_(ツ)_/¯'.freeze
TABLEFLIP = '(╯°□°)╯︵ ┻━┻'.freeze
# 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.
def execute(content, issuable)
......@@ -15,6 +18,7 @@ module QuickActions
content, commands = extractor.extract_commands(content, context)
extract_updates(commands, context)
[content, @updates]
end
......@@ -424,6 +428,18 @@ module QuickActions
@updates[:spend_time] = { duration: :reset, user: current_user }
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
desc 'CC'
params '@user'
......
......@@ -44,7 +44,7 @@ class WebHookService
http_status: response.code,
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(
trigger: hook_name,
url: hook.url,
......@@ -101,7 +101,7 @@ class WebHookService
request_headers: build_headers(hook_name),
request_data: request_data,
response_headers: format_response_headers(response),
response_body: response.body,
response_body: safe_response_body(response),
response_status: response.code,
internal_error_message: error_message
)
......@@ -124,4 +124,10 @@ class WebHookService
def format_response_headers(response)
response.headers.each_capitalized.to_h
end
def safe_response_body(response)
return '' unless response.body
response.body.encode('UTF-8', invalid: :replace, undef: :replace, replace: '')
end
end
......@@ -356,7 +356,7 @@
\. This setting requires a
= link_to 'restart', help_page_path('administration/restart_gitlab')
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
.col-sm-offset-2.col-sm-10
.checkbox
......
......@@ -7,7 +7,10 @@
- content_for :page_specific_javascripts do
= webpack_bundle_tag 'common_vue'
= webpack_bundle_tag 'filtered_search'
<<<<<<< HEAD
= webpack_bundle_tag 'issues'
=======
>>>>>>> ce/master
- if show_new_nav? && group_issues_exists
- content_for :breadcrumbs_extra do
......
- @breadcrumb_title = "Help"
- page_title "Help"
- header_title "Help", help_path
......
......@@ -109,6 +109,7 @@
%span.nav-item-name
Abuse Reports
%span.badge.count= number_with_delimiter(AbuseReport.count(:all))
<<<<<<< HEAD
= nav_link(controller: :licenses) do
= link_to admin_license_path, title: 'License' do
......@@ -116,6 +117,8 @@
= custom_icon('license')
%span
License
=======
>>>>>>> ce/master
- if akismet_enabled?
= nav_link(controller: :spam_logs) do
......
......@@ -67,7 +67,9 @@
SSH Keys
= nav_link(controller: :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
= nav_link(controller: :preferences) do
= link_to profile_preferences_path, title: 'Preferences' do
......
......@@ -95,6 +95,7 @@
= link_to project_issues_path(@project), title: 'Issues' do
%span
List
<<<<<<< HEAD
= nav_link(controller: :boards) do
= link_to project_boards_path(@project), title: 'Boards' do
......@@ -104,6 +105,8 @@
= link_to project_issues_path(@project), title: 'Issues' do
%span
List
=======
>>>>>>> ce/master
= nav_link(controller: :boards) do
= link_to project_boards_path(@project), title: 'Board' do
......
......@@ -30,14 +30,21 @@
= link_to _("Create merge request"), create_mr_path(@repository.root_ref, @ref), class: 'btn btn-success'
.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', 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 }
.control
= link_to project_commits_path(@project, @ref, rss_url_options), title: _("Commits feed"), class: 'btn' do
= icon("rss")
<<<<<<< HEAD
= render 'projects/commits/mirror_status'
=======
>>>>>>> ce/master
%div{ id: dom_id(@project) }
%ol#commits-list.list-unstyled.content_list
= 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 }
>>>>>>> ce/master
.table-holder
%table.table#tree-slider{ class: "table_#{@hex_path} tree-table" }
%thead
......
......@@ -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' }
.input-group-btn
= 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?
= 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 @@
= link_to 'Edit', '#', class: 'edit-link pull-right'
.value.hide-collapsed
- 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
%span.no-value None
......
......@@ -10,6 +10,7 @@
= hidden_field_tag :line_type
= 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 :note_project_id
= note_target_fields(@note)
= f.hidden_field :noteable_type
......
......@@ -14,7 +14,7 @@
- if avatar
.avatar-container.s40
= 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:''
- else
= project_icon(project, alt: '', class: 'avatar project-avatar s40')
......
......@@ -31,8 +31,6 @@ class EmailReceiverWorker
when Gitlab::Email::EmptyEmailError
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."
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
"We couldn't figure out what user corresponds to the email. Please create your comment through the web interface."
when Gitlab::Email::UserBlockedError
......
......@@ -5,6 +5,12 @@ class GitGarbageCollectWorker
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)
project = Project.find(project_id)
task = task.to_sym
......@@ -15,8 +21,14 @@ class GitGarbageCollectWorker
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)
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
flush_ref_caches(project) if task == :gc
......@@ -26,6 +38,19 @@ class GitGarbageCollectWorker
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)
case task
when :gc
......@@ -55,4 +80,14 @@ class GitGarbageCollectWorker
config_value = write_bitmaps ? 'true' : 'false'
%W[git -c repack.writeBitmaps=#{config_value}]
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
---
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:
author:
---
title: Ensure filesystem metrics test files are deleted
title: Fixed breadcrumbs title aggressively collapsing
merge_request:
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
#
# Example: '/etc/ca.pem'
#
ca_cert: ''
ca_file: ''
# Specifies the SSL version for OpenSSL to use, if the OpenSSL default
# is not appropriate.
......
......@@ -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['ssh_host'] ||= Settings.gitlab.host
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['protocol'] ||= Settings.gitlab.https ? "https" : "http"
Settings.gitlab['email_enabled'] ||= true if Settings.gitlab['email_enabled'].nil?
......
......@@ -62,8 +62,8 @@ class ProjectForeignKeysWithCascadingDeletes < ActiveRecord::Migration
# These columns are not indexed yet, meaning a cascading delete would take
# forever.
add_concurrent_index(:project_group_links, :project_id)
add_concurrent_index(:pages_domains, :project_id)
add_index_if_not_exists(:project_group_links, :project_id)
add_index_if_not_exists(:pages_domains, :project_id)
end
def down
......@@ -71,15 +71,15 @@ class ProjectForeignKeysWithCascadingDeletes < ActiveRecord::Migration
remove_foreign_key_without_error(source, column)
end
add_concurrent_foreign_key(:boards, :projects, column: :project_id)
add_concurrent_foreign_key(:lists, :labels, column: :label_id)
add_concurrent_foreign_key(:lists, :boards, column: :board_id)
add_foreign_key_if_not_exists(:boards, :projects, column: :project_id)
add_foreign_key_if_not_exists(:lists, :labels, column: :label_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,
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,
column: :protected_branch_id)
......@@ -89,7 +89,7 @@ class ProjectForeignKeysWithCascadingDeletes < ActiveRecord::Migration
def add_foreign_keys
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
......@@ -153,6 +153,18 @@ class ProjectForeignKeysWithCascadingDeletes < ActiveRecord::Migration
EOF
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)
remove_foreign_key(table, column: column)
rescue ArgumentError
......@@ -163,6 +175,12 @@ class ProjectForeignKeysWithCascadingDeletes < ActiveRecord::Migration
rescue ArgumentError
end
def foreign_key_exists?(table, column)
foreign_keys(table).any? do |key|
key.options[:column] == column.to_s
end
end
def connection
# Rails memoizes connection objects, but this causes them to be shared
# 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 @@
#
# 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: 20170728101014) do
>>>>>>> ce/master
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
......@@ -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", ["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.text "value"
t.text "encrypted_value"
t.string "encrypted_value_salt"
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 "updated_at", null: false
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.text "value"
t.text "encrypted_value"
t.string "encrypted_value_salt"
t.string "encrypted_value_iv"
t.integer "group_id", null: false
t.boolean "protected", default: false, null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "pipeline_schedule_id", null: false
t.datetime "created_at"
t.datetime "updated_at"
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|
t.string "description"
......@@ -1195,7 +1199,6 @@ ActiveRecord::Schema.define(version: 20170726111039) do
t.integer "level", default: 0, null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.text "events"
t.boolean "new_note"
t.boolean "new_issue"
t.boolean "reopen_issue"
......@@ -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_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_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_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", "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
......
......@@ -44,20 +44,29 @@ Shortcuts to GitLab's most visited docs:
### Projects and groups
- [Create a project](gitlab-basics/create-project.md)
- [Fork a project](gitlab-basics/fork-project.md)
- [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.
- [Projects](user/project/index.md):
- [Create a project](gitlab-basics/create-project.md)
- [Fork a project](gitlab-basics/fork-project.md)
- [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.
<<<<<<< HEAD
- [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.
- **(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.
- [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.
<<<<<<< HEAD
- [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.
- **(EES/EEP)** [Contribution Analytics](analytics/contribution_analytics.md): See detailed statistics of projects' contributors.
=======
>>>>>>> ce/master
### 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