Merge remote-tracking branch 'origin/master' into backport-ee-changes-for-build-minutes

This commit is contained in:
Kamil Trzcinski 2017-01-24 21:52:54 +01:00
commit ac92554dfc
No known key found for this signature in database
GPG Key ID: 4505F5C7E12C6A5A
345 changed files with 3306 additions and 1410 deletions

View File

@ -35,7 +35,6 @@ stages:
.dedicated-runner: &dedicated-runner
tags:
- gitlab-org
- 2gb
.knapsack-state: &knapsack-state
services: []

View File

@ -2,6 +2,136 @@
documentation](doc/development/changelog.md) for instructions on adding your own
entry.
## 8.16.0 (2017-02-22)
- Add LDAP Rake task to rename a provider. !2181
- Validate label's title length. !5767 (Tomáš Kukrál)
- Allow to add deploy keys with write-access. !5807 (Ali Ibrahim)
- Allow to use + symbol in filenames. !6644 (blackst0ne)
- Search bar redesign first iteration. !7345
- Fix date inconsistency on due date picker. !7422 (Giuliano Varriale)
- Add email confirmation field to registration form. !7432
- Updated project visibility settings UX. !7645
- Go to a project order. !7737 (Jacopo Beschi @jacopo-beschi)
- Support slash comand `/merge` for merging merge requests. !7746 (Jarka Kadlecova)
- Add more storage statistics. !7754 (Markus Koller)
- Add support for PlantUML diagrams in AsciiDoc documents. !7810 (Horacio Sanson)
- Remove extra orphaned rows when removing stray namespaces. !7841
- Added lighter count badge background-color for on white backgrounds. !7873
- Fixes issue boards list colored top border visual glitch. !7898 (Pier Paolo Ramon)
- change 'gray' color theme name to 'black' to match the actual color. !7908 (BM5k)
- Remove trailing whitespace when generating changelog entry. !7948
- Remove checking branches state in issue new branch button. !8023
- Log LDAP blocking/unblocking events to application log. !8042 (Markus Koller)
- ensure permalinks scroll to correct position on multiple clicks. !8046
- Allow to use ENV variables in redis config. !8073 (Semyon Pupkov)
- fix button layout issue on branches page. !8074
- Reduce DB-load for build-queues by storing last_update in Redis. !8084
- Record and show last used date of SSH Keys. !8113 (Vincent Wong)
- Resolves overflow in compare branch and tags dropdown. !8118
- Replace wording for slash command confirmation message. !8123
- remove build_user. !8162 (Arsenev Vladislav)
- Prevent empty pagination when list is not empty. !8172
- Make successful pipeline emails off for watchers. !8176
- Improve copy in Issue Tracker empty state. !8202
- Adds CSS class to status icon on MR widget to prevent non-colored icon. !8219
- Improve visibility of "Resolve conflicts" and "Merge locally" actions. !8229
- Add Gitaly to the architecture documentation. !8264 (Pablo Carranza <pablo@gitlab.com>)
- Sort numbers in build names more intelligently. !8277
- Show nested groups tab on group page. !8308
- Rename users with namespace ending with .git. !8309
- Rename filename to file path in tooltip of file header in merge request diff. !8314
- About GitLab link in sidebar that links to help page. !8316
- Merged the 'Groups' and 'Projects' tabs when viewing user profiles. !8323 (James Gregory)
- re-enable change username button after failure. !8332
- Darkened hr border color in descriptions because of update of bootstrap. !8333
- display merge request discussion tab for empty branches. !8347
- Fix double spaced CI log. !8349 (Jared Deckard <jared.deckard@gmail.com>)
- Refactored note edit form to improve frontend performance on MR and Issues pages, especially pages with has a lot of discussions in it. !8356
- Make CTRL+Enter submits a new merge request. !8360 (Saad Shahd)
- Fixes too short input for placeholder message in commit listing page. !8367
- Fix typo: seach to search. !8370
- Adds label to Environments "Date Created". !8376 (Saad Shahd)
- Convert project setting text into protected branch path link. !8377 (Ken Ding)
- Precompile all JavaScript fixtures. !8384
- Use original casing for build action text. !8387
- Scroll to bottom on build completion if autoscroll was active. !8391
- Properly handle failed reCAPTCHA on user registration. !8403
- Changed alerts to be responsive, centered text on smaller viewports. !8424 (Connor Smallman)
- Pass Gitaly resource path to gitlab-workhorse if Gitaly is enabled. !8440
- Fixes and Improves CSS and HTML problems in mini pipeline graph and builds dropdown. !8443
- Don't instrument 405 Grape calls. !8445
- Change CI template linter textarea with Ace Editor. !8452 (Didem Acet)
- Removes unneeded `window` declaration in environments related code. !8456
- API: fix query response for `/projects/:id/issues?milestone="No%20Milestone"`. !8457 (Panagiotis Atmatzidis, David Eisner)
- Fix broken url on group avatar. !8464 (hogewest)
- Fixes buttons not being accessible via the keyboard when creating new group. !8469
- Restore backup correctly when "BACKUP" environment variable is passed. !8477
- Add new endpoints for Time Tracking. !8483
- Fix Compare page throws 500 error when any branch/reference is not selected. !8492 (Martin Cabrera)
- Treat environments matching `production/*` as Production. !8500
- Hide build artifacts keep button if operation is not allowed. !8501
- Update the gitlab-markup gem to the version 1.5.1. !8509
- Remove Lock Icon on Protected Tag. !8513 (Sergey Nikitin)
- Use cached values to compute total issues count in milestone index pages. !8518
- Speed up dashboard milestone index by scoping IssuesFinder to user authorized projects. !8524
- Copy <some text> to clipboard. !8535
- Check for env[Grape::Env::GRAPE_ROUTING_ARGS] instead of endpoint.route. !8544
- Fixes builds dropdown making request when clicked to be closed. !8545
- Fixes pipeline status cell is too wide by adding missing classes in table head cells. !8549
- Mutate the attribute instead of issuing a write operation to the DB in `ProjectFeaturesCompatibility` concern. !8552
- Fix links to commits pages on pipelines list page. !8558
- Ensure updating project settings shows a flash message on success. !8579 (Sandish Chen)
- Fixes big pipeline and small pipeline width problems and tooltips text being outside the tooltip. !8593
- Autoresize markdown preview. !8607 (Didem Acet)
- Link external build badge to its target URL. !8611
- Adjust ProjectStatistic#repository_size with values saved as MB. !8616
- Correct User-agent placement in robots.txt. !8623 (Eric Sabelhaus)
- Record used SSH keys only once per day. !8655
- Do not generate pipeline branch/tag path if not present. !8658
- Fix Merge When Pipeline Succeeds immediate merge bug. !8685
- Fix blame 500 error on invalid path. !25761 (Jeff Stubler)
- Added animations to issue boards interactions.
- Check if user can read project before being assigned to issue.
- Show 'too many changes' message for created merge requests when they are too large.
- Fix redirect after update file when user has forked project.
- Parse JIRA issue references even if Issue Tracker is disabled.
- Made download artifacts button accessible via keyboard by changing it from an anchor tag to an actual button. (Ryan Harris)
- Make play button on Pipelines page accessible via keyboard. (Ryan Harris)
- Decreases font-size on login page.
- Fixed merge request tabs dont move when opening collapsed sidebar.
- Display project avatars on Admin Area and Projects pages for mobile views. (Ryan Harris)
- Fix participants margins to fit on one line.
- 26352 Change Profile settings to User / Settings.
- Fix Commits API to accept a Project path upon POST.
- Expire related caches after changing HEAD. (Minqi Pan)
- Add various hover animations throughout the application.
- Re-order update steps in the 8.14 -> 8.15 upgrade guide.
- Move award emoji's out of the discussion tab for merge requests.
- Synchronize all project authorization refreshing work to prevent race conditions.
- Remove the project_authorizations.id column.
- Combined the settings options project members and groups into a single one called members.
- Change earlier to task_status_short to avoid titlebar line wraps.
- 25701 standardize text colors.
- Handle HTTP errors in environment list.
- Re-add Google Cloud Storage as a backup strategy.
- Change status colors of runners to better defaults.
- Added number_with_delimiter to counter on milestone panels. (Ryan Harris)
- Query external CI statuses in the background.
- Allow group and project paths when transferring projects via the API.
- Don't validate environment urls on .gitlab-ci.yml.
- Fix a Grape deprecation, use `#request_method` instead of `#route_method`.
- Fill missing authorized projects rows.
- Allow API query to find projects with dots in their name. (Bruno Melli)
- Fix import/export wrong user mapping.
- Removed bottom padding from merge manually from CLI because of repositioning award emoji's.
- Fix project queued for deletion re-creation tooltip.
- Fix search group/project filtering to show results.
- Fix 500 error when POSTing to Users API with optional confirm param.
- 26504 Fix styling of MR jump to discussion button.
- Add margin to markdown math blocks.
- Add hover state to MR comment reply button.
## 8.15.4 (2017-01-09)
- Make successful pipeline emails off for watchers. !8176

