Commit 490ae8a6 authored by Lin Jen-Shin's avatar Lin Jen-Shin

Merge remote-tracking branch 'ee/master' into ce-to-ee-2017-07-28

* ee/master:
  And end
  Squashed commit of the following:
  Trailing Spaces removed
  Moves the Performance Bar to the top instead of being at the bottom
  Fix remote mirror last_update_at nil error in view
  Adds restrict group owners to admins option to admin application settings dashboard
  Working File Locks
  Update CHANGELOG.md for 9.4.2
  Update CHANGELOG-EE.md for 9.4.2-ee
  Converting it to true string if :file_locks available
  Merge issuable "reopened" state into "opened"
  Remove :remove_default_access_levels and use
  Replace autodeploy guide image to use blank namespace
  Latest Changes from CE applied
  Removed Path Locks from _tree_content.html.haml
  removed similar code
  fixed form submitting
  EE port of ph-inline-js
  Applied Patch of inline-js-removal-projects-other from CE Also removed Additional EE Inline Script on _tree_content.html.haml
parents 2b84e500 d8aec0b7
Please view this file on the master branch, on stable branches it's out of date. Please view this file on the master branch, on stable branches it's out of date.
## 9.4.2 (2017-07-28)
- Adds lower bound to pull mirror scheduling feature. !2366
- Add warning and option toggle when rebuilding authorized_keys. !2508
- Fix CSS for mini graph with downstream pipeline.
- Renamed board to boards in new project sidebar.
- Fix Rebasing not working with Merge Requests.
- Fixed issue boards focus mode when new navigation is turned on.
## 9.4.1 (2017-07-25) ## 9.4.1 (2017-07-25)
- Cleans up mirror capacity in project destroy service if project is a scheduled mirror. !2445 - Cleans up mirror capacity in project destroy service if project is a scheduled mirror. !2445
......
...@@ -2,6 +2,21 @@ ...@@ -2,6 +2,21 @@
documentation](doc/development/changelog.md) for instructions on adding your own documentation](doc/development/changelog.md) for instructions on adding your own
entry. entry.
## 9.4.2 (2017-07-28)
- Fix job merge request link to a forked source project. !12965
- Improve redirect route query performance. !13062
- Allow admin to read_users_list even if it's restricted. !13066
- Fixes 500 error caused by pending delete projects in admin dashboard. !13067
- Add instrumentation to MarkupHelper#link_to_gfm. !13069
- Pending delete projects should not show in deploy keys. !13088
- Fix sizing of custom header logo in new navigation.
- Fix crash on /help/ui.
- Fix creating merge request diffs when diff contains bytes that are invalid in UTF-8.
- fix vertical alignment of New Project button.
- Add LDAP SSL certificate verification option.
- Fix vertical alignment in firefox and safari for pipeline mini graph.
## 9.4.1 (2017-07-25) ## 9.4.1 (2017-07-25)
- Fix pipeline_schedules pages throwing error 500 (when ref is empty). !12983 - Fix pipeline_schedules pages throwing error 500 (when ref is empty). !12983
......
...@@ -24,11 +24,6 @@ class AuditLogs { ...@@ -24,11 +24,6 @@ class AuditLogs {
$('.project-item-select').on('click', () => { $('.project-item-select').on('click', () => {
$('form.filter-form').submit(); $('form.filter-form').submit();
}); });
$('form.filter-form').on('submit', function applyFilters(event) {
event.preventDefault();
gl.utils.visitUrl(`${this.action}?${$(this).serialize()}`);
});
} }
initFilterDropdown($dropdown, fieldName, searchFields, cb) { initFilterDropdown($dropdown, fieldName, searchFields, cb) {
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
/* global LabelsSelect */ /* global LabelsSelect */
/* global MilestoneSelect */ /* global MilestoneSelect */
/* global Commit */ /* global Commit */
/* global NewBranchForm */
/* global NotificationsForm */ /* global NotificationsForm */
/* global NotificationsDropdown */ /* global NotificationsDropdown */
/* global GroupAvatar */ /* global GroupAvatar */
...@@ -23,6 +24,7 @@ ...@@ -23,6 +24,7 @@
/* global MergeRequest */ /* global MergeRequest */
/* global Compare */ /* global Compare */
/* global CompareAutocomplete */ /* global CompareAutocomplete */
/* global PathLocks */
/* global ProjectNew */ /* global ProjectNew */
/* global ProjectShow */ /* global ProjectShow */
/* global Labels */ /* global Labels */
...@@ -68,6 +70,9 @@ import initExperimentalFlags from './experimental_flags'; ...@@ -68,6 +70,9 @@ 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 GpgBadges from './gpg_badges'; import GpgBadges from './gpg_badges';
import initNotes from './init_notes';
import initLegacyFilters from './init_legacy_filters';
import initIssuableSidebar from './init_issuable_sidebar';
// EE-only // EE-only
import ApproversSelect from './approvers_select'; import ApproversSelect from './approvers_select';
...@@ -166,6 +171,8 @@ import AuditLogs from './audit_logs'; ...@@ -166,6 +171,8 @@ import AuditLogs from './audit_logs';
new Issue(); new Issue();
shortcut_handler = new ShortcutsIssuable(); shortcut_handler = new ShortcutsIssuable();
new ZenMode(); new ZenMode();
initIssuableSidebar();
initNotes();
break; break;
case 'dashboard:milestones:index': case 'dashboard:milestones:index':
new ProjectSelect(); new ProjectSelect();
...@@ -176,10 +183,12 @@ import AuditLogs from './audit_logs'; ...@@ -176,10 +183,12 @@ import AuditLogs from './audit_logs';
new Milestone(); new Milestone();
new Sidebar(); new Sidebar();
break; break;
case 'dashboard:issues':
case 'dashboard:merge_requests':
case 'groups:issues': case 'groups:issues':
case 'groups:merge_requests': case 'groups:merge_requests':
new UsersSelect();
new ProjectSelect(); new ProjectSelect();
initLegacyFilters();
break; break;
case 'dashboard:todos:index': case 'dashboard:todos:index':
new Todos(); new Todos();
...@@ -259,7 +268,10 @@ import AuditLogs from './audit_logs'; ...@@ -259,7 +268,10 @@ import AuditLogs from './audit_logs';
case 'projects:tags:new': case 'projects:tags:new':
new ZenMode(); new ZenMode();
new gl.GLForm($('.tag-form'), true); new gl.GLForm($('.tag-form'), true);
new RefSelectDropdown($('.js-branch-select'), window.gl.availableRefs); new RefSelectDropdown($('.js-branch-select'));
break;
case 'projects:snippets:show':
initNotes();
break; break;
case 'projects:snippets:new': case 'projects:snippets:new':
case 'projects:snippets:edit': case 'projects:snippets:edit':
...@@ -285,15 +297,12 @@ import AuditLogs from './audit_logs'; ...@@ -285,15 +297,12 @@ import AuditLogs from './audit_logs';
window.mergeRequest = new MergeRequest({ window.mergeRequest = new MergeRequest({
action: mrShowNode.dataset.mrAction, action: mrShowNode.dataset.mrAction,
}); });
initIssuableSidebar();
initNotes();
break; break;
case 'dashboard:activity': case 'dashboard:activity':
new gl.Activities(); new gl.Activities();
break; break;
case 'dashboard:issues':
case 'dashboard:merge_requests':
new ProjectSelect();
new UsersSelect();
break;
case 'projects:commit:show': case 'projects:commit:show':
new Commit(); new Commit();
new gl.Diff(); new gl.Diff();
...@@ -302,6 +311,7 @@ import AuditLogs from './audit_logs'; ...@@ -302,6 +311,7 @@ import AuditLogs from './audit_logs';
new MiniPipelineGraph({ new MiniPipelineGraph({
container: '.js-commit-pipeline-graph', container: '.js-commit-pipeline-graph',
}).bindEvents(); }).bindEvents();
initNotes();
break; break;
case 'projects:commit:pipelines': case 'projects:commit:pipelines':
new MiniPipelineGraph({ new MiniPipelineGraph({
...@@ -331,6 +341,9 @@ import AuditLogs from './audit_logs'; ...@@ -331,6 +341,9 @@ import AuditLogs from './audit_logs';
case 'projects:edit': case 'projects:edit':
setupProjectEdit(); setupProjectEdit();
break; break;
case 'projects:pipelines:new':
new NewBranchForm($('.js-new-pipeline-form'));
break;
case 'projects:pipelines:builds': case 'projects:pipelines:builds':
case 'projects:pipelines:failures': case 'projects:pipelines:failures':
case 'projects:pipelines:show': case 'projects:pipelines:show':
...@@ -384,6 +397,17 @@ import AuditLogs from './audit_logs'; ...@@ -384,6 +397,17 @@ import AuditLogs from './audit_logs';
shortcut_handler = new ShortcutsNavigation(); shortcut_handler = new ShortcutsNavigation();
new TreeView(); new TreeView();
new BlobViewer(); new BlobViewer();
if (document.querySelector('.js-tree-content').dataset.pathLocksAvailable === 'true') {
PathLocks.init(
document.querySelector('.js-tree-content').dataset.pathLocksToggle,
document.querySelector('.js-tree-content').dataset.pathLocksPath,
);
}
$('#tree-slider').waitForImages(function() {
gl.utils.ajaxGet(document.querySelector('.js-tree-content').dataset.logsPath);
});
break; break;
case 'projects:find_file:show': case 'projects:find_file:show':
shortcut_handler = true; shortcut_handler = true;
...@@ -401,10 +425,20 @@ import AuditLogs from './audit_logs'; ...@@ -401,10 +425,20 @@ import AuditLogs from './audit_logs';
case 'projects:labels:edit': case 'projects:labels:edit':
new Labels(); new Labels();
break; break;
case 'groups:labels:index':
case 'projects:labels:index': case 'projects:labels:index':
if ($('.prioritized-labels').length) { if ($('.prioritized-labels').length) {
new gl.LabelManager(); new gl.LabelManager();
} }
$('.label-subscription').each((i, el) => {
const $el = $(el);
if ($el.find('.dropdown-group-label').length) {
new gl.GroupLabelSubscription($el);
} else {
new gl.ProjectLabelSubscription($el);
}
});
break; break;
case 'projects:network:show': case 'projects:network:show':
// Ensure we don't create a particular shortcut handler here. This is // Ensure we don't create a particular shortcut handler here. This is
...@@ -460,10 +494,15 @@ import AuditLogs from './audit_logs'; ...@@ -460,10 +494,15 @@ import AuditLogs from './audit_logs';
case 'snippets:show': case 'snippets:show':
new LineHighlighter(); new LineHighlighter();
new BlobViewer(); new BlobViewer();
initNotes();
break; break;
case 'import:fogbugz:new_user_map': case 'import:fogbugz:new_user_map':
new UsersSelect(); new UsersSelect();
break; break;
case 'profiles:personal_access_tokens:index':
case 'admin:impersonation_tokens:index':
new gl.DueDateSelectors();
break;
} }
switch (path.first()) { switch (path.first()) {
case 'sessions': case 'sessions':
...@@ -541,6 +580,7 @@ import AuditLogs from './audit_logs'; ...@@ -541,6 +580,7 @@ import AuditLogs from './audit_logs';
shortcut_handler = new ShortcutsWiki(); shortcut_handler = new ShortcutsWiki();
new ZenMode(); new ZenMode();
new gl.GLForm($('.wiki-form'), true); new gl.GLForm($('.wiki-form'), true);
new Sidebar();
break; break;
case 'snippets': case 'snippets':
shortcut_handler = new ShortcutsNavigation(); shortcut_handler = new ShortcutsNavigation();
......
/* eslint-disable no-new */
/* global MilestoneSelect */
/* global LabelsSelect */
/* global WeightSelect */
/* global IssuableContext */
/* global Sidebar */
export default () => {
const sidebarOptions = JSON.parse(document.querySelector('.js-sidebar-options').innerHTML);
new MilestoneSelect({
full_path: sidebarOptions.fullPath,
});
new LabelsSelect();
new WeightSelect();
new IssuableContext(sidebarOptions.currentUser);
gl.Subscription.bindAll('.subscription');
new gl.DueDateSelectors();
window.sidebar = new Sidebar();
};
/* eslint-disable no-new */
/* global LabelsSelect */
/* global MilestoneSelect */
/* global IssueStatusSelect */
/* global SubscriptionSelect */
/* global WeightSelect */
import UsersSelect from './users_select';
export default () => {
new UsersSelect();
new LabelsSelect();
new MilestoneSelect();
new IssueStatusSelect();
new SubscriptionSelect();
new WeightSelect();
};
/* global Notes */
export default () => {
const dataEl = document.querySelector('.js-notes-data');
const {
notesUrl,
notesIds,
now,
diffView,
autocomplete,
} = JSON.parse(dataEl.innerHTML);
window.notes = new Notes(notesUrl, notesIds, now, diffView, autocomplete);
};
...@@ -53,7 +53,7 @@ export default { ...@@ -53,7 +53,7 @@ export default {
return this.state && this.state.length > 0; return this.state && this.state.length > 0;
}, },
isOpen() { isOpen() {
return this.state === 'opened' || this.state === 'reopened'; return this.state === 'opened';
}, },
isClosed() { isClosed() {
return this.state === 'closed'; return this.state === 'closed';
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
import UsersSelect from './users_select'; import UsersSelect from './users_select';
const PARTICIPANTS_ROW_COUNT = 7;
(function() { (function() {
this.IssuableContext = (function() { this.IssuableContext = (function() {
function IssuableContext(currentUser) { function IssuableContext(currentUser) {
...@@ -50,11 +52,9 @@ import UsersSelect from './users_select'; ...@@ -50,11 +52,9 @@ import UsersSelect from './users_select';
} }
IssuableContext.prototype.initParticipants = function() { IssuableContext.prototype.initParticipants = function() {
var _this;
_this = this;
$(document).on("click", ".js-participants-more", this.toggleHiddenParticipants); $(document).on("click", ".js-participants-more", this.toggleHiddenParticipants);
return $(".js-participants-author").each(function(i) { return $(".js-participants-author").each(function(i) {
if (i >= _this.PARTICIPANTS_ROW_COUNT) { if (i >= PARTICIPANTS_ROW_COUNT) {
return $(this).addClass("js-participants-hidden").hide(); return $(this).addClass("js-participants-hidden").hide();
} }
}); });
......
...@@ -145,7 +145,6 @@ import './right_sidebar'; ...@@ -145,7 +145,6 @@ import './right_sidebar';
import './search'; import './search';
import './search_autocomplete'; import './search_autocomplete';
import './smart_interval'; import './smart_interval';
import './snippets_list';
import './star'; import './star';
import './subscription'; import './subscription';
import './subscription_select'; import './subscription_select';
...@@ -365,4 +364,14 @@ $(function () { ...@@ -365,4 +364,14 @@ $(function () {
gl.utils.renderTimeago(); gl.utils.renderTimeago();
$(document).trigger('init.scrolling-tabs'); $(document).trigger('init.scrolling-tabs');
$('form.filter-form').on('submit', function (event) {
const link = document.createElement('a');
link.href = this.action;
const action = `${this.action}${link.search === '' ? '?' : '&'}`;
event.preventDefault();
gl.utils.visitUrl(`${action}${$(this).serialize()}`);
});
}); });
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
/* global Flash */ /* global Flash */
import Vue from 'vue'; import Vue from 'vue';
import initIssuableSidebar from '../init_issuable_sidebar';
import './merge_conflict_store'; import './merge_conflict_store';
import './merge_conflict_service'; import './merge_conflict_service';
import './mixins/line_conflict_utils'; import './mixins/line_conflict_utils';
...@@ -19,6 +20,8 @@ $(() => { ...@@ -19,6 +20,8 @@ $(() => {
resolveConflictsPath: conflictsEl.dataset.resolveConflictsPath resolveConflictsPath: conflictsEl.dataset.resolveConflictsPath
}); });
initIssuableSidebar();
gl.MergeConflictsResolverApp = new Vue({ gl.MergeConflictsResolverApp = new Vue({
el: '#conflicts', el: '#conflicts',
data: mergeConflictsStore.state, data: mergeConflictsStore.state,
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
var _this, $els; var _this, $els;
if (currentProject != null) { if (currentProject != null) {
_this = this; _this = this;
this.currentProject = JSON.parse(currentProject); this.currentProject = typeof currentProject === 'string' ? JSON.parse(currentProject) : currentProject;
} }
$els = $(els); $els = $(els);
......
import Chart from 'vendor/Chart';
document.addEventListener('DOMContentLoaded', () => {
const chartData = JSON.parse(document.getElementById('pipelinesChartsData').innerHTML);
const buildChart = (chartScope) => {
const data = {
labels: chartScope.labels,
datasets: [{
fillColor: '#7f8fa4',
strokeColor: '#7f8fa4',
pointColor: '#7f8fa4',
pointStrokeColor: '#EEE',
data: chartScope.totalValues,
},
{
fillColor: '#44aa22',
strokeColor: '#44aa22',
pointColor: '#44aa22',
pointStrokeColor: '#fff',
data: chartScope.successValues,
},
],
};
const ctx = $(`#${chartScope.scope}Chart`).get(0).getContext('2d');
const options = {
scaleOverlay: true,
responsive: true,
maintainAspectRatio: false,
};
if (window.innerWidth < 768) {
// Scale fonts if window width lower than 768px (iPad portrait)
options.scaleFontSize = 8;
}
new Chart(ctx).Line(data, options);
};
chartData.forEach(scope => buildChart(scope));
});
import Chart from 'vendor/Chart';
document.addEventListener('DOMContentLoaded', () => {
const chartData = JSON.parse(document.getElementById('pipelinesTimesChartsData').innerHTML);
const data = {
labels: chartData.labels,
datasets: [{
fillColor: 'rgba(220,220,220,0.5)',
strokeColor: 'rgba(220,220,220,1)',
barStrokeWidth: 1,
barValueSpacing: 1,
barDatasetSpacing: 1,
data: chartData.values,
}],
};
const ctx = $('#build_timesChart').get(0).getContext('2d');
const options = {
scaleOverlay: true,
responsive: true,
maintainAspectRatio: false,
};
if (window.innerWidth < 768) {
// Scale fonts if window width lower than 768px (iPad portrait)
options.scaleFontSize = 8;
}
new Chart(ctx).Bar(data, options);
});
...@@ -6,21 +6,27 @@ import Cookies from 'js-cookie'; ...@@ -6,21 +6,27 @@ import Cookies from 'js-cookie';
(function() { (function() {
this.Project = (function() { this.Project = (function() {
function Project() { function Project() {
$('ul.clone-options-dropdown a').click(function() { const $cloneOptions = $('ul.clone-options-dropdown');
var url; const $projectCloneField = $('#project_clone');
if ($(this).hasClass('active')) { const $cloneBtnText = $('a.clone-dropdown-btn span');
return;
} $('a', $cloneOptions).on('click', (e) => {
$('.active').not($(this)).removeClass('active'); const $this = $(e.currentTarget);
$(this).toggleClass('active'); const url = $this.attr('href');
url = $("#project_clone").val();
$('#project_clone').val(url); e.preventDefault();
$('.active', $cloneOptions).not($this).removeClass('active');
$this.toggleClass('active');
$projectCloneField.val(url);
$cloneBtnText.text($this.text());
$('#modal-geo-info').data({
cloneUrlSecondary: $this.attr('href'),
cloneUrlPrimary: $this.data('primaryUrl') || ''
});
return $('.clone').text(url); return $('.clone').text(url);
// Git protocol switcher
// Remove the active class for all buttons (ssh, http, kerberos if shown)
// Add the active class for the clicked button
// Update the input field
// Update the command line instructions
}); });
// Ref switcher // Ref switcher
this.initRefSwitcher(); this.initRefSwitcher();
......
document.addEventListener('DOMContentLoaded', () => {
const importBtnTooltip = 'Please enter a valid project name.';
const $importBtnWrapper = $('.import_gitlab_project');
$('.how_to_import_link').on('click', (e) => {
e.preventDefault();
$('.how_to_import_link').next('.modal').show();
});
$('.modal-header .close').on('click', () => {
$('.modal').hide();
});
$('.btn_import_gitlab_project').on('click', () => {
const importHref = $('a.btn_import_gitlab_project').attr('href');
$('.btn_import_gitlab_project').attr('href', `${importHref}?namespace_id=${$('#project_namespace_id').val()}&path=${$('#project_path').val()}`);
});
$('.btn_import_gitlab_project').attr('disabled', !$('#project_path').val().trim().length);
$importBtnWrapper.attr('title', importBtnTooltip);
$('#new_project').on('submit', () => {
const $path = $('#project_path');
$path.val($path.val().trim());
});
$('#project_path').on('keyup', () => {
if ($('#project_path').val().trim().length) {
$('.btn_import_gitlab_project').attr('disabled', false);
$importBtnWrapper.attr('title', '');
$importBtnWrapper.removeClass('has-tooltip');
} else {
$('.btn_import_gitlab_project').attr('disabled', true);
$importBtnWrapper.addClass('has-tooltip');
}
});
$('#project_import_url').disable();
$('.import_git').on('click', () => {
const $projectImportUrl = $('#project_import_url');
$projectImportUrl.attr('disabled', !$projectImportUrl.attr('disabled'));
});
});
class RefSelectDropdown { class RefSelectDropdown {
constructor($dropdownButton, availableRefs) { constructor($dropdownButton, availableRefs) {
const availableRefsValue = availableRefs || JSON.parse(document.getElementById('availableRefs').innerHTML);
$dropdownButton.glDropdown({ $dropdownButton.glDropdown({
data: availableRefs, data: availableRefsValue,
filterable: true, filterable: true,
filterByText: true, filterByText: true,
remote: false, remote: false,
......
...@@ -5,7 +5,8 @@ import sidebarAssignees from './components/assignees/sidebar_assignees'; ...@@ -5,7 +5,8 @@ import sidebarAssignees from './components/assignees/sidebar_assignees';
import Mediator from './sidebar_mediator'; import Mediator from './sidebar_mediator';
function domContentLoaded() { function domContentLoaded() {
const mediator = new Mediator(gl.sidebarOptions); const sidebarOptions = JSON.parse(document.querySelector('.js-sidebar-options').innerHTML);
const mediator = new Mediator(sidebarOptions);
mediator.fetch(); mediator.fetch();
const sidebarAssigneesEl = document.querySelector('#js-vue-sidebar-assignees'); const sidebarAssigneesEl = document.querySelector('#js-vue-sidebar-assignees');
......
function SnippetsList() {
const $holder = $('.snippets-list-holder');
$holder.find('.pagination').on('ajax:success', (e, data) => {
$holder.replaceWith(data.html);
});
}
window.gl.SnippetsList = SnippetsList;
...@@ -37,10 +37,6 @@ export default class Todos { ...@@ -37,10 +37,6 @@ export default class Todos {
this.initFilterDropdown($('.js-type-search'), 'type'); this.initFilterDropdown($('.js-type-search'), 'type');
this.initFilterDropdown($('.js-action-search'), 'action_id'); this.initFilterDropdown($('.js-action-search'), 'action_id');
$('form.filter-form').on('submit', function applyFilters(event) {
event.preventDefault();
gl.utils.visitUrl(`${this.action}&${$(this).serialize()}`);
});
return new UsersSelect(); return new UsersSelect();
} }
......
...@@ -67,7 +67,7 @@ export default class MergeRequestStore { ...@@ -67,7 +67,7 @@ export default class MergeRequestStore {
this.mergeCheckPath = data.merge_check_path; this.mergeCheckPath = data.merge_check_path;
this.mergeActionsContentPath = data.commit_change_content_path; this.mergeActionsContentPath = data.commit_change_content_path;
this.isRemovingSourceBranch = this.isRemovingSourceBranch || false; this.isRemovingSourceBranch = this.isRemovingSourceBranch || false;
this.isOpen = data.state === 'opened' || data.state === 'reopened' || false; this.isOpen = data.state === 'opened';
this.hasMergeableDiscussionsState = data.mergeable_discussions_state === false; this.hasMergeableDiscussionsState = data.mergeable_discussions_state === false;
this.canRemoveSourceBranch = currentUser.can_remove_source_branch || false; this.canRemoveSourceBranch = currentUser.can_remove_source_branch || false;
this.canMerge = !!data.merge_path; this.canMerge = !!data.merge_path;
......
...@@ -315,6 +315,10 @@ header { ...@@ -315,6 +315,10 @@ header {
} }
} }
.with-performance-bar header.navbar-gitlab {
top: $performance-bar-height;
}
.navbar-nav { .navbar-nav {
li { li {
.badge { .badge {
......
...@@ -120,3 +120,7 @@ of the body element here, we negate cascading side effects but allow momentum sc ...@@ -120,3 +120,7 @@ of the body element here, we negate cascading side effects but allow momentum sc
.page-with-sidebar { .page-with-sidebar {
-webkit-overflow-scrolling: auto; -webkit-overflow-scrolling: auto;
} }
.with-performance-bar .page-with-sidebar {
margin-top: $header-height + $performance-bar-height;
}
...@@ -374,6 +374,10 @@ ...@@ -374,6 +374,10 @@
} }
} }
.with-performance-bar .layout-nav {
margin-top: $header-height + $performance-bar-height;
}
.scrolling-tabs-container { .scrolling-tabs-container {
position: relative; position: relative;
...@@ -468,6 +472,22 @@ ...@@ -468,6 +472,22 @@
} }
} }
.with-performance-bar .page-with-layout-nav {
.right-sidebar {
top: ($header-height + 1) * 2 + $performance-bar-height;
}
&.page-with-sub-nav {
.right-sidebar {
top: ($header-height + 1) * 3 + $performance-bar-height;
&.affix {
top: $header-height + $performance-bar-height;
}
}
}
}
.nav-block { .nav-block {
&.activities { &.activities {
border-bottom: 1px solid $border-color; border-bottom: 1px solid $border-color;
......
...@@ -89,6 +89,10 @@ ...@@ -89,6 +89,10 @@
} }
} }
.with-performance-bar .right-sidebar.affix {
top: $header-height + $performance-bar-height;
}
@mixin maintain-sidebar-dimensions { @mixin maintain-sidebar-dimensions {
display: block; display: block;
width: $gutter-width; width: $gutter-width;
......
...@@ -205,6 +205,8 @@ $divergence-graph-separator-bg: #ccc; ...@@ -205,6 +205,8 @@ $divergence-graph-separator-bg: #ccc;
$general-hover-transition-duration: 100ms; $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;
$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;
......
...@@ -118,7 +118,7 @@ $new-sidebar-width: 220px; ...@@ -118,7 +118,7 @@ $new-sidebar-width: 220px;
z-index: 400; z-index: 400;
width: $new-sidebar-width; width: $new-sidebar-width;
transition: left $sidebar-transition-duration; transition: left $sidebar-transition-duration;
top: 50px; top: $header-height;
bottom: 0; bottom: 0;
left: 0; left: 0;
overflow: auto; overflow: auto;
...@@ -163,6 +163,10 @@ $new-sidebar-width: 220px; ...@@ -163,6 +163,10 @@ $new-sidebar-width: 220px;
} }
} }
.with-performance-bar .nav-sidebar {
top: $header-height + $performance-bar-height;
}
.sidebar-sub-level-items { .sidebar-sub-level-items {
display: none; display: none;
padding-bottom: 8px; padding-bottom: 8px;
...@@ -260,7 +264,7 @@ $new-sidebar-width: 220px; ...@@ -260,7 +264,7 @@ $new-sidebar-width: 220px;
// Make issue boards full-height now that sub-nav is gone // Make issue boards full-height now that sub-nav is gone
.boards-list { .boards-list {
height: calc(100vh - 50px); height: calc(100vh - #{$header-height});
@media (min-width: $screen-sm-min) { @media (min-width: $screen-sm-min) {
height: 475px; // Needed for PhantomJS height: 475px; // Needed for PhantomJS
...@@ -270,6 +274,10 @@ $new-sidebar-width: 220px; ...@@ -270,6 +274,10 @@ $new-sidebar-width: 220px;
} }
} }
.with-performance-bar .boards-list {
height: calc(100vh - #{$header-height} - #{$performance-bar-height});
}
// Change color of all horizontal tabs to match the new indigo color // Change color of all horizontal tabs to match the new indigo color
.nav-links li.active a { .nav-links li.active a {
......
...@@ -64,10 +64,10 @@ ...@@ -64,10 +64,10 @@
color: $gl-text-color; color: $gl-text-color;
position: sticky; position: sticky;
position: -webkit-sticky; position: -webkit-sticky;
top: 50px; top: $header-height;
&.affix { &.affix {
top: 50px; top: $header-height;
} }
// with sidebar // with sidebar
...@@ -171,6 +171,16 @@ ...@@ -171,6 +171,16 @@
} }
} }
.with-performance-bar .build-page {
.top-bar {
top: $header-height + $performance-bar-height;
&.affix {
top: $header-height + $performance-bar-height;
}
}
}
.build-header { .build-header {
.ci-header-container, .ci-header-container,
.header-action-buttons { .header-action-buttons {
......
...@@ -445,6 +445,14 @@ ...@@ -445,6 +445,14 @@
} }
} }
.with-performance-bar .right-sidebar {
top: $header-height + $performance-bar-height;
.issuable-sidebar {
height: calc(100% - #{$header-height} - #{$performance-bar-height});
}
}
.detail-page-description { .detail-page-description {
padding: 16px 0; padding: 16px 0;
......
...@@ -759,6 +759,10 @@ ...@@ -759,6 +759,10 @@
} }
} }
.with-performance-bar .merge-request-tabs-holder {
top: $header-height + $performance-bar-height;
}
.merge-request-tabs { .merge-request-tabs {
display: flex; display: flex;
margin-bottom: 0; margin-bottom: 0;
......
...@@ -3,9 +3,16 @@ ...@@ -3,9 +3,16 @@
@import "peek/views/rblineprof"; @import "peek/views/rblineprof";
#peek { #peek {
height: 35px; position: fixed;
left: 0;
top: 0;
width: 100%;
z-index: 2000;
overflow-x: hidden;
height: $performance-bar-height;
background: $black; background: $black;
line-height: 35px; line-height: $performance-bar-height;
color: $perf-bar-text; color: $perf-bar-text;
&.disabled { &.disabled {
...@@ -25,7 +32,8 @@ ...@@ -25,7 +32,8 @@
} }
.wrapper { .wrapper {
width: 1000px; width: 80%;
height: $performance-bar-height;
margin: 0 auto; margin: 0 auto;
} }
......
...@@ -2,6 +2,7 @@ class Groups::LdapGroupLinksController < Groups::ApplicationController ...@@ -2,6 +2,7 @@ class Groups::LdapGroupLinksController < Groups::ApplicationController
before_action :group before_action :group
before_action :require_ldap_enabled before_action :require_ldap_enabled
before_action :authorize_admin_group! before_action :authorize_admin_group!
before_action :authorize_manage_ldap_group_links!
layout 'group_settings' layout 'group_settings'
...@@ -31,6 +32,12 @@ class Groups::LdapGroupLinksController < Groups::ApplicationController ...@@ -31,6 +32,12 @@ class Groups::LdapGroupLinksController < Groups::ApplicationController
private private
def authorize_manage_ldap_group_links!
unless can?(current_user, :admin_ldap_group_links, group)
return render_404
end
end
def require_ldap_enabled def require_ldap_enabled
render_404 unless Gitlab.config.ldap.enabled render_404 unless Gitlab.config.ldap.enabled
end end
......
...@@ -86,7 +86,6 @@ class IssuableFinder ...@@ -86,7 +86,6 @@ class IssuableFinder
end end
counts[:all] = counts.values.sum counts[:all] = counts.values.sum
counts[:opened] += counts[:reopened]
counts.with_indifferent_access counts.with_indifferent_access
end end
......
...@@ -268,7 +268,11 @@ module ApplicationHelper ...@@ -268,7 +268,11 @@ module ApplicationHelper
end end
def page_class def page_class
"issue-boards-page" if current_controller?(:boards) class_names = []
class_names << 'issue-boards-page' if current_controller?(:boards)
class_names << 'with-performance-bar' if performance_bar_enabled?
class_names
end end
# Returns active css class when condition returns true # Returns active css class when condition returns true
......
...@@ -21,7 +21,8 @@ module EE ...@@ -21,7 +21,8 @@ module EE
:slack_app_enabled, :slack_app_enabled,
:slack_app_id, :slack_app_id,
:slack_app_secret, :slack_app_secret,
:slack_app_verification_token :slack_app_verification_token,
:allow_group_owners_to_manage_ldap
] ]
end end
......
...@@ -362,4 +362,14 @@ module IssuablesHelper ...@@ -362,4 +362,14 @@ module IssuablesHelper
params[:format] = :json if issuable.is_a?(Issue) params[:format] = :json if issuable.is_a?(Issue)
end end
end end
def issuable_sidebar_options(issuable, can_edit_issuable)
{
endpoint: "#{issuable_json_path(issuable)}?basic=true",
editable: can_edit_issuable,
currentUser: current_user.as_json(only: [:username, :id, :name], methods: :avatar_url),
rootPath: root_path,
fullPath: @project.full_path
}
end
end end
module MembersHelper module MembersHelper
# Returns a `<action>_<source>_member` association, e.g.: # Returns a `<action>_<source>_member` association, e.g.:
# - admin_project_member, update_project_member, destroy_project_member # - admin_project_member, update_project_member, destroy_project_member
# - admin_group_member, update_group_member, destroy_group_member # - admin_group_member, update_group_member, destroy_group_member, override_group_member
def action_member_permission(action, member) def action_member_permission(action, member)
"#{action}_#{member.type.underscore}".to_sym "#{action}_#{member.type.underscore}".to_sym
end end
......
module NavHelper module NavHelper
def page_with_sidebar_class
class_name = page_gutter_class
class_name << 'page-with-new-sidebar' if defined?(@new_sidebar) && @new_sidebar
class_name
end
def page_gutter_class def page_gutter_class
if current_path?('merge_requests#show') || if current_path?('merge_requests#show') ||
current_path?('projects/merge_requests/conflicts#show') || current_path?('projects/merge_requests/conflicts#show') ||
current_path?('issues#show') || current_path?('issues#show') ||
current_path?('milestones#show') current_path?('milestones#show')
if cookies[:collapsed_gutter] == 'true' if cookies[:collapsed_gutter] == 'true'
"page-gutter right-sidebar-collapsed" %w[page-gutter right-sidebar-collapsed]
else else
"page-gutter right-sidebar-expanded" %w[page-gutter right-sidebar-expanded]
end end
elsif current_path?('jobs#show') elsif current_path?('jobs#show')
"page-gutter build-sidebar right-sidebar-expanded" %w[page-gutter build-sidebar right-sidebar-expanded]
elsif current_path?('wikis#show') || elsif current_path?('wikis#show') ||
current_path?('wikis#edit') || current_path?('wikis#edit') ||
current_path?('wikis#update') || current_path?('wikis#update') ||
current_path?('wikis#history') || current_path?('wikis#history') ||
current_path?('wikis#git_access') current_path?('wikis#git_access')
"page-gutter wiki-sidebar right-sidebar-expanded" %w[page-gutter wiki-sidebar right-sidebar-expanded]
else
[]
end end
end end
def nav_header_class def nav_header_class
class_name = '' class_names = []
class_name << " with-horizontal-nav" if defined?(nav) && nav class_names << 'with-horizontal-nav' if defined?(nav) && nav
class_name class_names
end end
def layout_nav_class def layout_nav_class
class_name = '' return [] if show_new_nav?
class_name << " page-with-layout-nav" if defined?(nav) && nav
class_name << " page-with-sub-nav" if content_for?(:sub_nav)
class_name class_names = []
class_names << 'page-with-layout-nav' if defined?(nav) && nav
class_names << 'page-with-sub-nav' if content_for?(:sub_nav)
class_names
end end
def nav_control_class def nav_control_class
......
...@@ -130,4 +130,14 @@ module NotesHelper ...@@ -130,4 +130,14 @@ module NotesHelper
can?(current_user, :create_note, @project) can?(current_user, :create_note, @project)
end end
end end
def initial_notes_data(autocomplete)
{
notesUrl: notes_url,
notesIds: @notes.map(&:id),
now: Time.now.to_i,
diffView: diff_view,
autocomplete: autocomplete
}
end
end end
class Burndown class Burndown
Issue = Struct.new(:closed_at, :weight, :state) class Issue
attr_reader :closed_at, :weight, :state
def initialize(closed_at, weight, state)
@closed_at = closed_at
@weight = weight
@state = state
end
def reopened?
@state == 'opened' && @closed_at.present?
end
end
attr_reader :start_date, :due_date, :end_date, :issues_count, :issues_weight, :accurate, :legacy_data attr_reader :start_date, :due_date, :end_date, :issues_count, :issues_weight, :accurate, :legacy_data
alias_method :accurate?, :accurate alias_method :accurate?, :accurate
...@@ -12,8 +24,8 @@ class Burndown ...@@ -12,8 +24,8 @@ class Burndown
@end_date = @milestone.due_date @end_date = @milestone.due_date
@end_date = Date.today if @end_date.present? && @end_date > Date.today @end_date = Date.today if @end_date.present? && @end_date > Date.today
@accurate = milestone_closed_issues.all?(&:closed_at) @accurate = milestone_issues.all?(&:closed_at)
@legacy_data = milestone_closed_issues.any? && milestone_closed_issues.none?(&:closed_at) @legacy_data = milestone_issues.any? && milestone_issues.none?(&:closed_at)
@issues_count, @issues_weight = milestone.issues.reorder(nil).pluck('COUNT(*), COALESCE(SUM(weight), 0)').first @issues_count, @issues_weight = milestone.issues.reorder(nil).pluck('COUNT(*), COALESCE(SUM(weight), 0)').first
end end
...@@ -59,21 +71,21 @@ class Burndown ...@@ -59,21 +71,21 @@ class Burndown
current_date = date.to_date current_date = date.to_date
closed = closed =
milestone_closed_issues.select do |issue| milestone_issues.select do |issue|
(issue.closed_at&.to_date || start_date) == current_date (issue.closed_at&.to_date || start_date) == current_date
end end
reopened = closed.select { |issue| issue.state == 'reopened' } reopened = closed.select(&:reopened?)
[closed, reopened] [closed, reopened]
end end
def milestone_closed_issues def milestone_issues
@milestone_closed_issues ||= @milestone_issues ||=
@milestone.issues @milestone.issues
.where("state IN ('reopened', 'closed')") .where("state = 'closed' OR (state = 'opened' AND closed_at IS NOT NULL)")
.order("closed_at ASC") .reorder("closed_at ASC")
.pluck("closed_at, weight, state") .pluck("closed_at, weight, state")
.map {|attrs| ::Burndown::Issue.new(*attrs) } .map {|attrs| Issue.new(*attrs) }
end end
end end
...@@ -223,6 +223,7 @@ module Ci ...@@ -223,6 +223,7 @@ module Ci
variables += project.group.secret_variables_for(ref, project).map(&:to_runner_variable) if project.group variables += project.group.secret_variables_for(ref, project).map(&:to_runner_variable) if project.group
variables += secret_variables(environment: environment) variables += secret_variables(environment: environment)
variables += trigger_request.user_variables if trigger_request variables += trigger_request.user_variables if trigger_request
variables += pipeline.variables.map(&:to_runner_variable)
variables += pipeline.pipeline_schedule.job_variables if pipeline.pipeline_schedule variables += pipeline.pipeline_schedule.job_variables if pipeline.pipeline_schedule
variables += persisted_environment_variables if environment variables += persisted_environment_variables if environment
......
...@@ -27,6 +27,7 @@ module Ci ...@@ -27,6 +27,7 @@ module Ci
has_many :statuses, class_name: 'CommitStatus', foreign_key: :commit_id has_many :statuses, class_name: 'CommitStatus', foreign_key: :commit_id
has_many :builds, foreign_key: :commit_id has_many :builds, foreign_key: :commit_id
has_many :trigger_requests, dependent: :destroy, foreign_key: :commit_id # rubocop:disable Cop/ActiveRecordDependent has_many :trigger_requests, dependent: :destroy, foreign_key: :commit_id # rubocop:disable Cop/ActiveRecordDependent
has_many :variables, class_name: 'Ci::PipelineVariable'
# Merge requests for which the current pipeline is running against # Merge requests for which the current pipeline is running against
# the merge request's latest commit. # the merge request's latest commit.
......
module Ci
class PipelineVariable < ActiveRecord::Base
extend Ci::Model
include HasVariable
belongs_to :pipeline
validates :key, uniqueness: { scope: :pipeline_id }
end
end
...@@ -71,9 +71,8 @@ module Issuable ...@@ -71,9 +71,8 @@ module Issuable
scope :of_projects, ->(ids) { where(project_id: ids) } scope :of_projects, ->(ids) { where(project_id: ids) }
scope :of_milestones, ->(ids) { where(milestone_id: ids) } scope :of_milestones, ->(ids) { where(milestone_id: ids) }
scope :with_milestone, ->(title) { left_joins_milestones.where(milestones: { title: title }) } scope :with_milestone, ->(title) { left_joins_milestones.where(milestones: { title: title }) }
scope :opened, -> { with_state(:opened, :reopened) } scope :opened, -> { with_state(:opened) }
scope :only_opened, -> { with_state(:opened) } scope :only_opened, -> { with_state(:opened) }
scope :only_reopened, -> { with_state(:reopened) }
scope :closed, -> { with_state(:closed) } scope :closed, -> { with_state(:closed) }
scope :order_milestone_due_desc, -> { outer_join_milestone.reorder('milestones.due_date IS NULL ASC, milestones.due_date DESC, milestones.id DESC') } scope :order_milestone_due_desc, -> { outer_join_milestone.reorder('milestones.due_date IS NULL ASC, milestones.due_date DESC, milestones.id DESC') }
scope :order_milestone_due_asc, -> { outer_join_milestone.reorder('milestones.due_date IS NULL ASC, milestones.due_date ASC, milestones.id ASC') } scope :order_milestone_due_asc, -> { outer_join_milestone.reorder('milestones.due_date IS NULL ASC, milestones.due_date ASC, milestones.id ASC') }
...@@ -241,7 +240,7 @@ module Issuable ...@@ -241,7 +240,7 @@ module Issuable
end end
def open? def open?
opened? || reopened? opened?
end end
def user_notes_count def user_notes_count
......
...@@ -39,7 +39,8 @@ module EE ...@@ -39,7 +39,8 @@ module EE
repository_size_limit: 0, repository_size_limit: 0,
mirror_max_delay: Settings.gitlab['mirror_max_delay'], mirror_max_delay: Settings.gitlab['mirror_max_delay'],
mirror_max_capacity: Settings.gitlab['mirror_max_capacity'], mirror_max_capacity: Settings.gitlab['mirror_max_capacity'],
mirror_capacity_threshold: Settings.gitlab['mirror_capacity_threshold'] mirror_capacity_threshold: Settings.gitlab['mirror_capacity_threshold'],
allow_group_owners_to_manage_ldap: true
) )
end end
end end
......
...@@ -73,15 +73,14 @@ class Issue < ActiveRecord::Base ...@@ -73,15 +73,14 @@ class Issue < ActiveRecord::Base
state_machine :state, initial: :opened do state_machine :state, initial: :opened do
event :close do event :close do
transition [:reopened, :opened] => :closed transition [:opened] => :closed
end end
event :reopen do event :reopen do
transition closed: :reopened transition closed: :opened
end end
state :opened state :opened
state :reopened
state :closed state :closed
before_transition any => :closed do |issue| before_transition any => :closed do |issue|
......
...@@ -45,23 +45,23 @@ class MergeRequest < ActiveRecord::Base ...@@ -45,23 +45,23 @@ class MergeRequest < ActiveRecord::Base
state_machine :state, initial: :opened do state_machine :state, initial: :opened do
event :close do event :close do
transition [:reopened, :opened] => :closed transition [:opened] => :closed
end end
event :mark_as_merged do event :mark_as_merged do
transition [:reopened, :opened, :locked] => :merged transition [:opened, :locked] => :merged
end end
event :reopen do event :reopen do
transition closed: :reopened transition closed: :opened
end end
event :lock_mr do event :lock_mr do
transition [:reopened, :opened] => :locked transition [:opened] => :locked
end end
event :unlock_mr do event :unlock_mr do
transition locked: :reopened transition locked: :opened
end end
after_transition any => :locked do |merge_request, transition| after_transition any => :locked do |merge_request, transition|
...@@ -75,7 +75,6 @@ class MergeRequest < ActiveRecord::Base ...@@ -75,7 +75,6 @@ class MergeRequest < ActiveRecord::Base
end end
state :opened state :opened
state :reopened
state :closed state :closed
state :merged state :merged
state :locked state :locked
...@@ -372,7 +371,7 @@ class MergeRequest < ActiveRecord::Base ...@@ -372,7 +371,7 @@ class MergeRequest < ActiveRecord::Base
errors.add :branch_conflict, "You can not use same project/branch for source and target" errors.add :branch_conflict, "You can not use same project/branch for source and target"
end end
if opened? || reopened? if opened?
similar_mrs = self.target_project.merge_requests.where(source_branch: source_branch, target_branch: target_branch, source_project_id: source_project.try(:id)).opened similar_mrs = self.target_project.merge_requests.where(source_branch: source_branch, target_branch: target_branch, source_project_id: source_project.try(:id)).opened
similar_mrs = similar_mrs.where('id not in (?)', self.id) if self.id similar_mrs = similar_mrs.where('id not in (?)', self.id) if self.id
if similar_mrs.any? if similar_mrs.any?
......
...@@ -114,7 +114,7 @@ class DroneCiService < CiService ...@@ -114,7 +114,7 @@ class DroneCiService < CiService
end end
def merge_request_valid?(data) def merge_request_valid?(data)
%w(opened reopened).include?(data[:object_attributes][:state]) && data[:object_attributes][:state] == 'opened' &&
data[:object_attributes][:merge_status] == 'unchecked' data[:object_attributes][:merge_status] == 'unchecked'
end end
end end
...@@ -6,19 +6,19 @@ module EE ...@@ -6,19 +6,19 @@ module EE
with_scope :subject with_scope :subject
condition(:ldap_synced) { @subject.ldap_synced? } condition(:ldap_synced) { @subject.ldap_synced? }
rule { ldap_synced }.prevent :admin_group_member condition(:can_owners_manage_ldap, scope: :global) do
current_application_settings.allow_group_owners_to_manage_ldap
rule { ldap_synced & admin }.policy do
enable :override_group_member
enable :update_group_member
end
rule { ldap_synced & owner }.policy do
enable :override_group_member
enable :update_group_member
end end
rule { auditor }.enable :read_group rule { auditor }.enable :read_group
rule { admin | (can_owners_manage_ldap & owner) }.enable :admin_ldap_group_links
rule { ldap_synced }.prevent :admin_group_member
rule { ldap_synced & (admin | owner) }.enable :update_group_member
rule { ldap_synced & (admin | (can_owners_manage_ldap & owner)) }.enable :override_group_member
end end
end end
end end
...@@ -2,7 +2,7 @@ module Ci ...@@ -2,7 +2,7 @@ module Ci
class CreatePipelineService < BaseService class CreatePipelineService < BaseService
attr_reader :pipeline attr_reader :pipeline
def execute(source, ignore_skip_ci: false, save_on_errors: true, trigger_request: nil, schedule: nil, mirror_update: false, &block) def execute(source, ignore_skip_ci: false, save_on_errors: true, trigger_request: nil, schedule: nil, mirror_update: false)
@pipeline = Ci::Pipeline.new( @pipeline = Ci::Pipeline.new(
source: source, source: source,
project: project, project: project,
...@@ -22,7 +22,27 @@ module Ci ...@@ -22,7 +22,27 @@ module Ci
return result if result return result if result
_create_pipeline(source, &block) begin
Ci::Pipeline.transaction do
pipeline.save!
yield(pipeline) if block_given?
Ci::CreatePipelineStagesService
.new(project, current_user)
.execute(pipeline)
end
rescue ActiveRecord::RecordInvalid => e
return error("Failed to persist the pipeline: #{e}")
end
update_merge_requests_head_pipeline
cancel_pending_pipelines if project.auto_cancel_pending_pipelines?
pipeline_created_counter.increment(source: source)
pipeline.tap(&:process!)
end end
private private
...@@ -69,24 +89,6 @@ module Ci ...@@ -69,24 +89,6 @@ module Ci
end end
end end
def _create_pipeline(source)
Ci::Pipeline.transaction do
update_merge_requests_head_pipeline if pipeline.save
yield(pipeline) if block_given?
Ci::CreatePipelineStagesService
.new(project, current_user)
.execute(pipeline)
end
cancel_pending_pipelines if project.auto_cancel_pending_pipelines?
pipeline_created_counter.increment(source: source)
pipeline.tap(&:process!)
end
def allowed_to_trigger_pipeline?(triggering_user) def allowed_to_trigger_pipeline?(triggering_user)
if triggering_user if triggering_user
allowed_to_create?(triggering_user) allowed_to_create?(triggering_user)
......
# This class is deprecated because we're closing Ci::TriggerRequest.
# New class is PipelineTriggerService (app/services/ci/pipeline_trigger_service.rb)
# which is integrated with Ci::PipelineVariable instaed of Ci::TriggerRequest.
# We remove this class after we removed v1 and v3 API. This class is still being
# referred by such legacy code.
module Ci module Ci
module CreateTriggerRequestService module CreateTriggerRequestService
Result = Struct.new(:trigger_request, :pipeline) Result = Struct.new(:trigger_request, :pipeline)
......
...@@ -14,9 +14,11 @@ module Ci ...@@ -14,9 +14,11 @@ module Ci
# 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 trigger.project == project return unless trigger.project == project
trigger_request = trigger.trigger_requests.create(variables: params[:variables])
pipeline = Ci::CreatePipelineService.new(project, trigger.owner, ref: params[:ref]) pipeline = Ci::CreatePipelineService.new(project, trigger.owner, ref: params[:ref])
.execute(:trigger, ignore_skip_ci: true, trigger_request: trigger_request) .execute(:trigger, ignore_skip_ci: true) do |pipeline|
trigger.trigger_requests.create!(pipeline: pipeline)
create_pipeline_variables!(pipeline)
end
if pipeline.persisted? if pipeline.persisted?
success(pipeline: pipeline) success(pipeline: pipeline)
...@@ -47,17 +49,27 @@ module Ci ...@@ -47,17 +49,27 @@ module Ci
error(pipeline.errors.messages, 400) error(pipeline.errors.messages, 400)
end end
end end
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
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
def create_pipeline_variables!(pipeline)
return unless params[:variables]
variables = params[:variables].map do |key, value|
{ key: key, value: value }
end
pipeline.variables.create!(variables)
end
end end
end end
...@@ -5,7 +5,7 @@ module Issues ...@@ -5,7 +5,7 @@ module Issues
if issue.reopen if issue.reopen
event_service.reopen_issue(issue, current_user) event_service.reopen_issue(issue, current_user)
create_note(issue) create_note(issue, 'reopened')
notification_service.reopen_issue(issue, current_user) notification_service.reopen_issue(issue, current_user)
execute_hooks(issue, 'reopen') execute_hooks(issue, 'reopen')
invalidate_cache_counts(issue, users: issue.assignees) invalidate_cache_counts(issue, users: issue.assignees)
...@@ -16,8 +16,8 @@ module Issues ...@@ -16,8 +16,8 @@ module Issues
private private
def create_note(issue) def create_note(issue, state = issue.state)
SystemNoteService.change_status(issue, issue.project, current_user, issue.state, nil) SystemNoteService.change_status(issue, issue.project, current_user, state, nil)
end end
end end
end end
...@@ -2,8 +2,8 @@ module MergeRequests ...@@ -2,8 +2,8 @@ module MergeRequests
class BaseService < ::IssuableBaseService class BaseService < ::IssuableBaseService
prepend EE::MergeRequests::BaseService prepend EE::MergeRequests::BaseService
def create_note(merge_request) def create_note(merge_request, state = merge_request.state)
SystemNoteService.change_status(merge_request, merge_request.target_project, current_user, merge_request.state, nil) SystemNoteService.change_status(merge_request, merge_request.target_project, current_user, state, nil)
end end
def create_title_change_note(issuable, old_title) def create_title_change_note(issuable, old_title)
...@@ -46,7 +46,7 @@ module MergeRequests ...@@ -46,7 +46,7 @@ module MergeRequests
end end
# Returns all origin and fork merge requests from `@project` satisfying passed arguments. # Returns all origin and fork merge requests from `@project` satisfying passed arguments.
def merge_requests_for(source_branch, mr_states: [:opened, :reopened]) def merge_requests_for(source_branch, mr_states: [:opened])
MergeRequest MergeRequest
.with_state(mr_states) .with_state(mr_states)
.where(source_branch: source_branch, source_project_id: @project.id) .where(source_branch: source_branch, source_project_id: @project.id)
......
...@@ -82,7 +82,7 @@ module MergeRequests ...@@ -82,7 +82,7 @@ module MergeRequests
# Note: Closed merge requests also need approvals reset. # Note: Closed merge requests also need approvals reset.
def reset_approvals_for_merge_requests def reset_approvals_for_merge_requests
merge_requests = merge_requests_for(@branch_name, mr_states: [:opened, :reopened, :closed]) merge_requests = merge_requests_for(@branch_name, mr_states: [:opened, :closed])
merge_requests.each do |merge_request| merge_requests.each do |merge_request|
target_project = merge_request.target_project target_project = merge_request.target_project
......
...@@ -5,7 +5,7 @@ module MergeRequests ...@@ -5,7 +5,7 @@ module MergeRequests
if merge_request.reopen if merge_request.reopen
event_service.reopen_mr(merge_request, current_user) event_service.reopen_mr(merge_request, current_user)
create_note(merge_request) create_note(merge_request, 'reopened')
notification_service.reopen_mr(merge_request, current_user) notification_service.reopen_mr(merge_request, current_user)
execute_hooks(merge_request, 'reopen') execute_hooks(merge_request, 'reopen')
merge_request.reload_diff(current_user) merge_request.reload_diff(current_user)
......
...@@ -48,6 +48,17 @@ ...@@ -48,6 +48,17 @@
= select(:application_setting, :enabled_git_access_protocol, [['Both SSH and HTTP(S)', nil], ['Only SSH', 'ssh'], ['Only HTTP(S)', 'http']], {}, class: 'form-control') = select(:application_setting, :enabled_git_access_protocol, [['Both SSH and HTTP(S)', nil], ['Only SSH', 'ssh'], ['Only HTTP(S)', 'http']], {}, class: 'form-control')
%span.help-block#clone-protocol-help %span.help-block#clone-protocol-help
Allow only the selected protocols to be used for Git access. Allow only the selected protocols to be used for Git access.
- if ldap_enabled?
.form-group
= f.label :allow_group_owners_to_manage_ldap, 'LDAP settings', class: 'control-label col-sm-2'
.col-sm-10
.checkbox
= f.label :allow_group_owners_to_manage_ldap do
= f.check_box :allow_group_owners_to_manage_ldap
Allow group owners to manage LDAP-related settings
%span.help-block
If checked, group owners can manage LDAP group links and LDAP member overrides
= link_to icon('question-circle'), help_page_path('administration/auth/ldap-ee')
%fieldset %fieldset
%legend Account and Limit Settings %legend Account and Limit Settings
......
- if Gitlab::LDAP::Config.enabled_extras? - if Gitlab::LDAP::Config.enabled_extras? && can?(current_user, :admin_ldap_group_links, @group)
= nav_link(path: 'ldap_group_links#index') do = nav_link(path: 'ldap_group_links#index') do
= link_to group_ldap_group_links_path(@group), title: 'LDAP Group' do = link_to group_ldap_group_links_path(@group), title: 'LDAP Group' do
%span %span
......
.page-with-sidebar{ class: "#{('page-with-new-sidebar' if defined?(@new_sidebar) && @new_sidebar)} #{page_gutter_class}" } .page-with-sidebar{ class: page_with_sidebar_class }
- if show_new_nav? - if show_new_nav?
- if defined?(nav) && nav - if defined?(nav) && nav
= render "layouts/nav/#{nav}" = render "layouts/nav/#{nav}"
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
= render "layouts/nav/#{nav}" = render "layouts/nav/#{nav}"
- if content_for?(:sub_nav) - if content_for?(:sub_nav)
= yield :sub_nav = yield :sub_nav
.content-wrapper{ class: "#{(layout_nav_class unless show_new_nav?)}" } .content-wrapper{ class: layout_nav_class }
- if show_new_nav? - if show_new_nav?
.mobile-overlay .mobile-overlay
.alert-wrapper .alert-wrapper
......
!!! 5 !!! 5
%html{ lang: I18n.locale, class: "#{page_class}" } %html{ lang: I18n.locale, class: page_class }
= render "layouts/head" = render "layouts/head"
%body{ class: @body_class, data: { page: body_data_page, project: "#{@project.path if @project}", group: "#{@group.path if @group}", find_file: find_file_path } } %body{ class: @body_class, data: { page: body_data_page, project: "#{@project.path if @project}", group: "#{@group.path if @group}", find_file: find_file_path } }
= render "layouts/init_auto_complete" if @gfm_form = render "layouts/init_auto_complete" if @gfm_form
= render 'peek/bar'
- if show_new_nav? - if show_new_nav?
= render "layouts/header/new" = render "layouts/header/new"
- else - else
...@@ -10,5 +11,3 @@ ...@@ -10,5 +11,3 @@
= render 'layouts/page', sidebar: sidebar, nav: nav = render 'layouts/page', sidebar: sidebar, nav: nav
= yield :scripts_body = yield :scripts_body
= render 'peek/bar'
%span.current-host
= truncate(view.hostname)
...@@ -17,7 +17,11 @@ ...@@ -17,7 +17,11 @@
- if @remote_mirror.last_error.present? - if @remote_mirror.last_error.present?
.panel.panel-danger .panel.panel-danger
.panel-heading .panel-heading
The remote repository failed to update #{time_ago_with_tooltip(@remote_mirror.last_update_at)}. - if @remote_mirror.last_update_at
The remote repository failed to update #{time_ago_with_tooltip(@remote_mirror.last_update_at)}.
- else
The remote repository failed to update.
- if @remote_mirror.last_successful_update_at - if @remote_mirror.last_successful_update_at
Last successful update #{time_ago_with_tooltip(@remote_mirror.last_successful_update_at)}. Last successful update #{time_ago_with_tooltip(@remote_mirror.last_successful_update_at)}.
.panel-body .panel-body
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
- page_title 'New Project' - page_title 'New Project'
- header_title "Projects", dashboard_projects_path - header_title "Projects", dashboard_projects_path
- visibility_level = params.dig(:project, :visibility_level) || default_project_visibility - visibility_level = params.dig(:project, :visibility_level) || default_project_visibility
- content_for :page_specific_javascripts do
= webpack_bundle_tag 'project_new'
.project-edit-container .project-edit-container
.project-edit-errors .project-edit-errors
...@@ -111,49 +113,3 @@ ...@@ -111,49 +113,3 @@
%i.fa.fa-spinner.fa-spin %i.fa.fa-spinner.fa-spin
Creating project &amp; repository. Creating project &amp; repository.
%p Please wait a moment, this page will automatically refresh when ready. %p Please wait a moment, this page will automatically refresh when ready.
:javascript
var importBtnTooltip = "Please enter a valid project name.";
var $importBtnWrapper = $('.import_gitlab_project');
$('.how_to_import_link').bind('click', function (e) {
e.preventDefault();
var import_modal = $(this).next(".modal").show();
});
$('.modal-header .close').bind('click', function() {
$(".modal").hide();
});
$('.btn_import_gitlab_project').bind('click', function() {
var _href = $("a.btn_import_gitlab_project").attr("href");
$(".btn_import_gitlab_project").attr("href", _href + '?namespace_id=' + $("#project_namespace_id").val() + '&path=' + $("#project_path").val());
});
$('.btn_import_gitlab_project').attr('disabled', $('#project_path').val().trim().length === 0);
$importBtnWrapper.attr('title', importBtnTooltip);
$('#new_project').submit(function(){
var $path = $('#project_path');
$path.val($path.val().trim());
});
$('#project_path').keyup(function(){
if($(this).val().trim().length !== 0) {
$('.btn_import_gitlab_project').attr('disabled', false);
$importBtnWrapper.attr('title','');
$importBtnWrapper.removeClass('has-tooltip');
} else {
$('.btn_import_gitlab_project').attr('disabled',true);
$importBtnWrapper.addClass('has-tooltip');
}
});
$('#project_import_url').disable();
$('.import_git').click(function( event ) {
$projectImportUrl = $('#project_import_url');
$projectMirror = $('#project_mirror');
$projectImportUrl.attr('disabled', !$projectImportUrl.attr('disabled'));
$projectMirror.attr('disabled', !$projectMirror.attr('disabled'));
});
- content_for :page_specific_javascripts do
= webpack_bundle_tag('pipelines_times')
%div %div
%p.light %p.light
= _("Commit duration in minutes for last 30 commits") = _("Commit duration in minutes for last 30 commits")
%canvas#build_timesChart{ height: 200 } %canvas#build_timesChart{ height: 200 }
:javascript %script#pipelinesTimesChartsData{ type: "application/json" }= { :labels => @charts[:pipeline_times].labels, :values => @charts[:pipeline_times].pipeline_times }.to_json.html_safe
var data = {
labels : #{@charts[:pipeline_times].labels.to_json},
datasets : [
{
fillColor : "rgba(220,220,220,0.5)",
strokeColor : "rgba(220,220,220,1)",
barStrokeWidth: 1,
barValueSpacing: 1,
barDatasetSpacing: 1,
data : #{@charts[:pipeline_times].pipeline_times.to_json}
}
]
}
var ctx = $("#build_timesChart").get(0).getContext("2d");
var options = { scaleOverlay: true, responsive: true, maintainAspectRatio: false };
if (window.innerWidth < 768) {
// Scale fonts if window width lower than 768px (iPad portrait)
options.scaleFontSize = 8
}
new Chart(ctx).Bar(data, options);
- content_for :page_specific_javascripts do
= webpack_bundle_tag('pipelines_charts')
%h4= _("Pipelines charts") %h4= _("Pipelines charts")
%p %p
&nbsp; &nbsp;
...@@ -26,31 +29,8 @@ ...@@ -26,31 +29,8 @@
= _("Jobs for last year") = _("Jobs for last year")
%canvas#yearChart.padded{ height: 250 } %canvas#yearChart.padded{ height: 250 }
- [:week, :month, :year].each do |scope| %script#pipelinesChartsData{ type: "application/json" }
:javascript - chartData = []
var data = { - [:week, :month, :year].each do |scope|
labels : #{@charts[scope].labels.to_json}, - chartData.push({ 'scope' => scope, 'labels' => @charts[scope].labels, 'totalValues' => @charts[scope].total, 'successValues' => @charts[scope].success })
datasets : [ = chartData.to_json.html_safe
{
fillColor : "#7f8fa4",
strokeColor : "#7f8fa4",
pointColor : "#7f8fa4",
pointStrokeColor : "#EEE",
data : #{@charts[scope].total.to_json}
},
{
fillColor : "#44aa22",
strokeColor : "#44aa22",
pointColor : "#44aa22",
pointStrokeColor : "#fff",
data : #{@charts[scope].success.to_json}
}
]
}
var ctx = $("##{scope}Chart").get(0).getContext("2d");
var options = { scaleOverlay: true, responsive: true, maintainAspectRatio: false };
if (window.innerWidth < 768) {
// Scale fonts if window width lower than 768px (iPad portrait)
options.scaleFontSize = 8
}
new Chart(ctx).Line(data, options);
...@@ -20,7 +20,4 @@ ...@@ -20,7 +20,4 @@
= f.submit 'Create pipeline', class: 'btn btn-create', tabindex: 3 = f.submit 'Create pipeline', class: 'btn btn-create', tabindex: 3
= link_to 'Cancel', project_pipelines_path(@project), class: 'btn btn-cancel' = link_to 'Cancel', project_pipelines_path(@project), class: 'btn btn-cancel'
:javascript %script#availableRefs{ type: "application/json" }= @project.repository.ref_names.to_json.html_safe
var availableRefs = #{@project.repository.ref_names.to_json};
new NewBranchForm($('.js-new-pipeline-form'), availableRefs)
...@@ -40,7 +40,4 @@ ...@@ -40,7 +40,4 @@
.form-actions .form-actions
= button_tag 'Create tag', class: 'btn btn-create', tabindex: 3 = button_tag 'Create tag', class: 'btn btn-create', tabindex: 3
= link_to 'Cancel', project_tags_path(@project), class: 'btn btn-cancel' = link_to 'Cancel', project_tags_path(@project), class: 'btn btn-cancel'
%script#availableRefs{ type: "application/json" }= @project.repository.ref_names.to_json.html_safe
:javascript
window.gl = window.gl || { };
window.gl.availableRefs = #{@project.repository.ref_names.to_json};
.tree-content-holder .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 }
.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
...@@ -22,17 +22,3 @@ ...@@ -22,17 +22,3 @@
- if can_edit_tree? - if can_edit_tree?
= render 'projects/blob/upload', title: _('Upload New File'), placeholder: _('Upload New File'), button_title: _('Upload file'), form_path: project_create_blob_path(@project, @id), method: :post = render 'projects/blob/upload', title: _('Upload New File'), placeholder: _('Upload New File'), button_title: _('Upload file'), form_path: project_create_blob_path(@project, @id), method: :post
= render 'projects/blob/new_dir' = render 'projects/blob/new_dir'
- if @project.feature_available?(:file_locks)
:javascript
PathLocks.init(
'#{toggle_project_path_locks_path(@project)}',
'#{@path}'
);
:javascript
// Load last commit log for each file in tree
$('#tree-slider').waitForImages(function() {
gl.utils.ajaxGet("#{escape_javascript(@logs_path)}");
});
...@@ -19,6 +19,3 @@ ...@@ -19,6 +19,3 @@
More Pages More Pages
= render 'projects/wikis/new' = render 'projects/wikis/new'
:javascript
new Sidebar();
...@@ -26,23 +26,4 @@ ...@@ -26,23 +26,4 @@
= geo_button(modal_target: '#modal-geo-info') if Gitlab::Geo.secondary? = geo_button(modal_target: '#modal-geo-info') if Gitlab::Geo.secondary?
:javascript
$('ul.clone-options-dropdown a').on('click',function(e){
e.preventDefault();
var $this = $(this);
$('a.clone-dropdown-btn span').text($this.text());
$('#project_clone').val($this.attr('href'));
});
// Change URLs in Geo Clone Dialog information text
$('ul.clone-options-dropdown a').on('click',function(e){
e.preventDefault();
var $this = $(this);
$('#modal-geo-info').data({
cloneUrlSecondary: $this.attr('href'),
cloneUrlPrimary: $this.data('primaryUrl') || ''
});
});
= render 'shared/geo_info_modal', project: project if Gitlab::Geo.secondary? = render 'shared/geo_info_modal', project: project if Gitlab::Geo.secondary?
...@@ -76,11 +76,3 @@ ...@@ -76,11 +76,3 @@
= link_to destroy_label_path(label), title: "Delete", class: 'btn btn-transparent btn-action remove-row', method: :delete, data: {confirm: label_deletion_confirm_text(label), toggle: "tooltip"} do = link_to destroy_label_path(label), title: "Delete", class: 'btn btn-transparent btn-action remove-row', method: :delete, data: {confirm: label_deletion_confirm_text(label), toggle: "tooltip"} do
%span.sr-only Delete %span.sr-only Delete
= icon('trash-o') = icon('trash-o')
- if current_user
- if can_subscribe_to_label_in_different_levels?(label)
:javascript
new gl.GroupLabelSubscription('##{dom_id(label)} .label-subscription');
- else
:javascript
new gl.ProjectLabelSubscription('##{dom_id(label)} .label-subscription');
...@@ -23,18 +23,3 @@ ...@@ -23,18 +23,3 @@
.prepend-top-default .prepend-top-default
= f.submit "Create #{type} token", class: "btn btn-create" = f.submit "Create #{type} token", class: "btn btn-create"
:javascript
var $dateField = $('.datepicker');
var date = $dateField.val();
new Pikaday({
field: $dateField.get(0),
theme: 'gitlab-theme animate-picker',
format: 'yyyy-mm-dd',
minDate: new Date(),
container: $dateField.parent().get(0),
onSelect: function(dateText) {
$dateField.val(dateFormat(new Date(dateText), 'yyyy-mm-dd'));
}
});
...@@ -37,14 +37,3 @@ ...@@ -37,14 +37,3 @@
.row-content-block.second-block.filtered-labels{ class: ("hidden" unless has_labels) } .row-content-block.second-block.filtered-labels{ class: ("hidden" unless has_labels) }
- if has_labels - if has_labels
= render 'shared/labels_row', labels: @labels = render 'shared/labels_row', labels: @labels
:javascript
new LabelsSelect();
new MilestoneSelect();
new IssueStatusSelect();
new WeightSelect();
new SubscriptionSelect();
$('form.filter-form').on('submit', function (event) {
event.preventDefault();
gl.utils.visitUrl(this.action + '&' + $(this).serialize());
});
...@@ -16,5 +16,3 @@ ...@@ -16,5 +16,3 @@
.hide-collapsed.participants-more .hide-collapsed.participants-more
%a.js-participants-more{ href: "#", data: { original_text: "+ #{participants_size - 7} more", less_text: "- show less" } } %a.js-participants-more{ href: "#", data: { original_text: "+ #{participants_size - 7} more", less_text: "- show less" } }
+ #{participants_extra} more + #{participants_extra} more
:javascript
IssuableContext.prototype.PARTICIPANTS_ROW_COUNT = #{participants_row};
...@@ -128,12 +128,3 @@ ...@@ -128,12 +128,3 @@
#js-add-issues-btn.prepend-left-10 #js-add-issues-btn.prepend-left-10
- elsif type != :boards_modal - elsif type != :boards_modal
= render 'shared/sort_dropdown' = render 'shared/sort_dropdown'
- unless type === :boards_modal
:javascript
$(document).off('page:restore').on('page:restore', function (event) {
if (gl.FilteredSearchManager) {
const filteredSearchManager = new gl.FilteredSearchManager();
filteredSearchManager.setup();
}
});
...@@ -165,18 +165,4 @@ ...@@ -165,18 +165,4 @@
= project_ref = project_ref
= clipboard_button(text: project_ref, title: "Copy reference to clipboard", placement: "left") = clipboard_button(text: project_ref, title: "Copy reference to clipboard", placement: "left")
:javascript %script.js-sidebar-options{ type: "application/json" }= issuable_sidebar_options(issuable, can_edit_issuable).to_json.html_safe
gl.sidebarOptions = {
endpoint: "#{issuable_json_path(issuable)}?basic=true",
editable: #{can_edit_issuable ? true : false},
currentUser: #{current_user.to_json(only: [:username, :id, :name], methods: :avatar_url)},
rootPath: "#{root_path}"
};
new MilestoneSelect('{"full_path":"#{@project.full_path}"}');
new LabelsSelect();
new WeightSelect();
new IssuableContext('#{escape_javascript(current_user.to_json(only: [:username, :id, :name]))}');
gl.Subscription.bindAll('.subscription');
new gl.DueDateSelectors();
window.sidebar = new Sidebar();
...@@ -22,5 +22,4 @@ ...@@ -22,5 +22,4 @@
= link_to "sign in", new_session_path(:user, redirect_to_referer: 'yes') = link_to "sign in", new_session_path(:user, redirect_to_referer: 'yes')
to comment to comment
:javascript %script.js-notes-data{ type: "application/json" }= initial_notes_data(autocomplete).to_json.html_safe
var notes = new Notes("#{notes_url}", #{@notes.map(&:id).to_json}, #{Time.now.to_i}, "#{diff_view}", #{autocomplete})
- remote = local_assigns.fetch(:remote, false)
- link_project = local_assigns.fetch(:link_project, false) - link_project = local_assigns.fetch(:link_project, false)
.snippets-list-holder .snippets-list-holder
...@@ -8,7 +7,4 @@ ...@@ -8,7 +7,4 @@
%li %li
.nothing-here-block Nothing here. .nothing-here-block Nothing here.
= paginate @snippets, theme: 'gitlab', remote: remote = paginate @snippets, theme: 'gitlab'
:javascript
gl.SnippetsList();
---
title: Fix CSS for mini graph with downstream pipeline
merge_request:
author:
---
title: Add admin application setting to allow group owners to manage LDAP.
merge_request: 2529
author:
---
title: Adds lower bound to pull mirror scheduling feature
merge_request: 2366
author:
---
title: Renamed board to boards in new project sidebar
merge_request:
author:
---
title: Add warning and option toggle when rebuilding authorized_keys.
merge_request: 2508
author:
---
title: Fixed issue boards focus mode when new navigation is turned on
merge_request:
author:
---
title: Fix vertical alignment in firefox and safari for pipeline mini graph
merge_request:
author:
---
title: Fix crash on /help/ui
merge_request:
author:
---
title: Pending delete projects should not show in deploy keys.
merge_request: 13088
author:
---
title: Fixes 500 error caused by pending delete projects in admin dashboard
merge_request: 13067
author:
---
title: Allow admin to read_users_list even if it's restricted
merge_request: 13066
author:
---
title: Add instrumentation to MarkupHelper#link_to_gfm
merge_request: 13069
author:
---
title: Fix job merge request link to a forked source project
merge_request: 12965
author:
--- ---
title: Fix Rebasing not working with Merge Requests title: Merge issuable "reopened" state into "opened"
merge_request: merge_request:
author: author:
---
title: Fix sizing of custom header logo in new navigation
merge_request:
author:
...@@ -57,8 +57,11 @@ var config = { ...@@ -57,8 +57,11 @@ var config = {
notebook_viewer: './blob/notebook_viewer.js', notebook_viewer: './blob/notebook_viewer.js',
pdf_viewer: './blob/pdf_viewer.js', pdf_viewer: './blob/pdf_viewer.js',
pipelines: './pipelines/pipelines_bundle.js', pipelines: './pipelines/pipelines_bundle.js',
pipelines_details: './pipelines/pipeline_details_bundle.js', pipelines_charts: './pipelines/pipelines_charts.js',
pipelines_details: './pipelines/pipeline_details_bundle.js',
pipelines_times: './pipelines/pipelines_times.js',
profile: './profile/profile_bundle.js', profile: './profile/profile_bundle.js',
project_new: './projects/project_new.js',
prometheus_metrics: './prometheus_metrics', prometheus_metrics: './prometheus_metrics',
protected_branches: './protected_branches', protected_branches: './protected_branches',
ee_protected_branches: './protected_branches/ee', ee_protected_branches: './protected_branches/ee',
......
class CreateCiPipelineVariables < ActiveRecord::Migration
DOWNTIME = false
def up
create_table :ci_pipeline_variables 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_id, null: false
end
add_index :ci_pipeline_variables, [:pipeline_id, :key], unique: true
end
def down
drop_table :ci_pipeline_variables
end
end
class AddForeignKeyToCiPipelineVariables < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_foreign_key(:ci_pipeline_variables, :ci_pipelines, column: :pipeline_id)
end
def down
remove_foreign_key(:ci_pipeline_variables, column: :pipeline_id)
end
end
class AddRestrictGroupOwnersToAdminsOptionToApplicationSettings < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_column_with_default(:application_settings, :allow_group_owners_to_manage_ldap, :boolean, default: true)
end
def down
remove_column(:application_settings, :allow_group_owners_to_manage_ldap)
end
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class MergeIssuableReopenedIntoOpenedState < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
class Issue < ActiveRecord::Base
self.table_name = 'issues'
include EachBatch
end
class MergeRequest < ActiveRecord::Base
self.table_name = 'merge_requests'
include EachBatch
end
def up
[Issue, MergeRequest].each do |model|
say "Changing #{model.table_name}.state from 'reopened' to 'opened'"
model.where(state: 'reopened').each_batch do |batch|
batch.update_all(state: 'opened')
end
end
end
end
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
# #
# 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.
ActiveRecord::Schema.define(version: 20170725145659) do ActiveRecord::Schema.define(version: 20170726111039) do
# 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"
...@@ -149,6 +149,7 @@ ActiveRecord::Schema.define(version: 20170725145659) do ...@@ -149,6 +149,7 @@ ActiveRecord::Schema.define(version: 20170725145659) do
t.string "slack_app_verification_token" t.string "slack_app_verification_token"
t.integer "performance_bar_allowed_group_id" t.integer "performance_bar_allowed_group_id"
t.boolean "password_authentication_enabled" t.boolean "password_authentication_enabled"
t.boolean "allow_group_owners_to_manage_ldap", default: true, null: false
end end
create_table "approvals", force: :cascade do |t| create_table "approvals", force: :cascade do |t|
...@@ -356,6 +357,17 @@ ActiveRecord::Schema.define(version: 20170725145659) do ...@@ -356,6 +357,17 @@ ActiveRecord::Schema.define(version: 20170725145659) do
add_index "ci_pipeline_schedules", ["next_run_at", "active"], name: "index_ci_pipeline_schedules_on_next_run_at_and_active", using: :btree add_index "ci_pipeline_schedules", ["next_run_at", "active"], name: "index_ci_pipeline_schedules_on_next_run_at_and_active", using: :btree
add_index "ci_pipeline_schedules", ["project_id"], name: "index_ci_pipeline_schedules_on_project_id", using: :btree add_index "ci_pipeline_schedules", ["project_id"], name: "index_ci_pipeline_schedules_on_project_id", using: :btree
create_table "ci_pipeline_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_id", null: false
end
add_index "ci_pipeline_variables", ["pipeline_id", "key"], name: "index_ci_pipeline_variables_on_pipeline_id_and_key", unique: true, using: :btree
create_table "ci_pipelines", force: :cascade do |t| create_table "ci_pipelines", force: :cascade do |t|
t.string "ref" t.string "ref"
t.string "sha" t.string "sha"
...@@ -1937,6 +1949,7 @@ ActiveRecord::Schema.define(version: 20170725145659) do ...@@ -1937,6 +1949,7 @@ ActiveRecord::Schema.define(version: 20170725145659) do
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_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_pipelines", "ci_pipeline_schedules", column: "pipeline_schedule_id", name: "fk_3d34ab2e06", on_delete: :nullify add_foreign_key "ci_pipelines", "ci_pipeline_schedules", column: "pipeline_schedule_id", name: "fk_3d34ab2e06", on_delete: :nullify
add_foreign_key "ci_pipelines", "ci_pipelines", column: "auto_canceled_by_id", name: "fk_262d4c2d19", on_delete: :nullify add_foreign_key "ci_pipelines", "ci_pipelines", column: "auto_canceled_by_id", name: "fk_262d4c2d19", on_delete: :nullify
add_foreign_key "ci_pipelines", "projects", name: "fk_86635dbd80", on_delete: :cascade add_foreign_key "ci_pipelines", "projects", name: "fk_86635dbd80", on_delete: :cascade
......
...@@ -33,7 +33,8 @@ describe Admin::ApplicationSettingsController do # rubocop:disable RSpec/FilePat ...@@ -33,7 +33,8 @@ describe Admin::ApplicationSettingsController do # rubocop:disable RSpec/FilePat
slack_app_enabled: true, slack_app_enabled: true,
slack_app_id: 'slack_app_id', slack_app_id: 'slack_app_id',
slack_app_secret: 'slack_app_secret', slack_app_secret: 'slack_app_secret',
slack_app_verification_token: 'slack_app_verification_token' slack_app_verification_token: 'slack_app_verification_token',
allow_group_owners_to_manage_ldap: false
} }
put :update, application_setting: settings put :update, application_setting: settings
......
FactoryGirl.define do
factory :ci_pipeline_variable, class: Ci::PipelineVariable do
sequence(:key) { |n| "VARIABLE_#{n}" }
value 'VARIABLE_VALUE'
pipeline factory: :ci_empty_pipeline
end
end
...@@ -17,12 +17,8 @@ FactoryGirl.define do ...@@ -17,12 +17,8 @@ FactoryGirl.define do
closed_at Time.now closed_at Time.now
end end
trait :reopened do
state :reopened
end
factory :closed_issue, traits: [:closed] factory :closed_issue, traits: [:closed]
factory :reopened_issue, traits: [:reopened] factory :reopened_issue, traits: [:opened]
factory :labeled_issue do factory :labeled_issue do
transient do transient do
......
...@@ -44,10 +44,6 @@ FactoryGirl.define do ...@@ -44,10 +44,6 @@ FactoryGirl.define do
state :opened state :opened
end end
trait :reopened do
state :reopened
end
trait :locked do trait :locked do
state :locked state :locked
end end
...@@ -80,7 +76,7 @@ FactoryGirl.define do ...@@ -80,7 +76,7 @@ FactoryGirl.define do
factory :merged_merge_request, traits: [:merged] factory :merged_merge_request, traits: [:merged]
factory :closed_merge_request, traits: [:closed] factory :closed_merge_request, traits: [:closed]
factory :reopened_merge_request, traits: [:reopened] factory :reopened_merge_request, traits: [:opened]
factory :merge_request_with_diffs, traits: [:with_diffs] factory :merge_request_with_diffs, traits: [:with_diffs]
factory :merge_request_with_approver, traits: [:with_approver] factory :merge_request_with_approver, traits: [:with_approver]
factory :merge_request_with_diff_notes do factory :merge_request_with_diff_notes do
......
...@@ -3,56 +3,80 @@ FactoryGirl.define do ...@@ -3,56 +3,80 @@ FactoryGirl.define do
name name
project project
after(:build) do |protected_branch|
protected_branch.push_access_levels.new(access_level: Gitlab::Access::MASTER)
protected_branch.merge_access_levels.new(access_level: Gitlab::Access::MASTER)
end
transient do transient do
# EE
authorize_user_to_push nil authorize_user_to_push nil
authorize_user_to_merge nil authorize_user_to_merge nil
authorize_group_to_push nil authorize_group_to_push nil
authorize_group_to_merge nil authorize_group_to_merge nil
end
trait :remove_default_access_levels do default_push_level true
after(:build) do |protected_branch| default_merge_level true
protected_branch.push_access_levels = [] default_access_level true
protected_branch.merge_access_levels = []
end
end end
trait :developers_can_push do trait :developers_can_push do
after(:create) do |protected_branch| transient do
protected_branch.push_access_levels.create!(access_level: Gitlab::Access::DEVELOPER) default_push_level false
end
after(:build) do |protected_branch|
protected_branch.push_access_levels.new(access_level: Gitlab::Access::DEVELOPER)
end end
end end
trait :developers_can_merge do trait :developers_can_merge do
after(:create) do |protected_branch| transient do
protected_branch.merge_access_levels.create!(access_level: Gitlab::Access::DEVELOPER) default_merge_level false
end
after(:build) do |protected_branch|
protected_branch.merge_access_levels.new(access_level: Gitlab::Access::DEVELOPER)
end end
end end
trait :no_one_can_push do trait :no_one_can_push do
after(:create) do |protected_branch| transient do
protected_branch.push_access_levels.create!(access_level: Gitlab::Access::NO_ACCESS) default_push_level false
end
after(:build) do |protected_branch|
protected_branch.push_access_levels.new(access_level: Gitlab::Access::NO_ACCESS)
end end
end end
trait :masters_can_push do trait :masters_can_push do
after(:create) do |protected_branch| transient do
protected_branch.push_access_levels.create!(access_level: Gitlab::Access::MASTER) default_push_level false
end
after(:build) do |protected_branch|
protected_branch.push_access_levels.new(access_level: Gitlab::Access::MASTER)
end end
end end
after(:create) do |protected_branch, evaluator| after(:build) do |protected_branch, evaluator|
protected_branch.push_access_levels.create!(user: evaluator.authorize_user_to_push) if evaluator.authorize_user_to_push # EE
protected_branch.merge_access_levels.create!(user: evaluator.authorize_user_to_merge) if evaluator.authorize_user_to_merge if user = evaluator.authorize_user_to_push
protected_branch.push_access_levels.new(user: user)
end
if user = evaluator.authorize_user_to_merge
protected_branch.merge_access_levels.new(user: user)
end
if group = evaluator.authorize_group_to_push
protected_branch.push_access_levels.new(group: group)
end
if group = evaluator.authorize_group_to_merge
protected_branch.merge_access_levels.new(group: group)
end
next unless protected_branch.merge_access_levels.empty?
protected_branch.push_access_levels.create!(group: evaluator.authorize_group_to_push) if evaluator.authorize_group_to_push if evaluator.default_access_level && evaluator.default_push_level
protected_branch.merge_access_levels.create!(group: evaluator.authorize_group_to_merge) if evaluator.authorize_group_to_merge protected_branch.push_access_levels.new(access_level: Gitlab::Access::MASTER)
end
if evaluator.default_access_level && evaluator.default_merge_level
protected_branch.merge_access_levels.new(access_level: Gitlab::Access::MASTER)
end
end end
end end
end end
...@@ -3,42 +3,56 @@ FactoryGirl.define do ...@@ -3,42 +3,56 @@ FactoryGirl.define do
name name
project project
after(:build) do |protected_tag|
protected_tag.create_access_levels.new(access_level: Gitlab::Access::MASTER)
end
transient do transient do
# EE
authorize_user_to_create nil authorize_user_to_create nil
authorize_group_to_create nil authorize_group_to_create nil
end
trait :remove_default_access_levels do default_access_level true
after(:build) do |protected_tag|
protected_tag.create_access_levels = []
end
end end
trait :developers_can_create do trait :developers_can_create do
after(:create) do |protected_tag| transient do
protected_tag.create_access_levels.create!(access_level: Gitlab::Access::DEVELOPER) default_access_level false
end
after(:build) do |protected_tag|
protected_tag.create_access_levels.new(access_level: Gitlab::Access::DEVELOPER)
end end
end end
trait :no_one_can_create do trait :no_one_can_create do
after(:create) do |protected_tag| transient do
protected_tag.create_access_levels.create!(access_level: Gitlab::Access::NO_ACCESS) default_access_level false
end
after(:build) do |protected_tag|
protected_tag.create_access_levels.new(access_level: Gitlab::Access::NO_ACCESS)
end end
end end
trait :masters_can_create do trait :masters_can_create do
after(:create) do |protected_tag| transient do
protected_tag.create_access_levels.create!(access_level: Gitlab::Access::MASTER) default_access_level false
end
after(:build) do |protected_tag|
protected_tag.create_access_levels.new(access_level: Gitlab::Access::MASTER)
end end
end end
after(:create) do |protected_tag, evaluator| after(:build) do |protected_tag, evaluator|
protected_tag.create_access_levels.create!(user: evaluator.authorize_user_to_create) if evaluator.authorize_user_to_create # EE
protected_tag.create_access_levels.create!(group: evaluator.authorize_group_to_create) if evaluator.authorize_group_to_create if evaluator.authorize_user_to_create
protected_tag.create_access_levels.new(user: evaluator.authorize_user_to_create)
end
if evaluator.authorize_group_to_create
protected_tag.create_access_levels.new(group: evaluator.authorize_group_to_create)
end
if evaluator.default_access_level
protected_tag.create_access_levels.new(access_level: Gitlab::Access::MASTER)
end
end end
end end
end end
...@@ -29,6 +29,29 @@ feature 'Admin updates settings' do ...@@ -29,6 +29,29 @@ feature 'Admin updates settings' do
expect(find('#application_setting_visibility_level_20')).not_to be_checked expect(find('#application_setting_visibility_level_20')).not_to be_checked
end end
describe 'LDAP settings' do
context 'with LDAP enabled' do
scenario 'Change allow group owners to manage ldap' do
allow(Gitlab::LDAP::Config).to receive(:enabled?).and_return(true)
visit admin_application_settings_path
find('#application_setting_allow_group_owners_to_manage_ldap').set(false)
click_button 'Save'
expect(page).to have_content('Application settings saved successfully')
expect(find('#application_setting_allow_group_owners_to_manage_ldap')).not_to be_checked
end
end
context 'with LDAP disabled' do
scenario 'Does not show option to allow group owners to manage ldap' do
visit admin_application_settings_path
expect(page).not_to have_css('#application_setting_allow_group_owners_to_manage_ldap')
end
end
end
scenario 'Change application settings' do scenario 'Change application settings' do
uncheck 'Gravatar enabled' uncheck 'Gravatar enabled'
fill_in 'Home page URL', with: 'https://about.gitlab.com/' fill_in 'Home page URL', with: 'https://about.gitlab.com/'
......
...@@ -9,6 +9,31 @@ feature 'Edit group settings' do ...@@ -9,6 +9,31 @@ feature 'Edit group settings' do
sign_in(user) sign_in(user)
end end
describe 'navbar' do
context 'with LDAP enabled' do
before do
allow_any_instance_of(Group).to receive(:ldap_synced?).and_return(true)
allow(Gitlab::LDAP::Config).to receive(:enabled?).and_return(true)
end
scenario 'is able to navigate to LDAP group section' do
visit edit_group_path(group)
expect(find('div.sub-nav')).to have_content('LDAP Group')
end
context 'with owners not being able to manage LDAP' do
scenario 'is not able to navigate to LDAP group section' do
stub_application_setting(allow_group_owners_to_manage_ldap: false)
visit edit_group_path(group)
expect(find('div.sub-nav')).not_to have_content('LDAP Group')
end
end
end
end
describe 'when the group path is changed' do describe 'when the group path is changed' do
let(:new_group_path) { 'bar' } let(:new_group_path) { 'bar' }
let(:old_group_full_path) { "/#{group.path}" } let(:old_group_full_path) { "/#{group.path}" }
......
...@@ -26,6 +26,18 @@ feature 'Groups > Members > Master/Owner can override LDAP access levels' do ...@@ -26,6 +26,18 @@ feature 'Groups > Members > Master/Owner can override LDAP access levels' do
expect(page).not_to have_button 'Edit permissions' expect(page).not_to have_button 'Edit permissions'
end end
scenario 'owner cannot override LDAP access level', js: true do
stub_application_setting(allow_group_owners_to_manage_ldap: false)
visit group_group_members_path(group)
within "#group_member_#{ldap_member.id}" do
expect(page).not_to have_content 'LDAP'
expect(page).not_to have_button 'Guest'
expect(page).not_to have_button 'Edit permissions'
end
end
scenario 'owner can override LDAP access level', js: true do scenario 'owner can override LDAP access level', js: true do
ldap_override_message = 'John Doe is currently an LDAP user. Editing their permissions will override the settings from the LDAP group sync.' ldap_override_message = 'John Doe is currently an LDAP user. Editing their permissions will override the settings from the LDAP group sync.'
......
require 'spec_helper'
feature 'Project remote mirror', feature: true do
let(:project) { create(:project, :remote_mirror) }
let(:remote_mirror) { project.remote_mirrors.first }
let(:user) { create(:user) }
describe 'On a project', js: true do
before do
project.team << [user, :master]
sign_in user
end
context 'when last_error is present but last_update_at is not' do
it 'renders error message without timstamp' do
remote_mirror.update_attributes(last_error: 'Some new error', last_update_at: nil)
visit project_mirror_path(project)
expect(page).to have_content('The remote repository failed to update.')
end
end
context 'when last_error and last_update_at are present' do
it 'renders error message with timestamp' do
remote_mirror.update_attributes(last_error: 'Some new error', last_update_at: Time.now - 5.minutes)
visit project_mirror_path(project)
expect(page).to have_content('The remote repository failed to update 5 minutes ago.')
end
end
end
end
...@@ -107,14 +107,6 @@ describe Banzai::Filter::IssuableStateFilter do ...@@ -107,14 +107,6 @@ describe Banzai::Filter::IssuableStateFilter do
expect(doc.css('a').last.text).to eq(issue.to_reference) expect(doc.css('a').last.text).to eq(issue.to_reference)
end end
it 'ignores reopened issue references' do
issue = create_issue(:reopened)
link = create_link(issue.to_reference, issue: issue.id, reference_type: 'issue')
doc = filter(link, context)
expect(doc.css('a').last.text).to eq(issue.to_reference)
end
it 'appends state to closed issue references' do it 'appends state to closed issue references' do
link = create_link(closed_issue.to_reference, issue: closed_issue.id, reference_type: 'issue') link = create_link(closed_issue.to_reference, issue: closed_issue.id, reference_type: 'issue')
doc = filter(link, context) doc = filter(link, context)
...@@ -139,7 +131,7 @@ describe Banzai::Filter::IssuableStateFilter do ...@@ -139,7 +131,7 @@ describe Banzai::Filter::IssuableStateFilter do
end end
it 'ignores reopened merge request references' do it 'ignores reopened merge request references' do
merge_request = create_merge_request(:reopened) merge_request = create_merge_request(:opened)
link = create_link( link = create_link(
merge_request.to_reference, merge_request.to_reference,
......
...@@ -556,7 +556,7 @@ describe Gitlab::GitAccess do ...@@ -556,7 +556,7 @@ describe Gitlab::GitAccess do
[%w(feature exact), ['feat*', 'wildcard']].each do |protected_branch_name, protected_branch_type| [%w(feature exact), ['feat*', 'wildcard']].each do |protected_branch_name, protected_branch_type|
context do context do
before do before do
create(:protected_branch, :remove_default_access_levels, :masters_can_push, name: protected_branch_name, project: project) create(:protected_branch, :masters_can_push, name: protected_branch_name, project: project)
end end
run_permission_checks(permissions_matrix) run_permission_checks(permissions_matrix)
...@@ -564,7 +564,7 @@ describe Gitlab::GitAccess do ...@@ -564,7 +564,7 @@ describe Gitlab::GitAccess do
context "when developers are allowed to push into the #{protected_branch_type} protected branch" do context "when developers are allowed to push into the #{protected_branch_type} protected branch" do
before do before do
create(:protected_branch, :remove_default_access_levels, :masters_can_push, :developers_can_push, name: protected_branch_name, project: project) create(:protected_branch, :masters_can_push, :developers_can_push, name: protected_branch_name, project: project)
end end
run_permission_checks(permissions_matrix.deep_merge(developer: { push_protected_branch: true, push_all: true, merge_into_protected_branch: true })) run_permission_checks(permissions_matrix.deep_merge(developer: { push_protected_branch: true, push_all: true, merge_into_protected_branch: true }))
...@@ -572,7 +572,7 @@ describe Gitlab::GitAccess do ...@@ -572,7 +572,7 @@ describe Gitlab::GitAccess do
context "developers are allowed to merge into the #{protected_branch_type} protected branch" do context "developers are allowed to merge into the #{protected_branch_type} protected branch" do
before do before do
create(:protected_branch, :remove_default_access_levels, :masters_can_push, :developers_can_merge, name: protected_branch_name, project: project) create(:protected_branch, :masters_can_push, :developers_can_merge, name: protected_branch_name, project: project)
end end
context "when a merge request exists for the given source/target branch" do context "when a merge request exists for the given source/target branch" do
...@@ -601,7 +601,7 @@ describe Gitlab::GitAccess do ...@@ -601,7 +601,7 @@ describe Gitlab::GitAccess do
context "when developers are allowed to push and merge into the #{protected_branch_type} protected branch" do context "when developers are allowed to push and merge into the #{protected_branch_type} protected branch" do
before do before do
create(:protected_branch, :remove_default_access_levels, :masters_can_push, :developers_can_merge, :developers_can_push, name: protected_branch_name, project: project) create(:protected_branch, :masters_can_push, :developers_can_merge, :developers_can_push, name: protected_branch_name, project: project)
end end
run_permission_checks(permissions_matrix.deep_merge(developer: { push_protected_branch: true, push_all: true, merge_into_protected_branch: true })) run_permission_checks(permissions_matrix.deep_merge(developer: { push_protected_branch: true, push_all: true, merge_into_protected_branch: true }))
...@@ -612,7 +612,7 @@ describe Gitlab::GitAccess do ...@@ -612,7 +612,7 @@ describe Gitlab::GitAccess do
let(:user) { create(:user) } let(:user) { create(:user) }
before do before do
create(:protected_branch, :remove_default_access_levels, authorize_user_to_push: user, name: protected_branch_name, project: project) create(:protected_branch, authorize_user_to_push: user, name: protected_branch_name, project: project)
end end
run_permission_checks(permissions_matrix.deep_merge(developer: { push_protected_branch: true, push_all: true, merge_into_protected_branch: true }, run_permission_checks(permissions_matrix.deep_merge(developer: { push_protected_branch: true, push_all: true, merge_into_protected_branch: true },
...@@ -625,7 +625,7 @@ describe Gitlab::GitAccess do ...@@ -625,7 +625,7 @@ describe Gitlab::GitAccess do
before do before do
create(:merge_request, source_project: project, source_branch: unprotected_branch, target_branch: 'feature', state: 'locked', in_progress_merge_commit_sha: merge_into_protected_branch) create(:merge_request, source_project: project, source_branch: unprotected_branch, target_branch: 'feature', state: 'locked', in_progress_merge_commit_sha: merge_into_protected_branch)
create(:protected_branch, :remove_default_access_levels, authorize_user_to_merge: user, name: protected_branch_name, project: project) create(:protected_branch, authorize_user_to_merge: user, name: protected_branch_name, project: project)
end end
run_permission_checks(permissions_matrix.deep_merge(admin: { push_protected_branch: false, push_all: false, merge_into_protected_branch: true }, run_permission_checks(permissions_matrix.deep_merge(admin: { push_protected_branch: false, push_all: false, merge_into_protected_branch: true },
...@@ -640,7 +640,7 @@ describe Gitlab::GitAccess do ...@@ -640,7 +640,7 @@ describe Gitlab::GitAccess do
before do before do
create(:merge_request, source_project: project, source_branch: unprotected_branch, target_branch: 'feature', state: 'locked', in_progress_merge_commit_sha: merge_into_protected_branch) create(:merge_request, source_project: project, source_branch: unprotected_branch, target_branch: 'feature', state: 'locked', in_progress_merge_commit_sha: merge_into_protected_branch)
create(:protected_branch, :remove_default_access_levels, authorize_user_to_push: user, authorize_user_to_merge: user, name: protected_branch_name, project: project) create(:protected_branch, authorize_user_to_push: user, authorize_user_to_merge: user, name: protected_branch_name, project: project)
end end
run_permission_checks(permissions_matrix.deep_merge(developer: { push_protected_branch: true, push_all: true, merge_into_protected_branch: true }, run_permission_checks(permissions_matrix.deep_merge(developer: { push_protected_branch: true, push_all: true, merge_into_protected_branch: true },
...@@ -656,7 +656,7 @@ describe Gitlab::GitAccess do ...@@ -656,7 +656,7 @@ describe Gitlab::GitAccess do
before do before do
group.add_master(user) group.add_master(user)
create(:protected_branch, :remove_default_access_levels, authorize_group_to_push: group, name: protected_branch_name, project: project) create(:protected_branch, authorize_group_to_push: group, name: protected_branch_name, project: project)
end end
permissions = permissions_matrix.except(:admin).deep_merge(developer: { push_protected_branch: true, push_all: true, merge_into_protected_branch: true }, permissions = permissions_matrix.except(:admin).deep_merge(developer: { push_protected_branch: true, push_all: true, merge_into_protected_branch: true },
...@@ -673,7 +673,7 @@ describe Gitlab::GitAccess do ...@@ -673,7 +673,7 @@ describe Gitlab::GitAccess do
before do before do
group.add_master(user) group.add_master(user)
create(:merge_request, source_project: project, source_branch: unprotected_branch, target_branch: 'feature', state: 'locked', in_progress_merge_commit_sha: merge_into_protected_branch) create(:merge_request, source_project: project, source_branch: unprotected_branch, target_branch: 'feature', state: 'locked', in_progress_merge_commit_sha: merge_into_protected_branch)
create(:protected_branch, :remove_default_access_levels, authorize_group_to_merge: group, name: protected_branch_name, project: project) create(:protected_branch, authorize_group_to_merge: group, name: protected_branch_name, project: project)
end end
permissions = permissions_matrix.except(:admin).deep_merge(master: { push_protected_branch: false, push_all: false, merge_into_protected_branch: true }, permissions = permissions_matrix.except(:admin).deep_merge(master: { push_protected_branch: false, push_all: false, merge_into_protected_branch: true },
...@@ -691,7 +691,7 @@ describe Gitlab::GitAccess do ...@@ -691,7 +691,7 @@ describe Gitlab::GitAccess do
before do before do
group.add_master(user) group.add_master(user)
create(:merge_request, source_project: project, source_branch: unprotected_branch, target_branch: 'feature', state: 'locked', in_progress_merge_commit_sha: merge_into_protected_branch) create(:merge_request, source_project: project, source_branch: unprotected_branch, target_branch: 'feature', state: 'locked', in_progress_merge_commit_sha: merge_into_protected_branch)
create(:protected_branch, :remove_default_access_levels, authorize_group_to_push: group, authorize_group_to_merge: group, name: protected_branch_name, project: project) create(:protected_branch, authorize_group_to_push: group, authorize_group_to_merge: group, name: protected_branch_name, project: project)
end end
permissions = permissions_matrix.except(:admin).deep_merge(developer: { push_protected_branch: true, push_all: true, merge_into_protected_branch: true }, permissions = permissions_matrix.except(:admin).deep_merge(developer: { push_protected_branch: true, push_all: true, merge_into_protected_branch: true },
...@@ -704,7 +704,7 @@ describe Gitlab::GitAccess do ...@@ -704,7 +704,7 @@ describe Gitlab::GitAccess do
context "when no one is allowed to push to the #{protected_branch_name} protected branch" do context "when no one is allowed to push to the #{protected_branch_name} protected branch" do
before do before do
create(:protected_branch, :remove_default_access_levels, :no_one_can_push, name: protected_branch_name, project: project) create(:protected_branch, :no_one_can_push, name: protected_branch_name, project: project)
end end
run_permission_checks(permissions_matrix.deep_merge(developer: { push_protected_branch: false, push_all: false, merge_into_protected_branch: false }, run_permission_checks(permissions_matrix.deep_merge(developer: { push_protected_branch: false, push_all: false, merge_into_protected_branch: false },
......
...@@ -106,6 +106,7 @@ pipelines: ...@@ -106,6 +106,7 @@ pipelines:
- statuses - statuses
- builds - builds
- trigger_requests - trigger_requests
- variables
- auto_canceled_by - auto_canceled_by
- auto_canceled_pipelines - auto_canceled_pipelines
- auto_canceled_jobs - auto_canceled_jobs
...@@ -120,6 +121,8 @@ pipelines: ...@@ -120,6 +121,8 @@ pipelines:
- sourced_pipelines - sourced_pipelines
- triggered_by_pipeline - triggered_by_pipeline
- triggered_pipelines - triggered_pipelines
pipeline_variables:
- pipeline
stages: stages:
- project - project
- pipeline - pipeline
......
...@@ -63,14 +63,14 @@ describe Burndown do ...@@ -63,14 +63,14 @@ describe Burndown do
expect(burndown).to be_accurate expect(burndown).to be_accurate
end end
context "when all closed and reopened issues does not have closed_at" do context "when all closed issues does not have closed_at" do
before do before do
milestone.issues.update_all(closed_at: nil) milestone.issues.update_all(closed_at: nil)
end end
it "considers closed_at as milestone start date" do it "considers closed_at as milestone start date" do
expect(subject).to eq([ expect(subject).to eq([
["2017-03-01", 15, 30], ["2017-03-01", 27, 54],
["2017-03-02", 27, 54], ["2017-03-02", 27, 54],
["2017-03-03", 27, 54], ["2017-03-03", 27, 54],
["2017-03-04", 27, 54], ["2017-03-04", 27, 54],
...@@ -85,7 +85,7 @@ describe Burndown do ...@@ -85,7 +85,7 @@ describe Burndown do
end end
end end
context "when one or more closed or reopened issues does not have closed_at" do context "when one or more closed issues does not have closed_at" do
before do before do
milestone.issues.closed.first.update(closed_at: nil) milestone.issues.closed.first.update(closed_at: nil)
end end
......
...@@ -1487,6 +1487,12 @@ describe Ci::Build do ...@@ -1487,6 +1487,12 @@ describe Ci::Build do
it { is_expected.to include(predefined_trigger_variable) } it { is_expected.to include(predefined_trigger_variable) }
end end
context 'when pipeline has a variable' do
let!(:pipeline_variable) { create(:ci_pipeline_variable, pipeline: pipeline) }
it { is_expected.to include(pipeline_variable.to_runner_variable) }
end
context 'when a job was triggered by a pipeline schedule' do context 'when a job was triggered by a pipeline schedule' do
let(:pipeline_schedule) { create(:ci_pipeline_schedule, project: project) } let(:pipeline_schedule) { create(:ci_pipeline_schedule, project: project) }
......
...@@ -17,6 +17,7 @@ describe Ci::Pipeline do ...@@ -17,6 +17,7 @@ describe Ci::Pipeline do
it { is_expected.to have_many(:statuses) } it { is_expected.to have_many(:statuses) }
it { is_expected.to have_many(:trigger_requests) } it { is_expected.to have_many(:trigger_requests) }
it { is_expected.to have_many(:variables) }
it { is_expected.to have_many(:builds) } it { is_expected.to have_many(:builds) }
it { is_expected.to have_many(:auto_canceled_pipelines) } it { is_expected.to have_many(:auto_canceled_pipelines) }
it { is_expected.to have_many(:auto_canceled_jobs) } it { is_expected.to have_many(:auto_canceled_jobs) }
......
require 'spec_helper'
describe Ci::PipelineVariable, models: true do
subject { build(:ci_pipeline_variable) }
it { is_expected.to include_module(HasVariable) }
it { is_expected.to validate_uniqueness_of(:key).scoped_to(:pipeline_id) }
end
...@@ -16,8 +16,8 @@ describe ProtectedBranch do ...@@ -16,8 +16,8 @@ describe ProtectedBranch do
context "while checking uniqueness of a role-based #{human_association_name}" do context "while checking uniqueness of a role-based #{human_association_name}" do
it "allows a single #{human_association_name} for a role (per protected branch)" do it "allows a single #{human_association_name} for a role (per protected branch)" do
first_protected_branch = create(:protected_branch, :remove_default_access_levels) first_protected_branch = create(:protected_branch, default_access_level: false)
second_protected_branch = create(:protected_branch, :remove_default_access_levels) second_protected_branch = create(:protected_branch, default_access_level: false)
first_protected_branch.send(association_name) << build(factory_name, access_level: Gitlab::Access::MASTER) first_protected_branch.send(association_name) << build(factory_name, access_level: Gitlab::Access::MASTER)
second_protected_branch.send(association_name) << build(factory_name, access_level: Gitlab::Access::MASTER) second_protected_branch.send(association_name) << build(factory_name, access_level: Gitlab::Access::MASTER)
...@@ -31,7 +31,7 @@ describe ProtectedBranch do ...@@ -31,7 +31,7 @@ describe ProtectedBranch do
end end
it "does not count a user-based #{human_association_name} with an `access_level` set" do it "does not count a user-based #{human_association_name} with an `access_level` set" do
protected_branch = create(:protected_branch, :remove_default_access_levels) protected_branch = create(:protected_branch, default_access_level: false)
protected_branch.send(association_name) << build(factory_name, user: user, access_level: Gitlab::Access::MASTER) protected_branch.send(association_name) << build(factory_name, user: user, access_level: Gitlab::Access::MASTER)
protected_branch.send(association_name) << build(factory_name, access_level: Gitlab::Access::MASTER) protected_branch.send(association_name) << build(factory_name, access_level: Gitlab::Access::MASTER)
...@@ -41,7 +41,7 @@ describe ProtectedBranch do ...@@ -41,7 +41,7 @@ describe ProtectedBranch do
it "does not count a group-based #{human_association_name} with an `access_level` set" do it "does not count a group-based #{human_association_name} with an `access_level` set" do
group = create(:group) group = create(:group)
protected_branch = create(:protected_branch, :remove_default_access_levels) protected_branch = create(:protected_branch, default_access_level: false)
protected_branch.send(association_name) << build(factory_name, group: group, access_level: Gitlab::Access::MASTER) protected_branch.send(association_name) << build(factory_name, group: group, access_level: Gitlab::Access::MASTER)
protected_branch.send(association_name) << build(factory_name, access_level: Gitlab::Access::MASTER) protected_branch.send(association_name) << build(factory_name, access_level: Gitlab::Access::MASTER)
...@@ -52,8 +52,8 @@ describe ProtectedBranch do ...@@ -52,8 +52,8 @@ describe ProtectedBranch do
context "while checking uniqueness of a user-based #{human_association_name}" do context "while checking uniqueness of a user-based #{human_association_name}" do
it "allows a single #{human_association_name} for a user (per protected branch)" do it "allows a single #{human_association_name} for a user (per protected branch)" do
first_protected_branch = create(:protected_branch, :remove_default_access_levels) first_protected_branch = create(:protected_branch, default_access_level: false)
second_protected_branch = create(:protected_branch, :remove_default_access_levels) second_protected_branch = create(:protected_branch, default_access_level: false)
first_protected_branch.send(association_name) << build(factory_name, user: user) first_protected_branch.send(association_name) << build(factory_name, user: user)
second_protected_branch.send(association_name) << build(factory_name, user: user) second_protected_branch.send(association_name) << build(factory_name, user: user)
...@@ -67,7 +67,7 @@ describe ProtectedBranch do ...@@ -67,7 +67,7 @@ describe ProtectedBranch do
end end
it "ignores the `access_level` while validating a user-based #{human_association_name}" do it "ignores the `access_level` while validating a user-based #{human_association_name}" do
protected_branch = create(:protected_branch, :remove_default_access_levels) protected_branch = create(:protected_branch, default_access_level: false)
protected_branch.send(association_name) << build(factory_name, access_level: Gitlab::Access::MASTER) protected_branch.send(association_name) << build(factory_name, access_level: Gitlab::Access::MASTER)
protected_branch.send(association_name) << build(factory_name, user: user, access_level: Gitlab::Access::MASTER) protected_branch.send(association_name) << build(factory_name, user: user, access_level: Gitlab::Access::MASTER)
...@@ -80,8 +80,8 @@ describe ProtectedBranch do ...@@ -80,8 +80,8 @@ describe ProtectedBranch do
let(:group) { create(:group) } let(:group) { create(:group) }
it "allows a single #{human_association_name} for a group (per protected branch)" do it "allows a single #{human_association_name} for a group (per protected branch)" do
first_protected_branch = create(:protected_branch, :remove_default_access_levels) first_protected_branch = create(:protected_branch, default_access_level: false)
second_protected_branch = create(:protected_branch, :remove_default_access_levels) second_protected_branch = create(:protected_branch, default_access_level: false)
first_protected_branch.send(association_name) << build(factory_name, group: group) first_protected_branch.send(association_name) << build(factory_name, group: group)
second_protected_branch.send(association_name) << build(factory_name, group: group) second_protected_branch.send(association_name) << build(factory_name, group: group)
...@@ -95,7 +95,7 @@ describe ProtectedBranch do ...@@ -95,7 +95,7 @@ describe ProtectedBranch do
end end
it "ignores the `access_level` while validating a group-based #{human_association_name}" do it "ignores the `access_level` while validating a group-based #{human_association_name}" do
protected_branch = create(:protected_branch, :remove_default_access_levels) protected_branch = create(:protected_branch, default_access_level: false)
protected_branch.send(association_name) << build(factory_name, access_level: Gitlab::Access::MASTER) protected_branch.send(association_name) << build(factory_name, access_level: Gitlab::Access::MASTER)
protected_branch.send(association_name) << build(factory_name, group: group, access_level: Gitlab::Access::MASTER) protected_branch.send(association_name) << build(factory_name, group: group, access_level: Gitlab::Access::MASTER)
......
...@@ -25,12 +25,22 @@ describe GroupPolicy do ...@@ -25,12 +25,22 @@ describe GroupPolicy do
let(:current_user) { owner } let(:current_user) { owner }
it { is_expected.to be_disallowed(:override_group_member) } it { is_expected.to be_disallowed(:override_group_member) }
it { is_expected.to be_allowed(:admin_ldap_group_links) }
context 'does not allow group owners to manage ldap' do
before do
stub_application_setting(allow_group_owners_to_manage_ldap: false)
end
it { is_expected.to be_disallowed(:admin_ldap_group_links) }
end
end end
context 'admin' do context 'admin' do
let(:current_user) { admin } let(:current_user) { admin }
it { is_expected.to be_disallowed(:override_group_member) } it { is_expected.to be_disallowed(:override_group_member) }
it { is_expected.to be_allowed(:admin_ldap_group_links) }
end end
end end
...@@ -43,42 +53,59 @@ describe GroupPolicy do ...@@ -43,42 +53,59 @@ describe GroupPolicy do
let(:current_user) { nil } let(:current_user) { nil }
it { is_expected.to be_disallowed(:override_group_member) } it { is_expected.to be_disallowed(:override_group_member) }
it { is_expected.to be_disallowed(:admin_ldap_group_links) }
end end
context 'guests' do context 'guests' do
let(:current_user) { guest } let(:current_user) { guest }
it { is_expected.to be_disallowed(:override_group_member) } it { is_expected.to be_disallowed(:override_group_member) }
it { is_expected.to be_disallowed(:admin_ldap_group_links) }
end end
context 'reporter' do context 'reporter' do
let(:current_user) { reporter } let(:current_user) { reporter }
it { is_expected.to be_disallowed(:override_group_member) } it { is_expected.to be_disallowed(:override_group_member) }
it { is_expected.to be_disallowed(:admin_ldap_group_links) }
end end
context 'developer' do context 'developer' do
let(:current_user) { developer } let(:current_user) { developer }
it { is_expected.to be_disallowed(:override_group_member) } it { is_expected.to be_disallowed(:override_group_member) }
it { is_expected.to be_disallowed(:admin_ldap_group_links) }
end end
context 'master' do context 'master' do
let(:current_user) { master } let(:current_user) { master }
it { is_expected.to be_disallowed(:override_group_member) } it { is_expected.to be_disallowed(:override_group_member) }
it { is_expected.to be_disallowed(:admin_ldap_group_links) }
end end
context 'owner' do context 'owner' do
let(:current_user) { owner } let(:current_user) { owner }
it { is_expected.to be_allowed(:override_group_member) } context 'allow group owners to manage ldap' do
it { is_expected.to be_allowed(:override_group_member) }
end
context 'does not allow group owners to manage ldap' do
before do
stub_application_setting(allow_group_owners_to_manage_ldap: false)
end
it { is_expected.to be_disallowed(:override_group_member) }
it { is_expected.to be_disallowed(:admin_ldap_group_links) }
end
end end
context 'admin' do context 'admin' do
let(:current_user) { admin } let(:current_user) { admin }
it { is_expected.to be_allowed(:override_group_member) } it { is_expected.to be_allowed(:override_group_member) }
it { is_expected.to be_allowed(:admin_ldap_group_links) }
end end
end end
end end
...@@ -1263,7 +1263,7 @@ describe API::Issues do ...@@ -1263,7 +1263,7 @@ describe API::Issues do
put api("/projects/#{project.id}/issues/#{closed_issue.iid}", user), state_event: 'reopen' put api("/projects/#{project.id}/issues/#{closed_issue.iid}", user), state_event: 'reopen'
expect(response).to have_http_status(200) expect(response).to have_http_status(200)
expect(json_response['state']).to eq 'reopened' expect(json_response['state']).to eq 'opened'
end end
context 'when an admin or owner makes the request' do context 'when an admin or owner makes the request' do
......
...@@ -22,6 +22,7 @@ describe API::Triggers do ...@@ -22,6 +22,7 @@ describe API::Triggers do
before do before do
stub_ci_pipeline_to_return_yaml_file stub_ci_pipeline_to_return_yaml_file
trigger.update(owner: user)
end end
context 'Handles errors' do context 'Handles errors' do
...@@ -55,8 +56,7 @@ describe API::Triggers do ...@@ -55,8 +56,7 @@ describe API::Triggers do
post api("/projects/#{project.id}/trigger/pipeline"), options.merge(ref: 'other-branch') post api("/projects/#{project.id}/trigger/pipeline"), options.merge(ref: 'other-branch')
expect(response).to have_http_status(400) expect(response).to have_http_status(400)
expect(json_response['message']['base']) expect(json_response['message']).to eq('base' => ["Reference not found"])
.to contain_exactly('Reference not found')
end end
context 'Validates variables' do context 'Validates variables' do
...@@ -82,7 +82,7 @@ describe API::Triggers do ...@@ -82,7 +82,7 @@ describe API::Triggers do
post api("/projects/#{project.id}/trigger/pipeline"), options.merge(variables: variables, ref: 'master') post api("/projects/#{project.id}/trigger/pipeline"), options.merge(variables: variables, ref: 'master')
expect(response).to have_http_status(201) expect(response).to have_http_status(201)
expect(pipeline.builds.reload.first.trigger_request.variables).to eq(variables) expect(pipeline.variables.map { |v| { v.key => v.value } }.last).to eq(variables)
end end
end end
end end
......
...@@ -1116,7 +1116,7 @@ describe API::V3::Issues do ...@@ -1116,7 +1116,7 @@ describe API::V3::Issues do
put v3_api("/projects/#{project.id}/issues/#{closed_issue.id}", user), state_event: 'reopen' put v3_api("/projects/#{project.id}/issues/#{closed_issue.id}", user), state_event: 'reopen'
expect(response).to have_http_status(200) expect(response).to have_http_status(200)
expect(json_response['state']).to eq 'reopened' expect(json_response['state']).to eq 'opened'
end end
context 'when an admin or owner makes the request' do context 'when an admin or owner makes the request' do
......
...@@ -23,7 +23,7 @@ describe Boards::Issues::ListService do ...@@ -23,7 +23,7 @@ describe Boards::Issues::ListService do
let!(:opened_issue1) { create(:labeled_issue, project: project, milestone: m1, title: 'Issue 1', labels: [bug]) } let!(:opened_issue1) { create(:labeled_issue, project: project, milestone: m1, title: 'Issue 1', labels: [bug]) }
let!(:opened_issue2) { create(:labeled_issue, project: project, milestone: m2, title: 'Issue 2', labels: [p2]) } let!(:opened_issue2) { create(:labeled_issue, project: project, milestone: m2, title: 'Issue 2', labels: [p2]) }
let!(:reopened_issue1) { create(:issue, :reopened, project: project, title: 'Issue 3' ) } let!(:reopened_issue1) { create(:issue, :opened, project: project, title: 'Issue 3' ) }
let!(:list1_issue1) { create(:labeled_issue, project: project, milestone: m1, labels: [p2, development]) } let!(:list1_issue1) { create(:labeled_issue, project: project, milestone: m1, labels: [p2, development]) }
let!(:list1_issue2) { create(:labeled_issue, project: project, milestone: m2, labels: [development]) } let!(:list1_issue2) { create(:labeled_issue, project: project, milestone: m2, labels: [development]) }
......
...@@ -73,7 +73,7 @@ describe Boards::Issues::MoveService do ...@@ -73,7 +73,7 @@ describe Boards::Issues::MoveService do
issue.reload issue.reload
expect(issue.labels).to contain_exactly(bug, testing) expect(issue.labels).to contain_exactly(bug, testing)
expect(issue).to be_reopened expect(issue).to be_opened
end end
end end
......
...@@ -532,7 +532,6 @@ describe Ci::CreatePipelineService do ...@@ -532,7 +532,6 @@ describe Ci::CreatePipelineService do
context 'when no one can create the tag' do context 'when no one can create the tag' do
let!(:protected_tag) do let!(:protected_tag) do
create(:protected_tag, create(:protected_tag,
:remove_default_access_levels,
:no_one_can_create, :no_one_can_create,
project: project, project: project,
name: ref) name: ref)
......
require 'spec_helper'
describe Ci::PipelineTriggerService, services: true do
let(:project) { create(:project, :repository) }
before do
stub_ci_pipeline_to_return_yaml_file
end
describe '#execute' do
let(:user) { create(:user) }
let(:trigger) { create(:ci_trigger, project: project, owner: user) }
let(:result) { described_class.new(project, user, params).execute }
before do
project.add_developer(user)
end
context 'when trigger belongs to a different project' do
let(:params) { { token: trigger.token, ref: 'master', variables: nil } }
let(:trigger) { create(:ci_trigger, project: create(:empty_project), owner: user) }
it 'does nothing' do
expect { result }.not_to change { Ci::Pipeline.count }
end
end
context 'when params have an existsed trigger token' do
context 'when params have an existsed ref' do
let(:params) { { token: trigger.token, ref: 'master', variables: nil } }
it 'triggers a pipeline' do
expect { result }.to change { Ci::Pipeline.count }.by(1)
expect(result[:pipeline].ref).to eq('master')
expect(result[:pipeline].project).to eq(project)
expect(result[:pipeline].user).to eq(trigger.owner)
expect(result[:status]).to eq(:success)
end
context 'when commit message has [ci skip]' do
before do
allow_any_instance_of(Ci::Pipeline).to receive(:git_commit_message) { '[ci skip]' }
end
it 'ignores [ci skip] and create as general' do
expect { result }.to change { Ci::Pipeline.count }.by(1)
expect(result[:status]).to eq(:success)
end
end
context 'when params have a variable' do
let(:params) { { token: trigger.token, ref: 'master', variables: variables } }
let(:variables) { { 'AAA' => 'AAA123' } }
it 'has a variable' do
expect { result }.to change { Ci::PipelineVariable.count }.by(1)
.and change { Ci::TriggerRequest.count }.by(1)
expect(result[:pipeline].variables.map { |v| { v.key => v.value } }.first).to eq(variables)
expect(result[:pipeline].trigger_requests.last.variables).to be_nil
end
end
end
context 'when params have a non-existsed ref' do
let(:params) { { token: trigger.token, ref: 'invalid-ref', variables: nil } }
it 'does not trigger a pipeline' do
expect { result }.not_to change { Ci::Pipeline.count }
expect(result[:http_status]).to eq(400)
end
end
end
context 'when params have a non-existsed trigger token' do
let(:params) { { token: 'invalid-token', ref: nil, variables: nil } }
it 'does not trigger a pipeline' do
expect { result }.not_to change { Ci::Pipeline.count }
expect(result).to be_nil
end
end
end
end
...@@ -43,7 +43,7 @@ describe DeleteMergedBranchesService do ...@@ -43,7 +43,7 @@ describe DeleteMergedBranchesService do
context 'open merge requests' do context 'open merge requests' do
it 'does not delete branches from open merge requests' do it 'does not delete branches from open merge requests' do
fork_link = create(:forked_project_link, forked_from_project: project) fork_link = create(:forked_project_link, forked_from_project: project)
create(:merge_request, :reopened, source_project: project, target_project: project, source_branch: 'branch-merged', target_branch: 'master') create(:merge_request, :opened, source_project: project, target_project: project, source_branch: 'branch-merged', target_branch: 'master')
create(:merge_request, :opened, source_project: fork_link.forked_to_project, target_project: project, target_branch: 'improve/awesome', source_branch: 'master') create(:merge_request, :opened, source_project: fork_link.forked_to_project, target_project: project, target_branch: 'improve/awesome', source_branch: 'master')
service.execute service.execute
......
...@@ -271,7 +271,6 @@ describe GitPushService do ...@@ -271,7 +271,6 @@ describe GitPushService do
stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_DEV_CAN_PUSH) stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_DEV_CAN_PUSH)
create(:protected_branch, :no_one_can_push, :developers_can_merge, create(:protected_branch, :no_one_can_push, :developers_can_merge,
:remove_default_access_levels,
project: project, name: 'master') project: project, name: 'master')
expect(project).to receive(:execute_hooks) expect(project).to receive(:execute_hooks)
expect(project.default_branch).to eq("master") expect(project.default_branch).to eq("master")
......
...@@ -35,7 +35,7 @@ describe Issues::ExportCsvService do ...@@ -35,7 +35,7 @@ describe Issues::ExportCsvService do
issue.update!(milestone: milestone, issue.update!(milestone: milestone,
assignees: [user], assignees: [user],
description: 'Issue with details', description: 'Issue with details',
state: :reopened, state: :opened,
due_date: DateTime.new(2014, 3, 2), due_date: DateTime.new(2014, 3, 2),
created_at: DateTime.new(2015, 4, 3, 2, 1, 0), created_at: DateTime.new(2015, 4, 3, 2, 1, 0),
updated_at: DateTime.new(2016, 5, 4, 3, 2, 1), updated_at: DateTime.new(2016, 5, 4, 3, 2, 1),
......
...@@ -78,7 +78,7 @@ describe MergeRequests::GetUrlsService do ...@@ -78,7 +78,7 @@ describe MergeRequests::GetUrlsService do
end end
context 'pushing to existing branch and merge request is reopened' do context 'pushing to existing branch and merge request is reopened' do
let!(:merge_request) { create(:merge_request, :reopened, source_project: project, source_branch: source_branch) } let!(:merge_request) { create(:merge_request, :opened, source_project: project, source_branch: source_branch) }
let(:changes) { existing_branch_changes } let(:changes) { existing_branch_changes }
it_behaves_like 'show_merge_request_url' it_behaves_like 'show_merge_request_url'
end end
......
...@@ -86,7 +86,7 @@ describe MergeRequests::RefreshService do ...@@ -86,7 +86,7 @@ describe MergeRequests::RefreshService do
let(:refresh_service) { service.new(@project, @user) } let(:refresh_service) { service.new(@project, @user) }
before do before do
@merge_request.update(state: :reopened) @merge_request.update(state: :opened)
allow(refresh_service).to receive(:execute_hooks) allow(refresh_service).to receive(:execute_hooks)
refresh_service.execute(@oldrev, @newrev, 'refs/heads/master') refresh_service.execute(@oldrev, @newrev, 'refs/heads/master')
......
...@@ -28,7 +28,7 @@ describe MergeRequests::ReopenService do ...@@ -28,7 +28,7 @@ describe MergeRequests::ReopenService do
end end
it { expect(merge_request).to be_valid } it { expect(merge_request).to be_valid }
it { expect(merge_request).to be_reopened } it { expect(merge_request).to be_opened }
it 'executes hooks with reopen action' do it 'executes hooks with reopen action' do
expect(service).to have_received(:execute_hooks) expect(service).to have_received(:execute_hooks)
......
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