View File

@ -1 +1 @@
1.2.1
1.3.0

View File

@ -21,7 +21,7 @@ gem 'rugged', '~> 0.24.0'
# Authentication libraries
gem 'devise', '~> 4.2'
gem 'doorkeeper', '~> 4.2.0'
gem 'omniauth', '~> 1.3.1'
gem 'omniauth', '~> 1.3.2'
gem 'omniauth-auth0', '~> 1.4.1'
gem 'omniauth-azure-oauth2', '~> 0.0.6'
gem 'omniauth-cas3', '~> 1.1.2'

View File

@ -449,7 +449,7 @@ GEM
octokit (4.6.2)
sawyer (~> 0.8.0, >= 0.5.3)
oj (2.17.4)
omniauth (1.3.1)
omniauth (1.3.2)
hashie (>= 1.2, < 4)
rack (>= 1.0, < 3)
omniauth-auth0 (1.4.1)
@ -925,7 +925,7 @@ DEPENDENCIES
oauth2 (~> 1.2.0)
octokit (~> 4.6.2)
oj (~> 2.17.4)
omniauth (~> 1.3.1)
omniauth (~> 1.3.2)
omniauth-auth0 (~> 1.4.1)
omniauth-authentiq (~> 0.2.0)
omniauth-azure-oauth2 (~> 0.0.6)

View File

@ -113,4 +113,4 @@ Please see [Getting help for GitLab](https://about.gitlab.com/getting-help/) on
## Is it awesome?
Thanks for [asking this question](https://twitter.com/supersloth/status/489462789384056832) Joshua.
[These people](https://twitter.com/gitlab/favorites) seem to like it.
[These people](https://twitter.com/gitlab/likes) seem to like it.

View File

@ -1 +1 @@
8.16.0-pre
8.17.0-pre

View File

@ -62,6 +62,7 @@ var DropDown = function(list) {
this.list = list;
this.items = [];
this.getItems();
this.initTemplateString();
this.addEvents();
this.initialState = list.innerHTML;
};
@ -72,6 +73,17 @@ Object.assign(DropDown.prototype, {
return this.items;
},
initTemplateString: function() {
var items = this.items || this.getItems();
var templateString = '';
if(items.length > 0) {
templateString = items[items.length - 1].outerHTML;
}
this.templateString = templateString;
return this.templateString;
},
clickEvent: function(e) {
// climb up the tree to find the LI
var selected = utils.closest(e.target, 'LI');
@ -111,30 +123,21 @@ Object.assign(DropDown.prototype, {
addData: function(data) {
this.data = (this.data || []).concat(data);
this.render(data);
this.render(this.data);
},
// call render manually on data;
render: function(data){
// debugger
// empty the list first
var sampleItem;
var templateString = this.templateString;
var newChildren = [];
var toAppend;
for(var i = 0; i < this.items.length; i++) {
var item = this.items[i];
sampleItem = item;
if(item.parentNode && item.parentNode.dataset.hasOwnProperty('dynamic')) {
item.parentNode.removeChild(item);
}
}
newChildren = this.data.map(function(dat){
var html = utils.t(sampleItem.outerHTML, dat);
newChildren = (data ||[]).map(function(dat){
var html = utils.t(templateString, dat);
var template = document.createElement('div');
template.innerHTML = html;
// console.log(template.content)
// Help set the image src template
var imageTags = template.querySelectorAll('img[data-src]');
@ -156,7 +159,7 @@ Object.assign(DropDown.prototype, {
if(toAppend) {
toAppend.innerHTML = newChildren.join('');
} else {
this.list.innerHTML = newChildren.join('');
this.list.innerHTML = newChildren.join('');
}
},
@ -173,10 +176,7 @@ Object.assign(DropDown.prototype, {
},
destroy: function() {
if (!this.hidden) {
this.hide();
}
this.hide();
this.list.removeEventListener('click', this.clickWrapper);
}
});
@ -278,7 +278,7 @@ require('./window')(function(w){
self.hooks[i].list.hide();
}
}.bind(this);
w.addEventListener('click', this.windowClickedWrapper);
document.addEventListener('click', this.windowClickedWrapper);
},
removeEvents: function(){
@ -307,7 +307,7 @@ require('./window')(function(w){
if(!list){
list = document.querySelector(hook.dataset[utils.toDataCamelCase(DATA_TRIGGER)]);
}
if(hook) {
if(hook.tagName === 'A' || hook.tagName === 'BUTTON') {
this.hooks.push(new HookButton(hook, list, plugins, config));
@ -462,6 +462,8 @@ Object.assign(HookInput.prototype, {
var self = this;
this.mousedown = function mousedown(e) {
if(self.hasRemovedEvents) return;
var mouseEvent = new CustomEvent('mousedown.dl', {
detail: {
hook: self,
@ -474,6 +476,8 @@ Object.assign(HookInput.prototype, {
}
this.input = function input(e) {
if(self.hasRemovedEvents) return;
var inputEvent = new CustomEvent('input.dl', {
detail: {
hook: self,
@ -487,10 +491,14 @@ Object.assign(HookInput.prototype, {
}
this.keyup = function keyup(e) {
if(self.hasRemovedEvents) return;
keyEvent(e, 'keyup.dl');
}
this.keydown = function keydown(e) {
if(self.hasRemovedEvents) return;
keyEvent(e, 'keydown.dl');
}
@ -520,7 +528,8 @@ Object.assign(HookInput.prototype, {
this.trigger.addEventListener('keydown', this.keydown);
},
removeEvents: function(){
removeEvents: function() {
this.hasRemovedEvents = true;
this.trigger.removeEventListener('mousedown', this.mousedown);
this.trigger.removeEventListener('input', this.input);
this.trigger.removeEventListener('keyup', this.keyup);
@ -578,7 +587,7 @@ require('./window')(function(w){
var listItems = removeHighlight(list);
if(currentIndex>0){
if(!listItems[currentIndex-1]){
currentIndex = currentIndex-1;
currentIndex = currentIndex-1;
}
listItems[currentIndex-1].classList.add('dropdown-active');
}
@ -630,7 +639,7 @@ require('./window')(function(w){
return;
}
if(currentKey === 'ArrowUp') {
isUpArrow = true;
isUpArrow = true;
}
if(currentKey === 'ArrowDown') {
isDownArrow = true;
@ -668,16 +677,16 @@ var camelize = function(str) {
};
var closest = function(thisTag, stopTag) {
while(thisTag.tagName !== stopTag && thisTag.tagName !== 'HTML'){
while(thisTag && thisTag.tagName !== stopTag && thisTag.tagName !== 'HTML'){
thisTag = thisTag.parentNode;
}
return thisTag;
};
var isDropDownParts = function(target) {
if(target.tagName === 'HTML') { return false; }
if(!target || target.tagName === 'HTML') { return false; }
return (
target.hasAttribute(DATA_TRIGGER) ||
target.hasAttribute(DATA_TRIGGER) ||
target.hasAttribute(DATA_DROPDOWN)
);
};

View File

@ -0,0 +1,12 @@
/* global CustomEvent */
/* eslint-disable no-global-assign */
// Custom event support for IE
CustomEvent = function CustomEvent(event, parameters) {
const params = parameters || { bubbles: false, cancelable: false, detail: undefined };
const evt = document.createEvent('CustomEvent');
evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);
return evt;
};
CustomEvent.prototype = window.Event.prototype;

View File

@ -9,7 +9,7 @@
this.config = {
droplabFilter: {
template: 'hint',
filterFunction: gl.DropdownUtils.filterHint,
filterFunction: gl.DropdownUtils.filterHint.bind(null, input),
},
};
}
@ -20,6 +20,9 @@
if (selected.tagName === 'LI') {
if (selected.hasAttribute('data-value')) {
this.dismissDropdown();
} else if (selected.getAttribute('data-action') === 'submit') {
this.dismissDropdown();
this.dispatchFormSubmitEvent();
} else {
const token = selected.querySelector('.js-filter-hint').innerText.trim();
const tag = selected.querySelector('.js-filter-tag').innerText.trim();

View File

@ -15,7 +15,7 @@
loadingTemplate: this.loadingTemplate,
},
droplabFilter: {
filterFunction: gl.DropdownUtils.filterWithSymbol.bind(null, this.symbol),
filterFunction: gl.DropdownUtils.filterWithSymbol.bind(null, this.symbol, input),
},
};
}

View File

@ -37,7 +37,7 @@
}
getSearchInput() {
const query = this.input.value.trim();
const query = gl.DropdownUtils.getSearchInput(this.input);
const { lastToken } = gl.FilteredSearchTokenizer.processTokens(query);
return lastToken.value || '';

View File

@ -20,17 +20,15 @@
return escapedText;
}
static filterWithSymbol(filterSymbol, item, query) {
static filterWithSymbol(filterSymbol, input, item) {
const updatedItem = item;
const query = gl.DropdownUtils.getSearchInput(input);
const { lastToken, searchToken } = gl.FilteredSearchTokenizer.processTokens(query);
if (lastToken !== searchToken) {
const title = updatedItem.title.toLowerCase();
let value = lastToken.value.toLowerCase();
if ((value[0] === '"' || value[0] === '\'') && title.indexOf(' ') !== -1) {
value = value.slice(1);
}
value = value.replace(/"(.*?)"/g, str => str.slice(1).slice(0, -1));
// Eg. filterSymbol = ~ for labels
const matchWithoutSymbol = lastToken.symbol === filterSymbol && title.indexOf(value) !== -1;
@ -44,8 +42,9 @@
return updatedItem;
}
static filterHint(item, query) {
static filterHint(input, item) {
const updatedItem = item;
const query = gl.DropdownUtils.getSearchInput(input);
let { lastToken } = gl.FilteredSearchTokenizer.processTokens(query);
lastToken = lastToken.key || lastToken || '';
@ -72,6 +71,48 @@
// Return boolean based on whether it was set
return dataValue !== null;
}
static getSearchInput(filteredSearchInput) {
const inputValue = filteredSearchInput.value;
const { right } = gl.DropdownUtils.getInputSelectionPosition(filteredSearchInput);
return inputValue.slice(0, right);
}
static getInputSelectionPosition(input) {
const selectionStart = input.selectionStart;
let inputValue = input.value;
// Replace all spaces inside quote marks with underscores
// This helps with matching the beginning & end of a token:key
inputValue = inputValue.replace(/"(.*?)"/g, str => str.replace(/\s/g, '_'));
// Get the right position for the word selected
// Regex matches first space
let right = inputValue.slice(selectionStart).search(/\s/);
if (right >= 0) {
right += selectionStart;
} else if (right < 0) {
right = inputValue.length;
}
// Get the left position for the word selected
// Regex matches last non-whitespace character
let left = inputValue.slice(0, right).search(/\S+$/);
if (selectionStart === 0) {
left = 0;
} else if (selectionStart === inputValue.length && left < 0) {
left = inputValue.length;
} else if (left < 0) {
left = selectionStart;
}
return {
left,
right,
};
}
}
window.gl = window.gl || {};

View File

@ -39,6 +39,7 @@
}
this.dismissDropdown();
this.dispatchInputEvent();
}
}
@ -78,7 +79,16 @@
dispatchInputEvent() {
// Propogate input change to FilteredSearchDropdownManager
// so that it can determine which dropdowns to open
this.input.dispatchEvent(new Event('input'));
this.input.dispatchEvent(new CustomEvent('input', {
bubbles: true,
cancelable: true,
}));
}
dispatchFormSubmitEvent() {
// dispatchEvent() is necessary as form.submit() does not
// trigger event handlers
this.input.form.dispatchEvent(new Event('submit'));
}
hideDropdown() {

View File

@ -57,28 +57,33 @@
static addWordToInput(tokenName, tokenValue = '') {
const input = document.querySelector('.filtered-search');
const inputValue = input.value;
const word = `${tokenName}:${tokenValue}`;
const { lastToken, searchToken } = gl.FilteredSearchTokenizer.processTokens(input.value);
const lastSearchToken = searchToken.split(' ').last();
const lastInputCharacter = input.value[input.value.length - 1];
const lastInputTrimmedCharacter = input.value.trim()[input.value.trim().length - 1];
// Get the string to replace
let newCaretPosition = input.selectionStart;
const { left, right } = gl.DropdownUtils.getInputSelectionPosition(input);
// Remove the typed tokenName
if (word.indexOf(lastSearchToken) === 0 && searchToken !== '') {
// Remove spaces after the colon
if (lastInputCharacter === ' ' && lastInputTrimmedCharacter === ':') {
input.value = input.value.trim();
}
input.value = `${inputValue.substr(0, left)}${word}${inputValue.substr(right)}`;
input.value = input.value.slice(0, -1 * lastSearchToken.length);
} else if (lastInputCharacter !== ' ' || (lastToken && lastToken.value[lastToken.value.length - 1] === ' ')) {
// Remove the existing tokenValue
const lastTokenString = `${lastToken.key}:${lastToken.symbol}${lastToken.value}`;
input.value = input.value.slice(0, -1 * lastTokenString.length);
// If we have added a tokenValue at the end of the input,
// add a space and set selection to the end
if (right >= inputValue.length && tokenValue !== '') {
input.value += ' ';
newCaretPosition = input.value.length;
}
input.value += word;
gl.FilteredSearchDropdownManager.updateInputCaretPosition(newCaretPosition, input);
}
static updateInputCaretPosition(selectionStart, input) {
// Reset the position
// Sometimes can end up at end of input
input.setSelectionRange(selectionStart, selectionStart);
const { right } = gl.DropdownUtils.getInputSelectionPosition(input);
input.setSelectionRange(right, right);
}
updateCurrentDropdownOffset() {
@ -90,9 +95,18 @@
this.font = window.getComputedStyle(this.filteredSearchInput).font;
}
const input = this.filteredSearchInput;
const inputText = input.value.slice(0, input.selectionStart);
const filterIconPadding = 27;
const offset = gl.text
.getTextWidth(this.filteredSearchInput.value, this.font) + filterIconPadding;
let offset = gl.text.getTextWidth(inputText, this.font) + filterIconPadding;
const currentDropdownWidth = this.mapping[key].element.clientWidth === 0 ? 200 :
this.mapping[key].element.clientWidth;
const offsetMaxWidth = this.filteredSearchInput.clientWidth - currentDropdownWidth;
if (offsetMaxWidth < offset) {
offset = offsetMaxWidth;
}
this.mapping[key].reference.setOffset(offset);
}
@ -148,9 +162,9 @@
setDropdown() {
const { lastToken, searchToken } = this.tokenizer
.processTokens(this.filteredSearchInput.value);
.processTokens(gl.DropdownUtils.getSearchInput(this.filteredSearchInput));
if (this.filteredSearchInput.value.split('').last() === ' ') {
if (this.currentDropdown) {
this.updateCurrentDropdownOffset();
}

View File

@ -25,24 +25,32 @@
}
bindEvents() {
this.handleFormSubmit = this.handleFormSubmit.bind(this);
this.setDropdownWrapper = this.dropdownManager.setDropdown.bind(this.dropdownManager);
this.toggleClearSearchButtonWrapper = this.toggleClearSearchButton.bind(this);
this.checkForEnterWrapper = this.checkForEnter.bind(this);
this.clearSearchWrapper = this.clearSearch.bind(this);
this.checkForBackspaceWrapper = this.checkForBackspace.bind(this);
this.tokenChange = this.tokenChange.bind(this);
this.filteredSearchInput.form.addEventListener('submit', this.handleFormSubmit);
this.filteredSearchInput.addEventListener('input', this.setDropdownWrapper);
this.filteredSearchInput.addEventListener('input', this.toggleClearSearchButtonWrapper);
this.filteredSearchInput.addEventListener('keydown', this.checkForEnterWrapper);
this.filteredSearchInput.addEventListener('keyup', this.checkForBackspaceWrapper);
this.filteredSearchInput.addEventListener('click', this.tokenChange);
this.filteredSearchInput.addEventListener('keyup', this.tokenChange);
this.clearSearchButton.addEventListener('click', this.clearSearchWrapper);
}
unbindEvents() {
this.filteredSearchInput.form.removeEventListener('submit', this.handleFormSubmit);
this.filteredSearchInput.removeEventListener('input', this.setDropdownWrapper);
this.filteredSearchInput.removeEventListener('input', this.toggleClearSearchButtonWrapper);
this.filteredSearchInput.removeEventListener('keydown', this.checkForEnterWrapper);
this.filteredSearchInput.removeEventListener('keyup', this.checkForBackspaceWrapper);
this.filteredSearchInput.removeEventListener('click', this.tokenChange);
this.filteredSearchInput.removeEventListener('keyup', this.tokenChange);
this.clearSearchButton.removeEventListener('click', this.clearSearchWrapper);
}
@ -83,8 +91,14 @@
this.dropdownManager.resetDropdowns();
}
handleFormSubmit(e) {
e.preventDefault();
this.search();
}
loadSearchParamsFromURL() {
const params = gl.utils.getUrlParamsArray();
const usernameParams = this.getUsernameParams();
const inputValues = [];
params.forEach((p) => {
@ -115,6 +129,16 @@
}
inputValues.push(`${sanitizedKey}:${symbol}${quotationsToUse}${sanitizedValue}${quotationsToUse}`);
} else if (!match && keyParam === 'assignee_id') {
const id = parseInt(value, 10);
if (usernameParams[id]) {
inputValues.push(`assignee:@${usernameParams[id]}`);
}
} else if (!match && keyParam === 'author_id') {
const id = parseInt(value, 10);
if (usernameParams[id]) {
inputValues.push(`author:@${usernameParams[id]}`);
}
} else if (!match && keyParam === 'search') {
inputValues.push(sanitizedValue);
}
@ -164,6 +188,27 @@
Turbolinks.visit(`?scope=all&utf8=✓&${paths.join('&')}`);
}
getUsernameParams() {
const usernamesById = {};
try {
const attribute = this.filteredSearchInput.getAttribute('data-username-params');
JSON.parse(attribute).forEach((user) => {
usernamesById[user.id] = user.username;
});
} catch (e) {
// do nothing
}
return usernamesById;
}
tokenChange() {
const dropdown = this.dropdownManager.mapping[this.dropdownManager.currentDropdown];
const currentDropdownRef = dropdown.reference;
this.setDropdownWrapper();
currentDropdownRef.dispatchInputEvent();
}
}
window.gl = window.gl || {};

View File

@ -2,12 +2,12 @@
(function() {
this.GroupAvatar = (function() {
function GroupAvatar() {
$('.js-choose-group-avatar-button').bind("click", function() {
$('.js-choose-group-avatar-button').on("click", function() {
var form;
form = $(this).closest("form");
return form.find(".js-group-avatar-input").click();
});
$('.js-group-avatar-input').bind("change", function() {
$('.js-group-avatar-input').on("change", function() {
var filename, form;
form = $(this).closest("form");
filename = $(this).val().replace(/^.*[\\\/]/, '');

View File

@ -126,7 +126,9 @@
MergeRequestWidget.prototype.getMergeStatus = function() {
return $.get(this.opts.merge_check_url, function(data) {
return $('.mr-state-widget').replaceWith(data);
var $html = $(data);
$('.mr-widget-body').replaceWith($html.find('.mr-widget-body'));
$('.mr-widget-footer').replaceWith($html.find('.mr-widget-footer'));
});
};

View File

@ -8,31 +8,42 @@
* temporarily.
* */
if ($('.accept-mr-form').length) {
$('.accept-mr-form').on('ajax:send', () => {
$('.accept-mr-form :input').disable();
});
$(document)
.off('ajax:send', '.accept-mr-form')
.on('ajax:send', '.accept-mr-form', () => {
$('.accept-mr-form :input').disable();
});
$('.accept_merge_request').on('click', () => {
$('.js-merge-button').html('<i class="fa fa-spinner fa-spin"></i> Merge in progress');
});
$(document)
.off('click', '.accept_merge_request')
.on('click', '.accept_merge_request', () => {
$('.js-merge-button').html('<i class="fa fa-spinner fa-spin"></i> Merge in progress');
});
$('.merge_when_build_succeeds').on('click', () => {
$('#merge_when_build_succeeds').val('1');
});
$(document)
.off('click', '.merge_when_build_succeeds')
.on('click', '.merge_when_build_succeeds', () => {
$('#merge_when_build_succeeds').val('1');
});
$('.js-merge-dropdown a').on('click', (e) => {
e.preventDefault();
$(this).closest('form').submit();
});
} else if ($('.rebase-in-progress').length) {
$(document)
.off('click', '.js-merge-dropdown a')
.on('click', '.js-merge-dropdown a', (e) => {
e.preventDefault();
$(e.target).closest('form').submit();
});
if ($('.rebase-in-progress').length) {
merge_request_widget.rebaseInProgress();
} else if ($('.rebase-mr-form').length) {
$('.rebase-mr-form').on('ajax:send', () => {
$(document)
.off('ajax:send', '.rebase-mr-form')
.on('ajax:send', '.rebase-mr-form', () => {
$('.rebase-mr-form :input').disable();
});
$('.js-rebase-button').on('click', () => {
$(document)
.off('click', '.js-rebase-button')
.on('click', '.js-rebase-button', () => {
$('.js-rebase-button').html("<i class='fa fa-spinner fa-spin'></i> Rebase in progress");
});
} else {

View File

@ -1,5 +1,5 @@
/* global Vue, Flash, gl */
/* eslint-disable no-param-reassign, no-bitwise */
/* eslint-disable no-param-reassign */
((gl) => {
gl.VueStage = Vue.extend({
@ -9,7 +9,20 @@
spinner: '<span class="fa fa-spinner fa-spin"></span>',
};
},
props: ['stage', 'svgs', 'match'],
props: {
stage: {
type: Object,
required: true,
},
svgs: {
type: DOMStringMap,
required: true,
},
match: {
type: Function,
required: true,
},
},
methods: {
fetchBuilds(e) {
const areaExpanded = e.currentTarget.attributes['aria-expanded'];
@ -24,6 +37,18 @@
return flash;
});
},
keepGraph(e) {
const { target } = e;
if (target.className.indexOf('js-ci-action-icon') >= 0) return null;
if (
target.parentElement &&
(target.parentElement.className.indexOf('js-ci-action-icon') >= 0)
) return null;
return e.stopPropagation();
},
},
computed: {
buildsOrSpinner() {
@ -64,7 +89,7 @@
<ul class="dropdown-menu mini-pipeline-graph-dropdown-menu js-builds-dropdown-container">
<div class="arrow-up"></div>
<div
@click=''
@click='keepGraph($event)'
:class="dropdownClass"
class="js-builds-dropdown-list scrollable-menu"
v-html="buildsOrSpinner"

View File

@ -15,6 +15,7 @@
}
.ci-status-icon-pending,
.ci-status-icon-failed_with_warnings,
.ci-status-icon-success_with_warnings {
color: $gl-warning;

View File

@ -46,10 +46,6 @@
font-weight: bold;
}
.fa-clipboard {
color: $dropdown-title-btn-color;
}
.commit-info {
&.branches {
margin-left: 8px;

View File

@ -377,6 +377,10 @@
display: inline-block;
padding: 5px;
&:nth-of-type(7n) {
padding-right: 0;
}
.author_link {
display: block;
}

View File

@ -195,10 +195,10 @@ ul.notes {
}
.note-body {
overflow: auto;
overflow-x: auto;
overflow-y: hidden;
.note-text {
overflow: auto;
word-wrap: break-word;
@include md-typography;
// Reset ul style types since we're nested inside a ul already

View File

@ -18,7 +18,6 @@
.file-finder-input:hover,
.issuable-search-form:hover,
.search-text-input:hover,
textarea:hover,
.form-control:hover {
border-color: lighten($dropdown-input-focus-border, 20%);
box-shadow: 0 0 4px lighten($search-input-focus-shadow-color, 20%);

View File

@ -19,7 +19,8 @@
overflow: visible;
}
&.ci-failed {
&.ci-failed,
&.ci-failed_with_warnings {
color: $gl-danger;
border-color: $gl-danger;

View File

@ -14,12 +14,8 @@ class ConfirmationsController < Devise::ConfirmationsController
if signed_in?(resource_name)
after_sign_in_path_for(resource)
else
sign_in(resource)
if signed_in?(resource_name)
after_sign_in_path_for(resource)
else
new_session_path(resource_name)
end
flash[:notice] += " Please sign in."
new_session_path(resource_name)
end
end
end

View File

@ -33,6 +33,18 @@ class Projects::IssuesController < Projects::ApplicationController
@labels = LabelsFinder.new(current_user, project_id: @project.id, title: params[:label_name]).execute
end
@users = []
if params[:assignee_id].present?
assignee = User.find_by_id(params[:assignee_id])
@users.push(assignee) if assignee
end
if params[:author_id].present?
author = User.find_by_id(params[:author_id])
@users.push(author) if author
end
respond_to do |format|
format.html
format.atom { render layout: false }

View File

@ -45,6 +45,8 @@ class SearchController < ApplicationController
end
@search_objects = @search_results.objects(@scope, params[:page])
check_single_commit_result
end
def autocomplete
@ -59,4 +61,16 @@ class SearchController < ApplicationController
render json: search_autocomplete_opts(term).to_json
end
private
def check_single_commit_result
if @search_results.single_commit_result?
only_commit = @search_results.objects('commits').first
query = params[:search].strip.downcase
found_by_commit_sha = Commit.valid_hash?(query) && only_commit.sha.start_with?(query)
redirect_to namespace_project_commit_path(@project.namespace, @project, only_commit) if found_by_commit_sha
end
end
end

View File

@ -1,23 +1,23 @@
module ServicesHelper
def service_event_description(event)
case event
when "push"
when "push", "push_events"
"Event will be triggered by a push to the repository"
when "tag_push"
when "tag_push", "tag_push_events"
"Event will be triggered when a new tag is pushed to the repository"
when "note"
when "note", "note_events"
"Event will be triggered when someone adds a comment"
when "issue"
when "issue", "issue_events"
"Event will be triggered when an issue is created/updated/closed"
when "confidential_issue"
when "confidential_issue", "confidential_issue_events"
"Event will be triggered when a confidential issue is created/updated/closed"
when "merge_request"
when "merge_request", "merge_request_events"
"Event will be triggered when a merge request is created/updated/merged"
when "build"
when "build", "build_events"
"Event will be triggered when a build status changes"
when "wiki_page"
when "wiki_page", "wiki_page_events"
"Event will be triggered when a wiki page is created/updated"
when "commit"
when "commit", "commit_events"
"Event will be triggered when a commit is created/updated"
end
end
@ -26,4 +26,6 @@ module ServicesHelper
event = event.pluralize if %w[merge_request issue confidential_issue].include?(event)
"#{event}_events"
end
extend self
end

View File

@ -107,15 +107,11 @@ class Notify < BaseMailer
def mail_thread(model, headers = {})
add_project_headers
add_unsubscription_headers_and_links
headers["X-GitLab-#{model.class.name}-ID"] = model.id
headers['X-GitLab-Reply-Key'] = reply_key
if !@labels_url && @sent_notification && @sent_notification.unsubscribable?
headers['List-Unsubscribe'] = "<#{unsubscribe_sent_notification_url(@sent_notification, force: true)}>"
@sent_notification_url = unsubscribe_sent_notification_url(@sent_notification)
end
if Gitlab::IncomingEmail.enabled?
address = Mail::Address.new(Gitlab::IncomingEmail.reply_address(reply_key))
address.display_name = @project.name_with_namespace
@ -171,4 +167,16 @@ class Notify < BaseMailer
headers['X-GitLab-Project-Id'] = @project.id
headers['X-GitLab-Project-Path'] = @project.path_with_namespace
end
def add_unsubscription_headers_and_links
return unless !@labels_url && @sent_notification && @sent_notification.unsubscribable?
list_unsubscribe_methods = [unsubscribe_sent_notification_url(@sent_notification, force: true)]
if Gitlab::IncomingEmail.enabled? && Gitlab::IncomingEmail.supports_wildcard?
list_unsubscribe_methods << "mailto:#{Gitlab::IncomingEmail.unsubscribe_address(reply_key)}"
end
headers['List-Unsubscribe'] = list_unsubscribe_methods.map { |e| "<#{e}>" }.join(',')
@sent_notification_url = unsubscribe_sent_notification_url(@sent_notification)
end
end

View File

@ -128,16 +128,21 @@ module Ci
end
def stages
# TODO, this needs refactoring, see gitlab-ce#26481.
stages_query = statuses
.group('stage').select(:stage).order('max(stage_idx)')
status_sql = statuses.latest.where('stage=sg.stage').status_sql
stages_query = statuses.group('stage').select(:stage)
.order('max(stage_idx)')
warnings_sql = statuses.latest.select('COUNT(*) > 0')
.where('stage=sg.stage').failed_but_allowed.to_sql
stages_with_statuses = CommitStatus.from(stages_query, :sg).
pluck('sg.stage', status_sql)
stages_with_statuses = CommitStatus.from(stages_query, :sg)
.pluck('sg.stage', status_sql, "(#{warnings_sql})")
stages_with_statuses.map do |stage|
Ci::Stage.new(self, name: stage.first, status: stage.last)
Ci::Stage.new(self, Hash[%i[name status warnings].zip(stage)])
end
end

View File

@ -126,9 +126,11 @@ module Ci
end
def tick_runner_queue
new_update = SecureRandom.hex
Gitlab::Redis.with { |redis| redis.set(runner_queue_key, new_update, ex: RUNNER_QUEUE_EXPIRY_TIME) }
new_update
SecureRandom.hex.tap do |new_update|
Gitlab::Redis.with do |redis|
redis.set(runner_queue_key, new_update, ex: RUNNER_QUEUE_EXPIRY_TIME)
end
end
end
def ensure_runner_queue_value

View File

@ -8,10 +8,11 @@ module Ci
delegate :project, to: :pipeline
def initialize(pipeline, name:, status: nil)
def initialize(pipeline, name:, status: nil, warnings: nil)
@pipeline = pipeline
@name = name
@status = status
@warnings = warnings
end
def to_param
@ -39,5 +40,17 @@ module Ci
def builds
@builds ||= pipeline.builds.where(stage: name)
end
def success?
status.to_s == 'success'
end
def has_warnings?
if @warnings.nil?
statuses.latest.failed_but_allowed.any?
else
@warnings
end
end
end
end

View File

@ -21,6 +21,9 @@ class Commit
DIFF_HARD_LIMIT_FILES = 1000
DIFF_HARD_LIMIT_LINES = 50000
# The SHA can be between 7 and 40 hex characters.
COMMIT_SHA_PATTERN = '\h{7,40}'
class << self
def decorate(commits, project)
commits.map do |commit|
@ -52,6 +55,10 @@ class Commit
def from_hash(hash, project)
new(Gitlab::Git::Commit.new(hash), project)
end
def valid_hash?(key)
!!(/\A#{COMMIT_SHA_PATTERN}\z/ =~ key)
end
end
attr_accessor :raw
@ -77,8 +84,6 @@ class Commit
# Pattern used to extract commit references from text
#
# The SHA can be between 7 and 40 hex characters.
#
# This pattern supports cross-project references.
def self.reference_pattern
@reference_pattern ||= %r{
@ -88,7 +93,7 @@ class Commit
end
def self.link_reference_pattern
@link_reference_pattern ||= super("commit", /(?<commit>\h{7,40})/)
@link_reference_pattern ||= super("commit", /(?<commit>#{COMMIT_SHA_PATTERN})/)
end
def to_reference(from_project = nil, full: false)

View File

@ -1,6 +1,7 @@
module HasStatus
extend ActiveSupport::Concern
DEFAULT_STATUS = 'created'
AVAILABLE_STATUSES = %w[created pending running success failed canceled skipped]
STARTED_STATUSES = %w[running success failed skipped]
ACTIVE_STATUSES = %w[pending running]

View File

@ -11,7 +11,7 @@ module Taskable
INCOMPLETE = 'incomplete'.freeze
ITEM_PATTERN = /
^
(?:\s*[-+*]|(?:\d+\.))? # optional list prefix
\s*(?:[-+*]|(?:\d+\.))? # optional list prefix
\s* # optional whitespace prefix
(\[\s\]|\[[xX]\]) # checkbox
(\s.+) # followed by whitespace and some text.

View File

@ -4,6 +4,8 @@ class Key < ActiveRecord::Base
include AfterCommitQueue
include Sortable
LAST_USED_AT_REFRESH_TIME = 1.day.to_i
belongs_to :user
before_validation :generate_fingerprint
@ -50,7 +52,10 @@ class Key < ActiveRecord::Base
end
def update_last_used_at
UseKeyWorker.perform_async(self.id)
lease = Gitlab::ExclusiveLease.new("key_update_last_used_at:#{id}", timeout: LAST_USED_AT_REFRESH_TIME)
return unless lease.try_obtain
UseKeyWorker.perform_async(id)
end
def add_to_shell

View File

@ -131,6 +131,8 @@ class Namespace < ActiveRecord::Base
Gitlab::UploadsTransfer.new.rename_namespace(path_was, path)
remove_exports!
# If repositories moved successfully we need to
# send update instructions to users.
# However we cannot allow rollback since we moved namespace dir
@ -219,6 +221,8 @@ class Namespace < ActiveRecord::Base
GitlabShellWorker.perform_in(5.minutes, :rm_namespace, repository_storage_path, new_path)
end
end
remove_exports!
end
def refresh_access_of_projects_invited_groups
@ -231,4 +235,20 @@ class Namespace < ActiveRecord::Base
def full_path_changed?
path_changed? || parent_id_changed?
end
def remove_exports!
Gitlab::Popen.popen(%W(find #{export_path} -not -path #{export_path} -delete))
end
def export_path
File.join(Gitlab::ImportExport.storage_path, full_path_was)
end
def full_path_was
if parent
parent.full_path + '/' + path_was
else
path_was
end
end
end

View File

@ -121,8 +121,6 @@ class Project < ActiveRecord::Base
# Merge Requests for target project should be removed with it
has_many :merge_requests, dependent: :destroy, foreign_key: 'target_project_id'
# Merge requests from source project should be kept when source project was removed
has_many :fork_merge_requests, foreign_key: 'source_project_id', class_name: 'MergeRequest'
has_many :issues, dependent: :destroy
has_many :labels, dependent: :destroy, class_name: 'ProjectLabel'
has_many :services, dependent: :destroy

View File

@ -25,7 +25,7 @@ You can create a Personal Access Token here:
http://app.asana.com/-/account_api'
end
def to_param
def self.to_param
'asana'
end
@ -44,7 +44,7 @@ http://app.asana.com/-/account_api'
]
end
def supported_events
def self.supported_events
%w(push)
end

View File

@ -12,7 +12,7 @@ class AssemblaService < Service
'Project Management Software (Source Commits Endpoint)'
end
def to_param
def self.to_param
'assembla'
end
@ -23,7 +23,7 @@ class AssemblaService < Service
]
end
def supported_events
def self.supported_events
%w(push)
end

View File

@ -40,7 +40,7 @@ class BambooService < CiService
'You must set up automatic revision labeling and a repository trigger in Bamboo.'
end
def to_param
def self.to_param
'bamboo'
end
@ -56,10 +56,6 @@ class BambooService < CiService
]
end
def supported_events
%w(push)
end
def build_page(sha, ref)
with_reactive_cache(sha, ref) {|cached| cached[:build_page] }
end

View File

@ -19,7 +19,7 @@ class BugzillaService < IssueTrackerService
end
end
def to_param
def self.to_param
'bugzilla'
end
end

View File

@ -24,10 +24,6 @@ class BuildkiteService < CiService
hook.save
end
def supported_events
%w(push)
end
def execute(data)
return unless supported_events.include?(data[:object_kind])
@ -54,7 +50,7 @@ class BuildkiteService < CiService
'Continuous integration and deployments'
end
def to_param
def self.to_param
'buildkite'
end

View File

@ -19,11 +19,11 @@ class BuildsEmailService < Service
'Email the builds status to a list of recipients.'
end
def to_param
def self.to_param
'builds_email'
end
def supported_events
def self.supported_events
%w(build)
end

View File

@ -12,7 +12,7 @@ class CampfireService < Service
'Simple web-based real-time group chat'
end
def to_param
def self.to_param
'campfire'
end
@ -24,7 +24,7 @@ class CampfireService < Service
]
end
def supported_events
def self.supported_events
%w(push)
end

View File

@ -25,7 +25,7 @@ class ChatNotificationService < Service
valid?
end
def supported_events
def self.supported_events
%w[push issue confidential_issue merge_request note tag_push
build pipeline wiki_page]
end
@ -82,19 +82,19 @@ class ChatNotificationService < Service
def get_message(object_kind, data)
case object_kind
when "push", "tag_push"
PushMessage.new(data)
ChatMessage::PushMessage.new(data)
when "issue"
IssueMessage.new(data) unless is_update?(data)
ChatMessage::IssueMessage.new(data) unless is_update?(data)
when "merge_request"
MergeMessage.new(data) unless is_update?(data)
ChatMessage::MergeMessage.new(data) unless is_update?(data)
when "note"
NoteMessage.new(data)
ChatMessage::NoteMessage.new(data)
when "build"
BuildMessage.new(data) if should_build_be_notified?(data)
ChatMessage::BuildMessage.new(data) if should_build_be_notified?(data)
when "pipeline"
PipelineMessage.new(data) if should_pipeline_be_notified?(data)
ChatMessage::PipelineMessage.new(data) if should_pipeline_be_notified?(data)
when "wiki_page"
WikiPageMessage.new(data)
ChatMessage::WikiPageMessage.new(data)
end
end

View File

@ -13,8 +13,8 @@ class ChatSlashCommandsService < Service
ActiveSupport::SecurityUtils.variable_size_secure_compare(token, self.token)
end
def supported_events
[]
def self.supported_events
%w()
end
def can_test?

View File

@ -8,7 +8,7 @@ class CiService < Service
self.respond_to?(:token) && self.token.present? && ActiveSupport::SecurityUtils.variable_size_secure_compare(token, self.token)
end
def supported_events
def self.supported_events
%w(push)
end

View File

@ -23,7 +23,7 @@ class CustomIssueTrackerService < IssueTrackerService
end
end
def to_param
def self.to_param
'custom_issue_tracker'
end

View File

@ -5,8 +5,8 @@
class DeploymentService < Service
default_value_for :category, 'deployment'
def supported_events
[]
def self.supported_events
%w()
end
def predefined_variables

View File

@ -32,7 +32,7 @@ class DroneCiService < CiService
true
end
def supported_events
def self.supported_events
%w(push merge_request tag_push)
end
@ -87,7 +87,7 @@ class DroneCiService < CiService
'Drone is a Continuous Integration platform built on Docker, written in Go'
end
def to_param
def self.to_param
'drone_ci'
end

View File

@ -12,11 +12,11 @@ class EmailsOnPushService < Service
'Email the commits and diff of each push to a list of recipients.'
end
def to_param
def self.to_param
'emails_on_push'
end
def supported_events
def self.supported_events
%w(push tag_push)
end

View File

@ -13,7 +13,7 @@ class ExternalWikiService < Service
'Replaces the link to the internal wiki with a link to an external wiki.'
end
def to_param
def self.to_param
'external_wiki'
end
@ -29,4 +29,8 @@ class ExternalWikiService < Service
nil
end
end
def self.supported_events
%w()
end
end

View File

@ -12,7 +12,7 @@ class FlowdockService < Service
'Flowdock is a collaboration web app for technical teams.'
end
def to_param
def self.to_param
'flowdock'
end
@ -22,7 +22,7 @@ class FlowdockService < Service
]
end
def supported_events
def self.supported_events
%w(push)
end

View File

@ -12,7 +12,7 @@ class GemnasiumService < Service
'Gemnasium monitors your project dependencies and alerts you about updates and security vulnerabilities.'
end
def to_param
def self.to_param
'gemnasium'
end
@ -23,7 +23,7 @@ class GemnasiumService < Service
]
end
def supported_events
def self.supported_events
%w(push)
end

View File

@ -7,7 +7,7 @@ class GitlabIssueTrackerService < IssueTrackerService
default_value_for :default, true
def to_param
def self.to_param
'gitlab'
end

View File

@ -27,7 +27,7 @@ class HipchatService < Service
'Private group chat and IM'
end
def to_param
def self.to_param
'hipchat'
end
@ -45,7 +45,7 @@ class HipchatService < Service
]
end
def supported_events
def self.supported_events
%w(push issue confidential_issue merge_request note tag_push build)
end

View File

@ -17,11 +17,11 @@ class IrkerService < Service
'gateway.'
end
def to_param
def self.to_param
'irker'
end
def supported_events
def self.supported_events
%w(push)
end

View File

@ -57,7 +57,7 @@ class IssueTrackerService < Service
end
end
def supported_events
def self.supported_events
%w(push)
end

View File

@ -12,7 +12,7 @@ class JiraService < IssueTrackerService
# This is confusing, but JiraService does not really support these events.
# The values here are required to display correct options in the service
# configuration screen.
def supported_events
def self.supported_events
%w(commit merge_request)
end
@ -81,7 +81,7 @@ class JiraService < IssueTrackerService
end
end
def to_param
def self.to_param
'jira'
end

View File

@ -52,7 +52,7 @@ class KubernetesService < DeploymentService
'deployments with `app=$CI_ENVIRONMENT_SLUG`'
end
def to_param
def self.to_param
'kubernetes'
end

View File

@ -7,7 +7,7 @@ class MattermostService < ChatNotificationService
'Receive event notifications in Mattermost'
end
def to_param
def self.to_param
'mattermost'
end
@ -36,6 +36,6 @@ class MattermostService < ChatNotificationService
end
def default_channel_placeholder
"#town-square"
"town-square"
end
end

View File

@ -15,7 +15,7 @@ class MattermostSlashCommandsService < ChatSlashCommandsService
"Perform common operations on GitLab in Mattermost"
end
def to_param
def self.to_param
'mattermost_slash_commands'
end

View File

@ -15,11 +15,11 @@ class PipelinesEmailService < Service
'Email the pipelines status to a list of recipients.'
end
def to_param
def self.to_param
'pipelines_email'
end
def supported_events
def self.supported_events
%w[pipeline]
end

View File

@ -14,7 +14,7 @@ class PivotaltrackerService < Service
'Project Management Software (Source Commits Endpoint)'
end
def to_param
def self.to_param
'pivotaltracker'
end
@ -34,7 +34,7 @@ class PivotaltrackerService < Service
]
end
def supported_events
def self.supported_events
%w(push)
end

View File

@ -13,7 +13,7 @@ class PushoverService < Service
'Pushover makes it easy to get real-time notifications on your Android device, iPhone, iPad, and Desktop.'
end
def to_param
def self.to_param
'pushover'
end
@ -61,7 +61,7 @@ class PushoverService < Service
]
end
def supported_events
def self.supported_events
%w(push)
end

View File

@ -19,7 +19,7 @@ class RedmineService < IssueTrackerService
end
end
def to_param
def self.to_param
'redmine'
end
end

View File

@ -7,7 +7,7 @@ class SlackService < ChatNotificationService
'Receive event notifications in Slack'
end
def to_param
def self.to_param
'slack'
end

View File

@ -9,7 +9,7 @@ class SlackSlashCommandsService < ChatSlashCommandsService
"Perform common operations on GitLab in Slack"
end
def to_param
def self.to_param
'slack_slash_commands'
end

View File

@ -43,14 +43,10 @@ class TeamcityService < CiService
'requests build, that setting is in the vsc root advanced settings.'
end
def to_param
def self.to_param
'teamcity'
end
def supported_events
%w(push)
end
def fields
[
{ type: 'text', name: 'teamcity_url',

View File

@ -76,6 +76,11 @@ class Service < ActiveRecord::Base
def to_param
# implement inside child
self.class.to_param
end
def self.to_param
raise NotImplementedError
end
def fields
@ -92,7 +97,11 @@ class Service < ActiveRecord::Base
end
def event_names
supported_events.map { |event| "#{event}_events" }
self.class.event_names
end
def self.event_names
self.supported_events.map { |event| "#{event}_events" }
end
def event_field(event)
@ -104,6 +113,10 @@ class Service < ActiveRecord::Base
end
def supported_events
self.class.supported_events
end
def self.supported_events
%w(push tag_push issue confidential_issue merge_request wiki_page)
end

View File

@ -40,10 +40,12 @@ class PipelineEntity < Grape::Entity
end
expose :path do |pipeline|
namespace_project_tree_path(
pipeline.project.namespace,
pipeline.project,
id: pipeline.ref)
if pipeline.ref
namespace_project_tree_path(
pipeline.project.namespace,
pipeline.project,
id: pipeline.ref)
end
end
expose :tag?, as: :tag

View File

@ -6,6 +6,14 @@ module Ci
runner.tick_runner_queue
end
end
return unless build.project.shared_runners_enabled?
Ci::Runner.shared.each do |runner|
if runner.can_pick?(build)
runner.tick_runner_queue
end
end
end
end
end

View File

@ -38,15 +38,13 @@ module MergeRequests
private
def merge_requests_for(branch)
origin_merge_requests = @project.origin_merge_requests
.opened.where(source_branch: branch).to_a
fork_merge_requests = @project.fork_merge_requests
.opened.where(source_branch: branch).to_a
(origin_merge_requests + fork_merge_requests)
.uniq.select(&:source_project)
# Returns all origin and fork merge requests from `@project` satisfying passed arguments.
def merge_requests_for(source_branch, mr_states: [:opened])
MergeRequest
.with_state(mr_states)
.where(source_branch: source_branch, source_project_id: @project.id)
.preload(:source_project) # we don't need a #includes since we're just preloading for the #select
.select(&:source_project)
end
def pipeline_merge_requests(pipeline)

View File

@ -42,7 +42,7 @@ module MergeRequests
commit_ids.include?(merge_request.diff_head_sha)
end
merge_requests.uniq.select(&:source_project).each do |merge_request|
filter_merge_requests(merge_requests).each do |merge_request|
MergeRequests::PostMergeService.
new(merge_request.target_project, @current_user).
execute(merge_request)
@ -58,10 +58,13 @@ module MergeRequests
def reload_merge_requests
merge_requests = @project.merge_requests.opened.
by_source_or_target_branch(@branch_name).to_a
merge_requests += fork_merge_requests
merge_requests = filter_merge_requests(merge_requests)
merge_requests.each do |merge_request|
# Fork merge requests
merge_requests += MergeRequest.opened
.where(source_branch: @branch_name, source_project: @project)
.where.not(target_project: @project).to_a
filter_merge_requests(merge_requests).each do |merge_request|
if merge_request.source_branch == @branch_name || force_push?
merge_request.reload_diff
else
@ -175,16 +178,7 @@ module MergeRequests
end
def merge_requests_for_source_branch
@source_merge_requests ||= begin
merge_requests = @project.origin_merge_requests.opened.where(source_branch: @branch_name).to_a
merge_requests += fork_merge_requests
filter_merge_requests(merge_requests)
end
end
def fork_merge_requests
@fork_merge_requests ||= @project.fork_merge_requests.opened.
where(source_branch: @branch_name).to_a
@source_merge_requests ||= merge_requests_for(@branch_name)
end
def branch_added?

View File

@ -1,3 +1,6 @@
- content_for :page_specific_javascripts do
= page_specific_javascript_tag('merge_request_widget/ci_bundle.js')
%h4
Set by #{link_to_member(@project, @merge_request.merge_user, avatar: true)}
to be merged automatically when the pipeline succeeds.

View File

@ -1,4 +1,4 @@
%button.choose-btn.btn.btn-sm.js-choose-group-avatar-button
%button.choose-btn.btn.btn-sm.js-choose-group-avatar-button{ type: 'button' }
%i.fa.fa-paperclip
%span Choose File ...
&nbsp;

View File

@ -11,13 +11,13 @@
class: "check_all_issues left"
.issues-other-filters.filtered-search-container
.filtered-search-input-container
%input.form-control.filtered-search{ placeholder: 'Search or filter results...', 'data-id' => 'filtered-search', 'data-project-id' => @project.id }
%input.form-control.filtered-search{ placeholder: 'Search or filter results...', 'data-id' => 'filtered-search', 'data-project-id' => @project.id, 'data-username-params' => @users.to_json(only: [:id, :username]) }
= icon('filter')
%button.clear-search.hidden{ type: 'button' }
= icon('times')
#js-dropdown-hint.dropdown-menu.hint-dropdown
%ul{ 'data-dropdown' => true }
%li.filter-dropdown-item{ 'data-value' => '' }
%li.filter-dropdown-item{ 'data-action' => 'submit' }
%button.btn.btn-link
= icon('search')
%span
@ -47,6 +47,10 @@
%li.filter-dropdown-item{ 'data-value' => 'none' }
%button.btn.btn-link
No Assignee
- if current_user
%li.filter-dropdown-item{ 'data-value' => current_user.to_reference }
%button.btn.btn-link
Assigned to me
%li.divider
%ul.filter-dropdown{ 'data-dynamic' => true, 'data-dropdown' => true }
%li.filter-dropdown-item
@ -121,7 +125,13 @@
new MilestoneSelect();
new IssueStatusSelect();
new SubscriptionSelect();
$('form.filter-form').on('submit', function (event) {
event.preventDefault();
Turbolinks.visit(this.action + '&' + $(this).serialize());
$(document).off('page:restore').on('page:restore', function (event) {
if (gl.FilteredSearchManager) {
new gl.FilteredSearchManager();
}
Issuable.init();
new gl.IssuableBulkActions({
prefixId: 'issue_',
});
});

View File

@ -1,4 +0,0 @@
---
title: Go to a project order
merge_request: 7737
author: Jacopo Beschi @jacopo-beschi

View File

@ -1,4 +0,0 @@
---
title: Fix double spaced CI log
merge_request: 8349
author: Jared Deckard <jared.deckard@gmail.com>

View File

@ -1,4 +0,0 @@
---
title: Allow group and project paths when transferring projects via the API
merge_request:
author:

View File

@ -1,4 +0,0 @@
---
title: Prevent empty pagination when list is not empty
merge_request: 8172
author:

View File

@ -1,4 +0,0 @@
---
title: Improve visibility of "Resolve conflicts" and "Merge locally" actions
merge_request: 8229
author:

View File

@ -1,4 +0,0 @@
---
title: Reduce DB-load for build-queues by storing last_update in Redis
merge_request: 8084
author:

View File

@ -1,4 +0,0 @@
---
title: Remove Lock Icon on Protected Tag
merge_request: 8513
author: Sergey Nikitin

View File

@ -0,0 +1,4 @@
---
title: Handle unsubscribe from email notifications via replying to reply+%{key}+unsubscribe@ address
merge_request: 6597
author:

View File

@ -0,0 +1,4 @@
---
title: Allow creating protected branches when user can merge to such branch
merge_request: 8458
author:

View File

@ -0,0 +1,4 @@
---
title: Adds service trigger events to api
merge_request: 8324
author:

View File

@ -1,4 +0,0 @@
---
title: Updated project visibility settings UX
merge_request: 7645
author:

View File

@ -1,4 +0,0 @@
---
title: Treat environments matching `production/*` as Production
merge_request: 8500
author:

View File

@ -1,4 +0,0 @@
---
title: Query external CI statuses in the background
merge_request:
author:

View File

@ -1,4 +0,0 @@
---
title: fix button layout issue on branches page
merge_request: 8074
author:

View File

@ -0,0 +1,4 @@
---
title: 'Allows to search within project by commit hash'
merge_request:
author: YarNayar

View File

@ -1,4 +0,0 @@
---
title: ensure permalinks scroll to correct position on multiple clicks
merge_request: 8046
author:

View File

@ -1,4 +0,0 @@
---
title: Support slash comand `/merge` for merging merge requests.
merge_request: 7746
author: Jarka Kadlecova

View File

@ -0,0 +1,4 @@
---
title: Fix nested tasks in ordered list
merge_request: 8626
author:

View File

@ -1,4 +0,0 @@
---
title: Added number_with_delimiter to counter on milestone panels
merge_request:
author: Ryan Harris

View File

@ -1,4 +0,0 @@
---
title: Adds label to Environments "Date Created"
merge_request: 8376
author: Saad Shahd

Some files were not shown because too many files have changed in this diff Show More