diff options
196 files changed, 1233 insertions, 831 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 68690ff33da..d30deef0096 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -35,7 +35,6 @@ stages: .dedicated-runner: &dedicated-runner tags: - gitlab-org - - 2gb .knapsack-state: &knapsack-state services: [] diff --git a/CHANGELOG.md b/CHANGELOG.md index cabfef84b24..aecacbee2f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/GITLAB_WORKHORSE_VERSION b/GITLAB_WORKHORSE_VERSION index 6085e946503..f0bb29e7638 100644 --- a/GITLAB_WORKHORSE_VERSION +++ b/GITLAB_WORKHORSE_VERSION @@ -1 +1 @@ -1.2.1 +1.3.0 @@ -1 +1 @@ -8.16.0-pre +8.17.0-pre diff --git a/app/assets/javascripts/droplab/droplab.js b/app/assets/javascripts/droplab/droplab.js index ed545ec8748..c79f0230951 100644 --- a/app/assets/javascripts/droplab/droplab.js +++ b/app/assets/javascripts/droplab/droplab.js @@ -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) ); }; diff --git a/app/assets/javascripts/extensions/custom_event.js.es6 b/app/assets/javascripts/extensions/custom_event.js.es6 new file mode 100644 index 00000000000..abedae4c1c7 --- /dev/null +++ b/app/assets/javascripts/extensions/custom_event.js.es6 @@ -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; diff --git a/app/assets/javascripts/filtered_search/dropdown_hint.js.es6 b/app/assets/javascripts/filtered_search/dropdown_hint.js.es6 index 63c20f57520..f4ec3b206cc 100644 --- a/app/assets/javascripts/filtered_search/dropdown_hint.js.es6 +++ b/app/assets/javascripts/filtered_search/dropdown_hint.js.es6 @@ -9,7 +9,7 @@ this.config = { droplabFilter: { template: 'hint', - filterFunction: gl.DropdownUtils.filterHint, + filterFunction: gl.DropdownUtils.filterHint.bind(null, input), }, }; } diff --git a/app/assets/javascripts/filtered_search/dropdown_non_user.js.es6 b/app/assets/javascripts/filtered_search/dropdown_non_user.js.es6 index f06c3fc9c6f..13cbec1be4a 100644 --- a/app/assets/javascripts/filtered_search/dropdown_non_user.js.es6 +++ b/app/assets/javascripts/filtered_search/dropdown_non_user.js.es6 @@ -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), }, }; } diff --git a/app/assets/javascripts/filtered_search/dropdown_user.js.es6 b/app/assets/javascripts/filtered_search/dropdown_user.js.es6 index e80d266ae89..7bf199d9274 100644 --- a/app/assets/javascripts/filtered_search/dropdown_user.js.es6 +++ b/app/assets/javascripts/filtered_search/dropdown_user.js.es6 @@ -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 || ''; diff --git a/app/assets/javascripts/filtered_search/dropdown_utils.js.es6 b/app/assets/javascripts/filtered_search/dropdown_utils.js.es6 index c27ef3042d1..443ac222f70 100644 --- a/app/assets/javascripts/filtered_search/dropdown_utils.js.es6 +++ b/app/assets/javascripts/filtered_search/dropdown_utils.js.es6 @@ -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 || {}; diff --git a/app/assets/javascripts/filtered_search/filtered_search_dropdown.js.es6 b/app/assets/javascripts/filtered_search/filtered_search_dropdown.js.es6 index 886d8113f4a..9128ea907b3 100644 --- a/app/assets/javascripts/filtered_search/filtered_search_dropdown.js.es6 +++ b/app/assets/javascripts/filtered_search/filtered_search_dropdown.js.es6 @@ -78,7 +78,10 @@ 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, + })); } hideDropdown() { diff --git a/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js.es6 b/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js.es6 index 1cd0483877a..408a0dfd768 100644 --- a/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js.es6 +++ b/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js.es6 @@ -57,28 +57,25 @@ 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]; - - // 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 = 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); - } + // Get the string to replace + const selectionStart = input.selectionStart; + const { left, right } = gl.DropdownUtils.getInputSelectionPosition(input); + + input.value = `${inputValue.substr(0, left)}${word}${inputValue.substr(right)}`; + gl.FilteredSearchDropdownManager.updateInputCaretPosition(selectionStart, input); + } + + static updateInputCaretPosition(selectionStart, input) { + // Reset the position + // Sometimes can end up at end of input + input.setSelectionRange(selectionStart, selectionStart); - input.value += word; + const { right } = gl.DropdownUtils.getInputSelectionPosition(input); + + input.setSelectionRange(right, right); } updateCurrentDropdownOffset() { @@ -90,9 +87,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 +154,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(); } diff --git a/app/assets/javascripts/filtered_search/filtered_search_manager.js.es6 b/app/assets/javascripts/filtered_search/filtered_search_manager.js.es6 index ffd0d7e9cba..c7b72b36561 100644 --- a/app/assets/javascripts/filtered_search/filtered_search_manager.js.es6 +++ b/app/assets/javascripts/filtered_search/filtered_search_manager.js.es6 @@ -30,11 +30,14 @@ 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.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); } @@ -43,6 +46,8 @@ 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); } @@ -85,6 +90,7 @@ loadSearchParamsFromURL() { const params = gl.utils.getUrlParamsArray(); + const usernameParams = this.getUsernameParams(); const inputValues = []; params.forEach((p) => { @@ -115,6 +121,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 +180,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 || {}; diff --git a/app/assets/javascripts/group_avatar.js b/app/assets/javascripts/group_avatar.js index 5247b2a08f7..10dfd05fe3c 100644 --- a/app/assets/javascripts/group_avatar.js +++ b/app/assets/javascripts/group_avatar.js @@ -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(/^.*[\\\/]/, ''); diff --git a/app/assets/javascripts/merge_request_widget.js.es6 b/app/assets/javascripts/merge_request_widget.js.es6 index 7a315e43667..7cc319e2f4e 100644 --- a/app/assets/javascripts/merge_request_widget.js.es6 +++ b/app/assets/javascripts/merge_request_widget.js.es6 @@ -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')); }); }; diff --git a/app/assets/javascripts/merge_request_widget/ci_bundle.js.es6 b/app/assets/javascripts/merge_request_widget/ci_bundle.js.es6 index 2b074994b4a..5969d2ba56b 100644 --- a/app/assets/javascripts/merge_request_widget/ci_bundle.js.es6 +++ b/app/assets/javascripts/merge_request_widget/ci_bundle.js.es6 @@ -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 { diff --git a/app/assets/javascripts/vue_pipelines_index/stage.js.es6 b/app/assets/javascripts/vue_pipelines_index/stage.js.es6 index 32973132174..4e85f16ebc5 100644 --- a/app/assets/javascripts/vue_pipelines_index/stage.js.es6 +++ b/app/assets/javascripts/vue_pipelines_index/stage.js.es6 @@ -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" diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss index 324c6cec96a..93cc5a8cf0a 100644 --- a/app/assets/stylesheets/pages/issuable.scss +++ b/app/assets/stylesheets/pages/issuable.scss @@ -377,6 +377,10 @@ display: inline-block; padding: 5px; + &:nth-of-type(7n) { + padding-right: 0; + } + .author_link { display: block; } diff --git a/app/controllers/projects/hooks_controller.rb b/app/controllers/projects/hooks_controller.rb index 0ae8ff98009..b668a9331e7 100644 --- a/app/controllers/projects/hooks_controller.rb +++ b/app/controllers/projects/hooks_controller.rb @@ -6,21 +6,15 @@ class Projects::HooksController < Projects::ApplicationController layout "project_settings" - def index - @hooks = @project.hooks - @hook = ProjectHook.new - end - def create @hook = @project.hooks.new(hook_params) @hook.save - if @hook.valid? - redirect_to namespace_project_hooks_path(@project.namespace, @project) - else + unless @hook.valid? @hooks = @project.hooks.select(&:persisted?) - render :index + flash[:alert] = @hook.errors.full_messages.join.html_safe end + redirect_to namespace_project_settings_integrations_path(@project.namespace, @project) end def test @@ -44,7 +38,7 @@ class Projects::HooksController < Projects::ApplicationController def destroy hook.destroy - redirect_to namespace_project_hooks_path(@project.namespace, @project) + redirect_to namespace_project_settings_integrations_path(@project.namespace, @project) end private diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb index 2beb0df8a07..8472ceca329 100644 --- a/app/controllers/projects/issues_controller.rb +++ b/app/controllers/projects/issues_controller.rb @@ -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 } diff --git a/app/controllers/projects/services_controller.rb b/app/controllers/projects/services_controller.rb index 30c2a5d9982..17cb1d5be24 100644 --- a/app/controllers/projects/services_controller.rb +++ b/app/controllers/projects/services_controller.rb @@ -9,10 +9,6 @@ class Projects::ServicesController < Projects::ApplicationController layout "project_settings" - def index - @services = @project.find_or_initialize_services - end - def edit end diff --git a/app/controllers/projects/settings/integrations_controller.rb b/app/controllers/projects/settings/integrations_controller.rb new file mode 100644 index 00000000000..fb2a4837735 --- /dev/null +++ b/app/controllers/projects/settings/integrations_controller.rb @@ -0,0 +1,18 @@ +module Projects + module Settings + class IntegrationsController < Projects::ApplicationController + include ServiceParams + + before_action :authorize_admin_project! + layout "project_settings" + + def show + @hooks = @project.hooks + @hook = ProjectHook.new + + # Services + @services = @project.find_or_initialize_services + end + end + end +end diff --git a/app/helpers/gitlab_routing_helper.rb b/app/helpers/gitlab_routing_helper.rb index 5742fec4458..2159e4ce21a 100644 --- a/app/helpers/gitlab_routing_helper.rb +++ b/app/helpers/gitlab_routing_helper.rb @@ -208,6 +208,10 @@ module GitlabRoutingHelper end # Settings + def project_settings_integrations_path(project, *args) + namespace_project_settings_integrations_path(project.namespace, project, *args) + end + def project_settings_members_path(project, *args) namespace_project_settings_members_path(project.namespace, project, *args) end diff --git a/app/models/ci/runner.rb b/app/models/ci/runner.rb index 6e58a1878c8..ed1843ba005 100644 --- a/app/models/ci/runner.rb +++ b/app/models/ci/runner.rb @@ -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 diff --git a/app/models/key.rb b/app/models/key.rb index 8be29c697f1..9c74ca84753 100644 --- a/app/models/key.rb +++ b/app/models/key.rb @@ -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 diff --git a/app/serializers/pipeline_entity.rb b/app/serializers/pipeline_entity.rb index d04a4990cb0..61f0f11d7d2 100644 --- a/app/serializers/pipeline_entity.rb +++ b/app/serializers/pipeline_entity.rb @@ -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 diff --git a/app/services/ci/update_build_queue_service.rb b/app/services/ci/update_build_queue_service.rb index 2e901016666..152c8ae5006 100644 --- a/app/services/ci/update_build_queue_service.rb +++ b/app/services/ci/update_build_queue_service.rb @@ -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 diff --git a/app/views/layouts/nav/_project_settings.html.haml b/app/views/layouts/nav/_project_settings.html.haml index 0fb2bb460cb..c6df66d2c3c 100644 --- a/app/views/layouts/nav/_project_settings.html.haml +++ b/app/views/layouts/nav/_project_settings.html.haml @@ -8,14 +8,10 @@ = link_to namespace_project_deploy_keys_path(@project.namespace, @project), title: 'Deploy Keys' do %span Deploy Keys - = nav_link(controller: :hooks) do - = link_to namespace_project_hooks_path(@project.namespace, @project), title: 'Webhooks' do + = nav_link(controller: :integrations) do + = link_to namespace_project_settings_integrations_path(@project.namespace, @project), title: 'Integrations' do %span - Webhooks - = nav_link(controller: :services) do - = link_to namespace_project_services_path(@project.namespace, @project), title: 'Services' do - %span - Services + Integrations = nav_link(controller: :protected_branches) do = link_to namespace_project_protected_branches_path(@project.namespace, @project), title: 'Protected Branches' do %span diff --git a/app/views/projects/hooks/index.html.haml b/app/views/projects/hooks/_index.html.haml index 8faad351463..8faad351463 100644 --- a/app/views/projects/hooks/index.html.haml +++ b/app/views/projects/hooks/_index.html.haml diff --git a/app/views/projects/merge_requests/widget/open/_merge_when_build_succeeds.html.haml b/app/views/projects/merge_requests/widget/open/_merge_when_build_succeeds.html.haml index 072d01d144e..f70cd09c5f4 100644 --- a/app/views/projects/merge_requests/widget/open/_merge_when_build_succeeds.html.haml +++ b/app/views/projects/merge_requests/widget/open/_merge_when_build_succeeds.html.haml @@ -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. diff --git a/app/views/projects/services/index.html.haml b/app/views/projects/services/_index.html.haml index 66fd3029dc9..964133504e6 100644 --- a/app/views/projects/services/index.html.haml +++ b/app/views/projects/services/_index.html.haml @@ -1,5 +1,3 @@ -- page_title "Services" - .row.prepend-top-default.append-bottom-default .col-lg-3 %h4.prepend-top-0 diff --git a/app/views/projects/hooks/_project_hook.html.haml b/app/views/projects/settings/integrations/_project_hook.html.haml index ceabe2eab3d..ceabe2eab3d 100644 --- a/app/views/projects/hooks/_project_hook.html.haml +++ b/app/views/projects/settings/integrations/_project_hook.html.haml diff --git a/app/views/projects/settings/integrations/show.html.haml b/app/views/projects/settings/integrations/show.html.haml new file mode 100644 index 00000000000..aa38a889cdd --- /dev/null +++ b/app/views/projects/settings/integrations/show.html.haml @@ -0,0 +1,3 @@ +- page_title 'Integrations' += render 'projects/hooks/index' += render 'projects/services/index' diff --git a/app/views/shared/_choose_group_avatar_button.html.haml b/app/views/shared/_choose_group_avatar_button.html.haml index ee043910548..94295970acf 100644 --- a/app/views/shared/_choose_group_avatar_button.html.haml +++ b/app/views/shared/_choose_group_avatar_button.html.haml @@ -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 ... diff --git a/app/views/shared/issuable/_search_bar.html.haml b/app/views/shared/issuable/_search_bar.html.haml index 8d7b1d616f4..44152319736 100644 --- a/app/views/shared/issuable/_search_bar.html.haml +++ b/app/views/shared/issuable/_search_bar.html.haml @@ -11,7 +11,7 @@ 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') @@ -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 @@ -125,3 +129,13 @@ 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_', + }); + }); diff --git a/app/views/shared/web_hooks/_form.html.haml b/app/views/shared/web_hooks/_form.html.haml index 5d659eb83a9..13586a5a12a 100644 --- a/app/views/shared/web_hooks/_form.html.haml +++ b/app/views/shared/web_hooks/_form.html.haml @@ -1,6 +1,3 @@ -- page_title "Webhooks" -- context_title = @project ? 'project' : 'group' - .row.prepend-top-default .col-lg-3 %h4.prepend-top-0 diff --git a/changelogs/unreleased/18786-go-to-a-project-order.yml b/changelogs/unreleased/18786-go-to-a-project-order.yml deleted file mode 100644 index 1b9e246d1a7..00000000000 --- a/changelogs/unreleased/18786-go-to-a-project-order.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Go to a project order -merge_request: 7737 -author: Jacopo Beschi @jacopo-beschi diff --git a/changelogs/unreleased/19086-double-newline.yml b/changelogs/unreleased/19086-double-newline.yml deleted file mode 100644 index dd9b58920fb..00000000000 --- a/changelogs/unreleased/19086-double-newline.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix double spaced CI log -merge_request: 8349 -author: Jared Deckard <jared.deckard@gmail.com> diff --git a/changelogs/unreleased/19966-api-call-to-move-project-to-different-group-fails-when-using-group-and-project-names-instead-of-id.yml b/changelogs/unreleased/19966-api-call-to-move-project-to-different-group-fails-when-using-group-and-project-names-instead-of-id.yml deleted file mode 100644 index 61cf047026b..00000000000 --- a/changelogs/unreleased/19966-api-call-to-move-project-to-different-group-fails-when-using-group-and-project-names-instead-of-id.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Allow group and project paths when transferring projects via the API -merge_request: -author: diff --git a/changelogs/unreleased/19988-prevent-empty-pagination-when-list-not-empty.yml b/changelogs/unreleased/19988-prevent-empty-pagination-when-list-not-empty.yml deleted file mode 100644 index 5570ede4a9a..00000000000 --- a/changelogs/unreleased/19988-prevent-empty-pagination-when-list-not-empty.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Prevent empty pagination when list is not empty -merge_request: 8172 -author: diff --git a/changelogs/unreleased/21135-resolve-these-conflicts-link-is-too-subtle.yml b/changelogs/unreleased/21135-resolve-these-conflicts-link-is-too-subtle.yml deleted file mode 100644 index 574c322803c..00000000000 --- a/changelogs/unreleased/21135-resolve-these-conflicts-link-is-too-subtle.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Improve visibility of "Resolve conflicts" and "Merge locally" actions -merge_request: 8229 -author: diff --git a/changelogs/unreleased/21698-redis-runner-last-build.yml b/changelogs/unreleased/21698-redis-runner-last-build.yml deleted file mode 100644 index 2aba3c353a3..00000000000 --- a/changelogs/unreleased/21698-redis-runner-last-build.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Reduce DB-load for build-queues by storing last_update in Redis -merge_request: 8084 -author: diff --git a/changelogs/unreleased/22111-remove-lock-icon-on-protected-tag.yml b/changelogs/unreleased/22111-remove-lock-icon-on-protected-tag.yml deleted file mode 100644 index e4f7c1b7762..00000000000 --- a/changelogs/unreleased/22111-remove-lock-icon-on-protected-tag.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Remove Lock Icon on Protected Tag -merge_request: 8513 -author: Sergey Nikitin diff --git a/changelogs/unreleased/24032-changed-visibility-level-to-public-but-project-is-not-public.yml b/changelogs/unreleased/24032-changed-visibility-level-to-public-but-project-is-not-public.yml deleted file mode 100644 index 875106d7dd5..00000000000 --- a/changelogs/unreleased/24032-changed-visibility-level-to-public-but-project-is-not-public.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Updated project visibility settings UX -merge_request: 7645 -author: diff --git a/changelogs/unreleased/24139-production-wildcard-for-cycle-analytics.yml b/changelogs/unreleased/24139-production-wildcard-for-cycle-analytics.yml deleted file mode 100644 index 83cf3670ec0..00000000000 --- a/changelogs/unreleased/24139-production-wildcard-for-cycle-analytics.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Treat environments matching `production/*` as Production -merge_request: 8500 -author: diff --git a/changelogs/unreleased/24185-legacy-ci-status-reactive-cache.yml b/changelogs/unreleased/24185-legacy-ci-status-reactive-cache.yml deleted file mode 100644 index 09ff63a44fb..00000000000 --- a/changelogs/unreleased/24185-legacy-ci-status-reactive-cache.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Query external CI statuses in the background -merge_request: -author: diff --git a/changelogs/unreleased/24820-buttons-in-the-branches-page-are-stacking-on-top-of-each-other-depending-on-the-selected-filter.yml b/changelogs/unreleased/24820-buttons-in-the-branches-page-are-stacking-on-top-of-each-other-depending-on-the-selected-filter.yml deleted file mode 100644 index fac7697ede1..00000000000 --- a/changelogs/unreleased/24820-buttons-in-the-branches-page-are-stacking-on-top-of-each-other-depending-on-the-selected-filter.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: fix button layout issue on branches page -merge_request: 8074 -author: diff --git a/changelogs/unreleased/24876-page-jumps-to-wrong-position-when-clicking-a-comment-anchor.yml b/changelogs/unreleased/24876-page-jumps-to-wrong-position-when-clicking-a-comment-anchor.yml deleted file mode 100644 index c31c89dc4bc..00000000000 --- a/changelogs/unreleased/24876-page-jumps-to-wrong-position-when-clicking-a-comment-anchor.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: ensure permalinks scroll to correct position on multiple clicks -merge_request: 8046 -author: diff --git a/changelogs/unreleased/24915_merge_slash_command.yml b/changelogs/unreleased/24915_merge_slash_command.yml deleted file mode 100644 index eb8ced8ab01..00000000000 --- a/changelogs/unreleased/24915_merge_slash_command.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Support slash comand `/merge` for merging merge requests. -merge_request: 7746 -author: Jarka Kadlecova diff --git a/changelogs/unreleased/25277-milestone-counter-number-with-delimiter.yml b/changelogs/unreleased/25277-milestone-counter-number-with-delimiter.yml deleted file mode 100644 index 0c9853de3b6..00000000000 --- a/changelogs/unreleased/25277-milestone-counter-number-with-delimiter.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Added number_with_delimiter to counter on milestone panels -merge_request: -author: Ryan Harris diff --git a/changelogs/unreleased/25371-environments-date-created-column-is-not-labeled.yml b/changelogs/unreleased/25371-environments-date-created-column-is-not-labeled.yml deleted file mode 100644 index 13d3476fe39..00000000000 --- a/changelogs/unreleased/25371-environments-date-created-column-is-not-labeled.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Adds label to Environments "Date Created" -merge_request: 8376 -author: Saad Shahd diff --git a/changelogs/unreleased/25430-make-colors-in-runner-status-more-colorblind-friendly.yml b/changelogs/unreleased/25430-make-colors-in-runner-status-more-colorblind-friendly.yml deleted file mode 100644 index e60c42cdfba..00000000000 --- a/changelogs/unreleased/25430-make-colors-in-runner-status-more-colorblind-friendly.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Change status colors of runners to better defaults -merge_request: -author: diff --git a/changelogs/unreleased/25507-handle-errors-environment-list.yml b/changelogs/unreleased/25507-handle-errors-environment-list.yml deleted file mode 100644 index 4e9794f7917..00000000000 --- a/changelogs/unreleased/25507-handle-errors-environment-list.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Handle HTTP errors in environment list -merge_request: -author: diff --git a/changelogs/unreleased/25580-trucate-dropdown-for-long-branch.yml b/changelogs/unreleased/25580-trucate-dropdown-for-long-branch.yml deleted file mode 100644 index 18d3ac050ae..00000000000 --- a/changelogs/unreleased/25580-trucate-dropdown-for-long-branch.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Resolves overflow in compare branch and tags dropdown -merge_request: 8118 -author: diff --git a/changelogs/unreleased/25678-remove-user-build.yml b/changelogs/unreleased/25678-remove-user-build.yml deleted file mode 100644 index 873e637d670..00000000000 --- a/changelogs/unreleased/25678-remove-user-build.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: remove build_user -merge_request: 8162 -author: Arsenev Vladislav diff --git a/changelogs/unreleased/25701-standardize-text-colors.yml b/changelogs/unreleased/25701-standardize-text-colors.yml deleted file mode 100644 index a48ca6c187d..00000000000 --- a/changelogs/unreleased/25701-standardize-text-colors.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 25701 standardize text colors -merge_request: -author: diff --git a/changelogs/unreleased/25705-your-commands-have-been-executed-is-overkill.yml b/changelogs/unreleased/25705-your-commands-have-been-executed-is-overkill.yml deleted file mode 100644 index 850e98518a6..00000000000 --- a/changelogs/unreleased/25705-your-commands-have-been-executed-is-overkill.yml +++ /dev/null @@ -1,3 +0,0 @@ ---- -title: Replace wording for slash command confirmation message -merge_request: 8123 diff --git a/changelogs/unreleased/25725-remove-window-object.yml b/changelogs/unreleased/25725-remove-window-object.yml deleted file mode 100644 index c64b71ddd33..00000000000 --- a/changelogs/unreleased/25725-remove-window-object.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Removes unneeded `window` declaration in environments related code -merge_request: 8456 -author: diff --git a/changelogs/unreleased/25776-alerts-should-be-responsive.yml b/changelogs/unreleased/25776-alerts-should-be-responsive.yml deleted file mode 100644 index 15006523d3e..00000000000 --- a/changelogs/unreleased/25776-alerts-should-be-responsive.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Changed alerts to be responsive, centered text on smaller viewports -merge_request: 8424 -author: Connor Smallman diff --git a/changelogs/unreleased/25829-update-username-button-remains-disabled-upon-failure.yml b/changelogs/unreleased/25829-update-username-button-remains-disabled-upon-failure.yml deleted file mode 100644 index c82bacd8bcd..00000000000 --- a/changelogs/unreleased/25829-update-username-button-remains-disabled-upon-failure.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: re-enable change username button after failure -merge_request: 8332 -author: diff --git a/changelogs/unreleased/25898-ci-icon-color-mr.yml b/changelogs/unreleased/25898-ci-icon-color-mr.yml deleted file mode 100644 index dd0f93e176f..00000000000 --- a/changelogs/unreleased/25898-ci-icon-color-mr.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Adds CSS class to status icon on MR widget to prevent non-colored icon -merge_request: 8219 -author: diff --git a/changelogs/unreleased/25941-odd-overflow-behavior-for-long-issue-headers.yml b/changelogs/unreleased/25941-odd-overflow-behavior-for-long-issue-headers.yml deleted file mode 100644 index c28cf7a0f86..00000000000 --- a/changelogs/unreleased/25941-odd-overflow-behavior-for-long-issue-headers.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Change earlier to task_status_short to avoid titlebar line wraps -merge_request: -author: diff --git a/changelogs/unreleased/25946-manual-pipeline-dropdown-casing.yml b/changelogs/unreleased/25946-manual-pipeline-dropdown-casing.yml deleted file mode 100644 index b753c823348..00000000000 --- a/changelogs/unreleased/25946-manual-pipeline-dropdown-casing.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Use original casing for build action text -merge_request: 8387 -author: diff --git a/changelogs/unreleased/25985-combine-members-and-groups-settings-pages.yml b/changelogs/unreleased/25985-combine-members-and-groups-settings-pages.yml deleted file mode 100644 index 206be8fe3cb..00000000000 --- a/changelogs/unreleased/25985-combine-members-and-groups-settings-pages.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Combined the settings options project members and groups into a single one - called members -merge_request: -author: diff --git a/changelogs/unreleased/25996-Move-award-emoji-out-of-the-discussion-tab-for-MR.yml b/changelogs/unreleased/25996-Move-award-emoji-out-of-the-discussion-tab-for-MR.yml deleted file mode 100644 index e05e2dd6fed..00000000000 --- a/changelogs/unreleased/25996-Move-award-emoji-out-of-the-discussion-tab-for-MR.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Move award emoji's out of the discussion tab for merge requests -merge_request: -author: diff --git a/changelogs/unreleased/26014-fix-update-doc.yml b/changelogs/unreleased/26014-fix-update-doc.yml deleted file mode 100644 index 419c032cb0f..00000000000 --- a/changelogs/unreleased/26014-fix-update-doc.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Re-order update steps in the 8.14 -> 8.15 upgrade guide -merge_request: -author: diff --git a/changelogs/unreleased/26051-fix-missing-endpoint-route-method.yml b/changelogs/unreleased/26051-fix-missing-endpoint-route-method.yml deleted file mode 100644 index 85440eb86f9..00000000000 --- a/changelogs/unreleased/26051-fix-missing-endpoint-route-method.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Don't instrument 405 Grape calls -merge_request: 8445 -author: diff --git a/changelogs/unreleased/26109-preserve-scroll-position-on-autoreload.yml b/changelogs/unreleased/26109-preserve-scroll-position-on-autoreload.yml deleted file mode 100644 index cde0d114d7c..00000000000 --- a/changelogs/unreleased/26109-preserve-scroll-position-on-autoreload.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Scroll to bottom on build completion if autoscroll was active -merge_request: 8391 -author: diff --git a/changelogs/unreleased/26129-add-link-to-branches-page.yml b/changelogs/unreleased/26129-add-link-to-branches-page.yml deleted file mode 100644 index aceb92dbb9c..00000000000 --- a/changelogs/unreleased/26129-add-link-to-branches-page.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Convert project setting text into protected branch path link -merge_request: 8377 -author: Ken Ding diff --git a/changelogs/unreleased/26134-ctrl-enter-does-not-submit-a-new-merge-request.yml b/changelogs/unreleased/26134-ctrl-enter-does-not-submit-a-new-merge-request.yml deleted file mode 100644 index 40183f8d3fa..00000000000 --- a/changelogs/unreleased/26134-ctrl-enter-does-not-submit-a-new-merge-request.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Make CTRL+Enter submits a new merge request -merge_request: 8360 -author: Saad Shahd diff --git a/changelogs/unreleased/26155-merge-request-tabs-don-t-render-when-no-commits-available.yml b/changelogs/unreleased/26155-merge-request-tabs-don-t-render-when-no-commits-available.yml deleted file mode 100644 index 242a77b5d48..00000000000 --- a/changelogs/unreleased/26155-merge-request-tabs-don-t-render-when-no-commits-available.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: display merge request discussion tab for empty branches -merge_request: 8347 -author: diff --git a/changelogs/unreleased/26192-fixes-too-short-input.yml b/changelogs/unreleased/26192-fixes-too-short-input.yml deleted file mode 100644 index ff707f4694d..00000000000 --- a/changelogs/unreleased/26192-fixes-too-short-input.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fixes too short input for placeholder message in commit listing page -merge_request: 8367 -author: diff --git a/changelogs/unreleased/26207-add-hover-animations.yml b/changelogs/unreleased/26207-add-hover-animations.yml deleted file mode 100644 index 12a69d04717..00000000000 --- a/changelogs/unreleased/26207-add-hover-animations.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Add various hover animations throughout the application -merge_request: -author: diff --git a/changelogs/unreleased/26226-generate-all-haml-fixtures-within-teaspoon-fixtures-task.yml b/changelogs/unreleased/26226-generate-all-haml-fixtures-within-teaspoon-fixtures-task.yml deleted file mode 100644 index 28981291132..00000000000 --- a/changelogs/unreleased/26226-generate-all-haml-fixtures-within-teaspoon-fixtures-task.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Precompile all JavaScript fixtures -merge_request: 8384 -author: diff --git a/changelogs/unreleased/26238-buttons-not-accessible.yml b/changelogs/unreleased/26238-buttons-not-accessible.yml deleted file mode 100644 index 34d38d45709..00000000000 --- a/changelogs/unreleased/26238-buttons-not-accessible.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fixes buttons not being accessible via the keyboard when creating new group -merge_request: 8469 -author: diff --git a/changelogs/unreleased/26261-post-api-v3-projects-idorproject-commits-commits-does-not-work-with-project-path.yml b/changelogs/unreleased/26261-post-api-v3-projects-idorproject-commits-commits-does-not-work-with-project-path.yml deleted file mode 100644 index 37bd7e46b49..00000000000 --- a/changelogs/unreleased/26261-post-api-v3-projects-idorproject-commits-commits-does-not-work-with-project-path.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix Commits API to accept a Project path upon POST -merge_request: -author: diff --git a/changelogs/unreleased/26352-user-dropdown-settings.yml b/changelogs/unreleased/26352-user-dropdown-settings.yml deleted file mode 100644 index 19bd47b8673..00000000000 --- a/changelogs/unreleased/26352-user-dropdown-settings.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 26352 Change Profile settings to User / Settings -merge_request: -author: diff --git a/changelogs/unreleased/26435-show-project-avatars-on-mobile.yml b/changelogs/unreleased/26435-show-project-avatars-on-mobile.yml deleted file mode 100644 index 43afdf45013..00000000000 --- a/changelogs/unreleased/26435-show-project-avatars-on-mobile.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Display project avatars on Admin Area and Projects pages for mobile views -merge_request: -author: Ryan Harris diff --git a/changelogs/unreleased/26445-make-icon-buttons-accessible-via-keyboard.yml b/changelogs/unreleased/26445-make-icon-buttons-accessible-via-keyboard.yml deleted file mode 100644 index b4aef8fe3da..00000000000 --- a/changelogs/unreleased/26445-make-icon-buttons-accessible-via-keyboard.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Make play button on Pipelines page accessible via keyboard -merge_request: -author: Ryan Harris diff --git a/changelogs/unreleased/26446-access-download-artifacts-via-keyboard.yml b/changelogs/unreleased/26446-access-download-artifacts-via-keyboard.yml deleted file mode 100644 index 83f6233dd88..00000000000 --- a/changelogs/unreleased/26446-access-download-artifacts-via-keyboard.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Made download artifacts button accessible via keyboard by changing it from - an anchor tag to an actual button -merge_request: -author: Ryan Harris diff --git a/changelogs/unreleased/26472-math-margin.yml b/changelogs/unreleased/26472-math-margin.yml deleted file mode 100644 index 3999f521558..00000000000 --- a/changelogs/unreleased/26472-math-margin.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Add margin to markdown math blocks -merge_request: -author: diff --git a/changelogs/unreleased/26504-mr-discussion-btn.yml b/changelogs/unreleased/26504-mr-discussion-btn.yml deleted file mode 100644 index dec74ec61b1..00000000000 --- a/changelogs/unreleased/26504-mr-discussion-btn.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 26504 Fix styling of MR jump to discussion button -merge_request: -author: diff --git a/changelogs/unreleased/26587-metrics-middleware-endpoint-is-nil.yml b/changelogs/unreleased/26587-metrics-middleware-endpoint-is-nil.yml deleted file mode 100644 index 5891a5ef6e8..00000000000 --- a/changelogs/unreleased/26587-metrics-middleware-endpoint-is-nil.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Check for env[Grape::Env::GRAPE_ROUTING_ARGS] instead of endpoint.route -merge_request: 8544 -author: diff --git a/changelogs/unreleased/26601-dropdown-makes-request-close.yml b/changelogs/unreleased/26601-dropdown-makes-request-close.yml deleted file mode 100644 index a810e04376d..00000000000 --- a/changelogs/unreleased/26601-dropdown-makes-request-close.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fixes builds dropdown making request when clicked to be closed -merge_request: 8545 -author: diff --git a/changelogs/unreleased/26615-pipeline-status-cell.yml b/changelogs/unreleased/26615-pipeline-status-cell.yml deleted file mode 100644 index 9a19b041e63..00000000000 --- a/changelogs/unreleased/26615-pipeline-status-cell.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fixes pipeline status cell is too wide by adding missing classes in table head cells -merge_request: 8549 -author: diff --git a/changelogs/unreleased/26616-fix-search-group-project-filters.yml b/changelogs/unreleased/26616-fix-search-group-project-filters.yml deleted file mode 100644 index 0fd0dbbfc24..00000000000 --- a/changelogs/unreleased/26616-fix-search-group-project-filters.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix search group/project filtering to show results -merge_request: -author: diff --git a/changelogs/unreleased/26667-pipeline-width-for-huge-pipeline.yml b/changelogs/unreleased/26667-pipeline-width-for-huge-pipeline.yml deleted file mode 100644 index 08dcc5c3e8c..00000000000 --- a/changelogs/unreleased/26667-pipeline-width-for-huge-pipeline.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fixes big pipeline and small pipeline width problems and tooltips text being outside the tooltip -merge_request: 8593 -author: diff --git a/changelogs/unreleased/26773-fix-project-statistics-repository-size.yml b/changelogs/unreleased/26773-fix-project-statistics-repository-size.yml deleted file mode 100644 index 8ce9bbcb3a9..00000000000 --- a/changelogs/unreleased/26773-fix-project-statistics-repository-size.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Adjust ProjectStatistic#repository_size with values saved as MB -merge_request: 8616 -author: diff --git a/changelogs/unreleased/26785-fix-droplab-in-ie-11-v1.yml b/changelogs/unreleased/26785-fix-droplab-in-ie-11-v1.yml new file mode 100644 index 00000000000..76e9b19b828 --- /dev/null +++ b/changelogs/unreleased/26785-fix-droplab-in-ie-11-v1.yml @@ -0,0 +1,4 @@ +--- +title: Add some basic fixes for IE11/Edge +merge_request: +author: diff --git a/changelogs/unreleased/7898-fixes-issue-boards-list-colored-top-border-visual-glitch.yml b/changelogs/unreleased/7898-fixes-issue-boards-list-colored-top-border-visual-glitch.yml deleted file mode 100644 index 74412c32375..00000000000 --- a/changelogs/unreleased/7898-fixes-issue-boards-list-colored-top-border-visual-glitch.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fixes issue boards list colored top border visual glitch -merge_request: 7898 -author: Pier Paolo Ramon diff --git a/changelogs/unreleased/8623-correct-robots-txt.yml b/changelogs/unreleased/8623-correct-robots-txt.yml deleted file mode 100644 index 00ed80511cc..00000000000 --- a/changelogs/unreleased/8623-correct-robots-txt.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: "Correct User-agent placement in robots.txt" -merge_request: 8623 -author: Eric Sabelhaus diff --git a/changelogs/unreleased/add-changelog-search-bar-first-iteration.yml b/changelogs/unreleased/add-changelog-search-bar-first-iteration.yml deleted file mode 100644 index 4d83d744be7..00000000000 --- a/changelogs/unreleased/add-changelog-search-bar-first-iteration.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Search bar redesign first iteration -merge_request: 7345 -author: diff --git a/changelogs/unreleased/add_email_password_confirmation.yml b/changelogs/unreleased/add_email_password_confirmation.yml deleted file mode 100644 index 92f9b9b7a6d..00000000000 --- a/changelogs/unreleased/add_email_password_confirmation.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Add email confirmation field to registration form -merge_request: 7432 -author: diff --git a/changelogs/unreleased/additional-award-emoji-repositioning-fixes.yml b/changelogs/unreleased/additional-award-emoji-repositioning-fixes.yml deleted file mode 100644 index 8d5a94c3aa8..00000000000 --- a/changelogs/unreleased/additional-award-emoji-repositioning-fixes.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Removed bottom padding from merge manually from CLI because of repositioning award emoji's -merge_request: -author: diff --git a/changelogs/unreleased/allow_plus_sign_for_snippets.yml b/changelogs/unreleased/allow_plus_sign_for_snippets.yml deleted file mode 100644 index 62d9dd74d07..00000000000 --- a/changelogs/unreleased/allow_plus_sign_for_snippets.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Allow to use + symbol in filenames -merge_request: 6644 -author: blackst0ne diff --git a/changelogs/unreleased/asciidoctor-plantuml.yml b/changelogs/unreleased/asciidoctor-plantuml.yml deleted file mode 100644 index ba6ef7c0800..00000000000 --- a/changelogs/unreleased/asciidoctor-plantuml.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Add support for PlantUML diagrams in AsciiDoc documents. -merge_request: 7810 -author: Horacio Sanson diff --git a/changelogs/unreleased/badge-color-on-white-bg.yml b/changelogs/unreleased/badge-color-on-white-bg.yml deleted file mode 100644 index 680d7ff11f0..00000000000 --- a/changelogs/unreleased/badge-color-on-white-bg.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Added lighter count badge background-color for on white backgrounds -merge_request: 7873 -author: diff --git a/changelogs/unreleased/bug-project-feature-compatibility.yml b/changelogs/unreleased/bug-project-feature-compatibility.yml deleted file mode 100644 index 2124ee085e0..00000000000 --- a/changelogs/unreleased/bug-project-feature-compatibility.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Mutate the attribute instead of issuing a write operation to the DB in `ProjectFeaturesCompatibility` - concern. -merge_request: 8552 -author: diff --git a/changelogs/unreleased/clipboard-button-text.yml b/changelogs/unreleased/clipboard-button-text.yml deleted file mode 100644 index dc93da60426..00000000000 --- a/changelogs/unreleased/clipboard-button-text.yml +++ /dev/null @@ -1,3 +0,0 @@ ---- -title: 'Copy <some text> to clipboard' -merge_request: 8535 diff --git a/changelogs/unreleased/didemacet-ci-lint-page.yml b/changelogs/unreleased/didemacet-ci-lint-page.yml deleted file mode 100644 index 07386321c9d..00000000000 --- a/changelogs/unreleased/didemacet-ci-lint-page.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Change CI template linter textarea with Ace Editor -merge_request: 8452 -author: Didem Acet diff --git a/changelogs/unreleased/dot-in-project-queries.yml b/changelogs/unreleased/dot-in-project-queries.yml deleted file mode 100644 index fc48dc7b74d..00000000000 --- a/changelogs/unreleased/dot-in-project-queries.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Allow API query to find projects with dots in their name -merge_request: -author: Bruno Melli diff --git a/changelogs/unreleased/dz-nested-group-misc.yml b/changelogs/unreleased/dz-nested-group-misc.yml deleted file mode 100644 index 9c9d0b1c644..00000000000 --- a/changelogs/unreleased/dz-nested-group-misc.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Show nested groups tab on group page -merge_request: 8308 -author: diff --git a/changelogs/unreleased/dz-rename-invalid-users.yml b/changelogs/unreleased/dz-rename-invalid-users.yml deleted file mode 100644 index f420b069531..00000000000 --- a/changelogs/unreleased/dz-rename-invalid-users.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Rename users with namespace ending with .git -merge_request: 8309 -author: diff --git a/changelogs/unreleased/env-var-in-redis-config.yml b/changelogs/unreleased/env-var-in-redis-config.yml deleted file mode 100644 index 561ea7f514e..00000000000 --- a/changelogs/unreleased/env-var-in-redis-config.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Allow to use ENV variables in redis config -merge_request: 8073 -author: Semyon Pupkov diff --git a/changelogs/unreleased/feature-1376-allow-write-access-deploy-keys.yml b/changelogs/unreleased/feature-1376-allow-write-access-deploy-keys.yml deleted file mode 100644 index 0fd590a877b..00000000000 --- a/changelogs/unreleased/feature-1376-allow-write-access-deploy-keys.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Allow to add deploy keys with write-access -merge_request: 5807 -author: Ali Ibrahim diff --git a/changelogs/unreleased/feature-admin-merge-groups-and-projects.yml b/changelogs/unreleased/feature-admin-merge-groups-and-projects.yml deleted file mode 100644 index 0c0b74b686a..00000000000 --- a/changelogs/unreleased/feature-admin-merge-groups-and-projects.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Merged the 'Groups' and 'Projects' tabs when viewing user profiles -merge_request: 8323 -author: James Gregory diff --git a/changelogs/unreleased/feature-gitaly-feature-flag.yml b/changelogs/unreleased/feature-gitaly-feature-flag.yml deleted file mode 100644 index 1fa566aeb10..00000000000 --- a/changelogs/unreleased/feature-gitaly-feature-flag.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Pass Gitaly resource path to gitlab-workhorse if Gitaly is enabled -merge_request: 8440 -author: diff --git a/changelogs/unreleased/feature-log-ldap-to-application-log.yml b/changelogs/unreleased/feature-log-ldap-to-application-log.yml deleted file mode 100644 index 4cfbc23edb7..00000000000 --- a/changelogs/unreleased/feature-log-ldap-to-application-log.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Log LDAP blocking/unblocking events to application log -merge_request: 8042 -author: Markus Koller diff --git a/changelogs/unreleased/feature-more-storage-statistics.yml b/changelogs/unreleased/feature-more-storage-statistics.yml deleted file mode 100644 index 824fd36dc34..00000000000 --- a/changelogs/unreleased/feature-more-storage-statistics.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Add more storage statistics -merge_request: 7754 -author: Markus Koller diff --git a/changelogs/unreleased/filename-to-file-path.yml b/changelogs/unreleased/filename-to-file-path.yml deleted file mode 100644 index 3c6c838595a..00000000000 --- a/changelogs/unreleased/filename-to-file-path.yml +++ /dev/null @@ -1,3 +0,0 @@ ---- -title: Rename filename to file path in tooltip of file header in merge request diff -merge_request: 8314
\ No newline at end of file diff --git a/changelogs/unreleased/fill-authorized-projects.yml b/changelogs/unreleased/fill-authorized-projects.yml deleted file mode 100644 index e8e33011a15..00000000000 --- a/changelogs/unreleased/fill-authorized-projects.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fill missing authorized projects rows -merge_request: -author: diff --git a/changelogs/unreleased/fix-api-deprecation.yml b/changelogs/unreleased/fix-api-deprecation.yml deleted file mode 100644 index 90285ddf058..00000000000 --- a/changelogs/unreleased/fix-api-deprecation.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix a Grape deprecation, use `#request_method` instead of `#route_method` -merge_request: -author: diff --git a/changelogs/unreleased/fix-blame-500.yml b/changelogs/unreleased/fix-blame-500.yml deleted file mode 100644 index 379d81aaa44..00000000000 --- a/changelogs/unreleased/fix-blame-500.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix blame 500 error on invalid path. -merge_request: 25761 -author: Jeff Stubler diff --git a/changelogs/unreleased/fix-boards-search-typo.yml b/changelogs/unreleased/fix-boards-search-typo.yml deleted file mode 100644 index 0c083fc0d10..00000000000 --- a/changelogs/unreleased/fix-boards-search-typo.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Fix typo: seach to search' -merge_request: 8370 -author: diff --git a/changelogs/unreleased/fix-broken-url-on-group-avatar.yml b/changelogs/unreleased/fix-broken-url-on-group-avatar.yml deleted file mode 100644 index 7ce22b4826e..00000000000 --- a/changelogs/unreleased/fix-broken-url-on-group-avatar.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix broken url on group avatar -merge_request: 8464 -author: hogewest diff --git a/changelogs/unreleased/fix-build-sort-order.yml b/changelogs/unreleased/fix-build-sort-order.yml deleted file mode 100644 index a6d6371f69a..00000000000 --- a/changelogs/unreleased/fix-build-sort-order.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Sort numbers in build names more intelligently -merge_request: 8277 -author: diff --git a/changelogs/unreleased/fix-copy-issues-empty-state.yml b/changelogs/unreleased/fix-copy-issues-empty-state.yml deleted file mode 100644 index a87b7612217..00000000000 --- a/changelogs/unreleased/fix-copy-issues-empty-state.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Improve copy in Issue Tracker empty state -merge_request: 8202 -author: diff --git a/changelogs/unreleased/fix-external-status-badge-links.yml b/changelogs/unreleased/fix-external-status-badge-links.yml deleted file mode 100644 index 2287a9b76c4..00000000000 --- a/changelogs/unreleased/fix-external-status-badge-links.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Link external build badge to its target URL -merge_request: 8611 -author: diff --git a/changelogs/unreleased/fix-keep-artifacts-button-visibility.yml b/changelogs/unreleased/fix-keep-artifacts-button-visibility.yml deleted file mode 100644 index 3d8cf1c74a2..00000000000 --- a/changelogs/unreleased/fix-keep-artifacts-button-visibility.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Hide build artifacts keep button if operation is not allowed -merge_request: 8501 -author: diff --git a/changelogs/unreleased/fix-light-hr-in-descriptions.yml b/changelogs/unreleased/fix-light-hr-in-descriptions.yml deleted file mode 100644 index 8efd471e416..00000000000 --- a/changelogs/unreleased/fix-light-hr-in-descriptions.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Darkened hr border color in descriptions because of update of bootstrap -merge_request: 8333 -author: diff --git a/changelogs/unreleased/fix-more-orphans-remove-undeleted-groups.yml b/changelogs/unreleased/fix-more-orphans-remove-undeleted-groups.yml deleted file mode 100644 index bc2068b8177..00000000000 --- a/changelogs/unreleased/fix-more-orphans-remove-undeleted-groups.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Remove extra orphaned rows when removing stray namespaces -merge_request: 7841 -author: diff --git a/changelogs/unreleased/fix-no-milestone-option-for-projects-endpoint-23194.yml b/changelogs/unreleased/fix-no-milestone-option-for-projects-endpoint-23194.yml deleted file mode 100644 index 98066537723..00000000000 --- a/changelogs/unreleased/fix-no-milestone-option-for-projects-endpoint-23194.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'API: fix query response for `/projects/:id/issues?milestone="No%20Milestone"`' -merge_request: 8457 -author: Panagiotis Atmatzidis, David Eisner diff --git a/changelogs/unreleased/fix-project-delete-tooltip.yml b/changelogs/unreleased/fix-project-delete-tooltip.yml deleted file mode 100644 index 42fd9c32519..00000000000 --- a/changelogs/unreleased/fix-project-delete-tooltip.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix project queued for deletion re-creation tooltip -merge_request: -author: diff --git a/changelogs/unreleased/fix-serialized-commit-path.yml b/changelogs/unreleased/fix-serialized-commit-path.yml deleted file mode 100644 index 4e4df503874..00000000000 --- a/changelogs/unreleased/fix-serialized-commit-path.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix links to commits pages on pipelines list page -merge_request: 8558 -author: diff --git a/changelogs/unreleased/fix-timezone-due-date-picker.yml b/changelogs/unreleased/fix-timezone-due-date-picker.yml deleted file mode 100644 index 2e6b71c70ca..00000000000 --- a/changelogs/unreleased/fix-timezone-due-date-picker.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix date inconsistency on due date picker -merge_request: 7422 -author: Giuliano Varriale diff --git a/changelogs/unreleased/fix-user-api-confirm-param.yml b/changelogs/unreleased/fix-user-api-confirm-param.yml deleted file mode 100644 index 42642576634..00000000000 --- a/changelogs/unreleased/fix-user-api-confirm-param.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix 500 error when POSTing to Users API with optional confirm param -merge_request: -author: diff --git a/changelogs/unreleased/get_last_used_date_of_ssh_key.yml b/changelogs/unreleased/get_last_used_date_of_ssh_key.yml deleted file mode 100644 index b753949922c..00000000000 --- a/changelogs/unreleased/get_last_used_date_of_ssh_key.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Record and show last used date of SSH Keys -merge_request: 8113 -author: Vincent Wong diff --git a/changelogs/unreleased/i--25814-500-error.yml b/changelogs/unreleased/i--25814-500-error.yml deleted file mode 100644 index cd55ede84c8..00000000000 --- a/changelogs/unreleased/i--25814-500-error.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix Compare page throws 500 error when any branch/reference is not selected -merge_request: 8492 -author: Martin Cabrera diff --git a/changelogs/unreleased/input-button-hover.yml b/changelogs/unreleased/input-button-hover.yml deleted file mode 100644 index cbb35adb769..00000000000 --- a/changelogs/unreleased/input-button-hover.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Add hover state to MR comment reply button -merge_request: -author: diff --git a/changelogs/unreleased/issue-boards-animate.yml b/changelogs/unreleased/issue-boards-animate.yml deleted file mode 100644 index 28394aec3d5..00000000000 --- a/changelogs/unreleased/issue-boards-animate.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Added animations to issue boards interactions -merge_request: -author: diff --git a/changelogs/unreleased/issue_22664.yml b/changelogs/unreleased/issue_22664.yml deleted file mode 100644 index 18a8d9ec6be..00000000000 --- a/changelogs/unreleased/issue_22664.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Check if user can read project before being assigned to issue -merge_request: -author: diff --git a/changelogs/unreleased/issue_25017.yml b/changelogs/unreleased/issue_25017.yml deleted file mode 100644 index 09126ae81bc..00000000000 --- a/changelogs/unreleased/issue_25017.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Show 'too many changes' message for created merge requests when they are too large -merge_request: -author: diff --git a/changelogs/unreleased/issue_25578.yml b/changelogs/unreleased/issue_25578.yml deleted file mode 100644 index e10f1d232af..00000000000 --- a/changelogs/unreleased/issue_25578.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix redirect after update file when user has forked project -merge_request: -author: diff --git a/changelogs/unreleased/issue_25682.yml b/changelogs/unreleased/issue_25682.yml deleted file mode 100644 index a50138756ba..00000000000 --- a/changelogs/unreleased/issue_25682.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Parse JIRA issue references even if Issue Tracker is disabled -merge_request: -author: diff --git a/changelogs/unreleased/issues-8081.yml b/changelogs/unreleased/issues-8081.yml deleted file mode 100644 index 82f746937bc..00000000000 --- a/changelogs/unreleased/issues-8081.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: change 'gray' color theme name to 'black' to match the actual color -merge_request: 7908 -author: BM5k diff --git a/changelogs/unreleased/ldap_maint_task.yml b/changelogs/unreleased/ldap_maint_task.yml deleted file mode 100644 index 8acffba0ce5..00000000000 --- a/changelogs/unreleased/ldap_maint_task.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Add LDAP Rake task to rename a provider -merge_request: 2181 -author: diff --git a/changelogs/unreleased/login-page-font-size.yml b/changelogs/unreleased/login-page-font-size.yml deleted file mode 100644 index e7775006673..00000000000 --- a/changelogs/unreleased/login-page-font-size.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Decreases font-size on login page -merge_request: -author: diff --git a/changelogs/unreleased/markdown-area-height-fix.yml b/changelogs/unreleased/markdown-area-height-fix.yml deleted file mode 100644 index bf1b82cfd12..00000000000 --- a/changelogs/unreleased/markdown-area-height-fix.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Autoresize markdown preview -merge_request: 8607 -author: Didem Acet diff --git a/changelogs/unreleased/merge-dropdown-this-context.yml b/changelogs/unreleased/merge-dropdown-this-context.yml new file mode 100644 index 00000000000..5c4890fcaa2 --- /dev/null +++ b/changelogs/unreleased/merge-dropdown-this-context.yml @@ -0,0 +1,4 @@ +--- +title: Fixed bug where links in merge dropdown wouldn't work +merge_request: +author: diff --git a/changelogs/unreleased/mr-tabs-alignment-sidebar-open.yml b/changelogs/unreleased/mr-tabs-alignment-sidebar-open.yml deleted file mode 100644 index b8c7b78cf0d..00000000000 --- a/changelogs/unreleased/mr-tabs-alignment-sidebar-open.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fixed merge request tabs dont move when opening collapsed sidebar -merge_request: -author: diff --git a/changelogs/unreleased/nuke-ugly-spaces-in-changelog-generator.yml b/changelogs/unreleased/nuke-ugly-spaces-in-changelog-generator.yml deleted file mode 100644 index fd173031107..00000000000 --- a/changelogs/unreleased/nuke-ugly-spaces-in-changelog-generator.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Remove trailing whitespace when generating changelog entry -merge_request: 7948 -author: diff --git a/changelogs/unreleased/pc-add-gitaly-to-architecture.yml b/changelogs/unreleased/pc-add-gitaly-to-architecture.yml deleted file mode 100644 index 7c18da698df..00000000000 --- a/changelogs/unreleased/pc-add-gitaly-to-architecture.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Add Gitaly to the architecture documentation -merge_request: 8264 -author: Pablo Carranza <pablo@gitlab.com> diff --git a/changelogs/unreleased/pipelines-graph-html-css.yml b/changelogs/unreleased/pipelines-graph-html-css.yml deleted file mode 100644 index ff0c3122fdb..00000000000 --- a/changelogs/unreleased/pipelines-graph-html-css.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fixes and Improves CSS and HTML problems in mini pipeline graph and builds dropdown -merge_request: 8443 -author: diff --git a/changelogs/unreleased/pmq20-gitlab-ce-psvr-head-cache.yml b/changelogs/unreleased/pmq20-gitlab-ce-psvr-head-cache.yml deleted file mode 100644 index 23230128dc9..00000000000 --- a/changelogs/unreleased/pmq20-gitlab-ce-psvr-head-cache.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Expire related caches after changing HEAD -merge_request: -author: Minqi Pan diff --git a/changelogs/unreleased/re-style-issue-new-branch.yml b/changelogs/unreleased/re-style-issue-new-branch.yml deleted file mode 100644 index 977a54ff2ae..00000000000 --- a/changelogs/unreleased/re-style-issue-new-branch.yml +++ /dev/null @@ -1,3 +0,0 @@ ---- -title: Remove checking branches state in issue new branch button -merge_request: 8023 diff --git a/changelogs/unreleased/recaptcha_500.yml b/changelogs/unreleased/recaptcha_500.yml deleted file mode 100644 index de9ef183d5e..00000000000 --- a/changelogs/unreleased/recaptcha_500.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Properly handle failed reCAPTCHA on user registration -merge_request: 8403 -author: diff --git a/changelogs/unreleased/reduce-queries-milestone-index.yml b/changelogs/unreleased/reduce-queries-milestone-index.yml deleted file mode 100644 index a779b58c973..00000000000 --- a/changelogs/unreleased/reduce-queries-milestone-index.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Use cached values to compute total issues count in milestone index pages -merge_request: 8518 -author: diff --git a/changelogs/unreleased/refresh-authorizations-tighter-lease.yml b/changelogs/unreleased/refresh-authorizations-tighter-lease.yml deleted file mode 100644 index ab42b2eb72d..00000000000 --- a/changelogs/unreleased/refresh-authorizations-tighter-lease.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Synchronize all project authorization refreshing work to prevent race conditions -merge_request: -author: diff --git a/changelogs/unreleased/remove-project-authorizations-id-column.yml b/changelogs/unreleased/remove-project-authorizations-id-column.yml deleted file mode 100644 index 24c86f0fb1b..00000000000 --- a/changelogs/unreleased/remove-project-authorizations-id-column.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Remove the project_authorizations.id column -merge_request: -author: diff --git a/changelogs/unreleased/remove-successful-pipeline-emails-for-now.yml b/changelogs/unreleased/remove-successful-pipeline-emails-for-now.yml deleted file mode 100644 index 47d484e5c84..00000000000 --- a/changelogs/unreleased/remove-successful-pipeline-emails-for-now.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Make successful pipeline emails off for watchers -merge_request: 8176 -author: diff --git a/changelogs/unreleased/restore-backup-when-env-variable-is-passed.yml b/changelogs/unreleased/restore-backup-when-env-variable-is-passed.yml deleted file mode 100644 index 8ec3cfdbb08..00000000000 --- a/changelogs/unreleased/restore-backup-when-env-variable-is-passed.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Restore backup correctly when "BACKUP" environment variable is passed -merge_request: 8477 -author: diff --git a/changelogs/unreleased/sandish-gitlab-ce-update_ret_val.yml b/changelogs/unreleased/sandish-gitlab-ce-update_ret_val.yml deleted file mode 100644 index 7107ddfd982..00000000000 --- a/changelogs/unreleased/sandish-gitlab-ce-update_ret_val.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Ensure updating project settings shows a flash message on success -merge_request: 8579 -author: Sandish Chen diff --git a/changelogs/unreleased/single-edit-comment-widget-2.yml b/changelogs/unreleased/single-edit-comment-widget-2.yml deleted file mode 100644 index e8b8beb15de..00000000000 --- a/changelogs/unreleased/single-edit-comment-widget-2.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Refactored note edit form to improve frontend performance on MR and Issues - pages, especially pages with has a lot of discussions in it -merge_request: 8356 -author: diff --git a/changelogs/unreleased/speed-up-dashboard-milestone-index.yml b/changelogs/unreleased/speed-up-dashboard-milestone-index.yml deleted file mode 100644 index ba4ff931ea8..00000000000 --- a/changelogs/unreleased/speed-up-dashboard-milestone-index.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Speed up dashboard milestone index by scoping IssuesFinder to user authorized - projects -merge_request: 8524 -author: diff --git a/changelogs/unreleased/support-google-cloud-storage-backups.yml b/changelogs/unreleased/support-google-cloud-storage-backups.yml deleted file mode 100644 index cec279a5c73..00000000000 --- a/changelogs/unreleased/support-google-cloud-storage-backups.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Re-add Google Cloud Storage as a backup strategy -merge_request: -author: diff --git a/changelogs/unreleased/time-tracking-api.yml b/changelogs/unreleased/time-tracking-api.yml deleted file mode 100644 index b58d73bef81..00000000000 --- a/changelogs/unreleased/time-tracking-api.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Add new endpoints for Time Tracking. -merge_request: 8483 -author: diff --git a/changelogs/unreleased/update-gitlab-markup-gem.yml b/changelogs/unreleased/update-gitlab-markup-gem.yml deleted file mode 100644 index 96cdfd051f0..00000000000 --- a/changelogs/unreleased/update-gitlab-markup-gem.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Update the gitlab-markup gem to the version 1.5.1 -merge_request: 8509 -author: diff --git a/changelogs/unreleased/validate-title-length.yml b/changelogs/unreleased/validate-title-length.yml deleted file mode 100644 index 7abf1c4d05a..00000000000 --- a/changelogs/unreleased/validate-title-length.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: "Validate label's title length" -merge_request: 5767 -author: Tomáš Kukrál diff --git a/changelogs/unreleased/view-ce-vs-ee.yml b/changelogs/unreleased/view-ce-vs-ee.yml deleted file mode 100644 index 38bce4ac7c3..00000000000 --- a/changelogs/unreleased/view-ce-vs-ee.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: About GitLab link in sidebar that links to help page -merge_request: 8316 -author: diff --git a/changelogs/unreleased/zj-unadressable-url-variables.yml b/changelogs/unreleased/zj-unadressable-url-variables.yml deleted file mode 100644 index 6c412bd0540..00000000000 --- a/changelogs/unreleased/zj-unadressable-url-variables.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Don't validate environment urls on .gitlab-ci.yml -merge_request: -author: diff --git a/config/routes/project.rb b/config/routes/project.rb index 1fc6ed28c74..6620b765e02 100644 --- a/config/routes/project.rb +++ b/config/routes/project.rb @@ -307,9 +307,9 @@ constraints(ProjectUrlConstrainer.new) do end end end - namespace :settings do resource :members, only: [:show] + resource :integrations, only: [:show] end # Since both wiki and repository routing contains wildcard characters diff --git a/db/migrate/20170121123724_add_index_to_ci_builds_for_status_runner_id_and_type.rb b/db/migrate/20170121123724_add_index_to_ci_builds_for_status_runner_id_and_type.rb new file mode 100644 index 00000000000..4ea953f2b78 --- /dev/null +++ b/db/migrate/20170121123724_add_index_to_ci_builds_for_status_runner_id_and_type.rb @@ -0,0 +1,17 @@ +class AddIndexToCiBuildsForStatusRunnerIdAndType < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + disable_ddl_transaction! + + def up + add_concurrent_index :ci_builds, [:status, :type, :runner_id] + end + + def down + if index_exists?(:ci_builds, [:status, :type, :runner_id]) + remove_index :ci_builds, column: [:status, :type, :runner_id] + end + end +end diff --git a/db/migrate/20170121130655_add_index_to_ci_runners_for_is_shared.rb b/db/migrate/20170121130655_add_index_to_ci_runners_for_is_shared.rb new file mode 100644 index 00000000000..620befcf4d7 --- /dev/null +++ b/db/migrate/20170121130655_add_index_to_ci_runners_for_is_shared.rb @@ -0,0 +1,17 @@ +class AddIndexToCiRunnersForIsShared < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + disable_ddl_transaction! + + def up + add_concurrent_index :ci_runners, :is_shared + end + + def down + if index_exists?(:ci_runners, :is_shared) + remove_index :ci_runners, :is_shared + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 7815392c1c3..3c836db27fc 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20170106172224) do +ActiveRecord::Schema.define(version: 20170121130655) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -224,6 +224,7 @@ ActiveRecord::Schema.define(version: 20170106172224) do add_index "ci_builds", ["gl_project_id"], name: "index_ci_builds_on_gl_project_id", using: :btree add_index "ci_builds", ["project_id"], name: "index_ci_builds_on_project_id", using: :btree add_index "ci_builds", ["runner_id"], name: "index_ci_builds_on_runner_id", using: :btree + add_index "ci_builds", ["status", "type", "runner_id"], name: "index_ci_builds_on_status_and_type_and_runner_id", using: :btree add_index "ci_builds", ["status"], name: "index_ci_builds_on_status", using: :btree add_index "ci_builds", ["token"], name: "index_ci_builds_on_token", unique: true, using: :btree @@ -327,6 +328,7 @@ ActiveRecord::Schema.define(version: 20170106172224) do t.boolean "locked", default: false, null: false end + add_index "ci_runners", ["is_shared"], name: "index_ci_runners_on_is_shared", using: :btree add_index "ci_runners", ["locked"], name: "index_ci_runners_on_locked", using: :btree add_index "ci_runners", ["token"], name: "index_ci_runners_on_token", using: :btree diff --git a/doc/README.md b/doc/README.md index 43261ef7457..e329131b8ee 100644 --- a/doc/README.md +++ b/doc/README.md @@ -53,7 +53,8 @@ - [Migrate GitLab CI to CE/EE](migrate_ci_to_ce/README.md) Follow this guide to migrate your existing GitLab CI data to GitLab CE/EE. - [Git LFS configuration](workflow/lfs/lfs_administration.md) - [Housekeeping](administration/housekeeping.md) Keep your Git repository tidy and fast. -- [GitLab Performance Monitoring](administration/monitoring/performance/introduction.md) Configure GitLab and InfluxDB for measuring performance metrics. +- [GitLab performance monitoring with InfluxDB](administration/monitoring/performance/introduction.md) Configure GitLab and InfluxDB for measuring performance metrics. +- [GitLab performance monitoring with Prometheus](administration/monitoring/performance/prometheus.md) Configure GitLab and Prometheus for measuring performance metrics. - [Request Profiling](administration/monitoring/performance/request_profiling.md) Get a detailed profile on slow requests. - [Monitoring uptime](user/admin_area/monitoring/health_check.md) Check the server status using the health check endpoint. - [Debugging Tips](administration/troubleshooting/debug.md) Tips to debug problems when things go wrong diff --git a/doc/administration/monitoring/performance/introduction.md b/doc/administration/monitoring/performance/introduction.md index 79904916b7e..8b106e89cc2 100644 --- a/doc/administration/monitoring/performance/introduction.md +++ b/doc/administration/monitoring/performance/introduction.md @@ -12,6 +12,11 @@ documents in order to understand and properly configure GitLab Performance Monit - [InfluxDB Schema](influxdb_schema.md) - [Grafana Install/Configuration](grafana_configuration.md) +>**Note:** +Omnibus GitLab 8.16 includes Prometheus as an additional tool to collect +metrics. It will eventually replace InfluxDB when their metrics collection is +on par. Read more in the [Prometheus documentation](prometheus.md). + ## Introduction to GitLab Performance Monitoring GitLab Performance Monitoring makes it possible to measure a wide variety of statistics diff --git a/doc/administration/monitoring/performance/prometheus.md b/doc/administration/monitoring/performance/prometheus.md new file mode 100644 index 00000000000..51c63325064 --- /dev/null +++ b/doc/administration/monitoring/performance/prometheus.md @@ -0,0 +1,102 @@ +# GitLab Prometheus + +>**Notes:** +- Prometheus and the node exporter are bundled in the Omnibus GitLab package + since GitLab 8.16. For installations from source you will have to install + them yourself. Over subsequent releases additional GitLab metrics will be + captured. +- Prometheus services are off by default but will be on starting with GitLab 9.0. + +[Prometheus] is a powerful time-series monitoring service, providing a flexible +platform for monitoring GitLab and other software products. +GitLab provides out of the box monitoring with Prometheus, providing easy +access to high quality time-series monitoring of GitLab services. + +## Overview + +Prometheus works by periodically connecting to data sources and collecting their +performance metrics. To view and work with the monitoring data, you can either +connect directly to Prometheus or utilize a dashboard tool like [Grafana]. + +## Configuring Prometheus + +>**Note:** +Available since Omnibus GitLab 8.16. For installations from source you'll +have to install and configure it yourself. + +To enable Prometheus: + +1. Edit `/etc/gitlab/gitlab.rb` +1. Find and uncomment the following line, making sure it's set to `true`: + + ```ruby + prometheus['enable'] = true + ``` + +1. Save the file and [reconfigure GitLab][reconfigure] for the changes to + take effect + +By default, Prometheus will run as the `gitlab-prometheus` user and listen on +TCP port `9090` under localhost. If the [node exporter](#node-exporter) service +has been enabled, it will automatically be set up as a monitoring target for +Prometheus. + +## Viewing Performance Metrics + +After you have [enabled Prometheus](#configuring-prometheus), you can visit +`<your_domain_name>:9090` for the dashboard that Prometheus offers by default. + +The performance data collected by Prometheus can be viewed directly in the +Prometheus console or through a compatible dashboard tool. +The Prometheus interface provides a [flexible query language][prom-query] to work +with the collected data where you can visualize their output. +For a more fully featured dashboard, Grafana can be used and has +[official support for Prometheus][prom-grafana]. + +## Prometheus exporters + +There are a number of libraries and servers which help in exporting existing +metrics from third-party systems as Prometheus metrics. This is useful for cases +where it is not feasible to instrument a given system with Prometheus metrics +directly (for example, HAProxy or Linux system stats). You can read more in the +[Prometheus exporters and integrations documentation][prom-exporters]. + +While you can use any exporter you like with your GitLab installation, the +following ones documented here are bundled in the Omnibus GitLab packages +making it easy to configure and use. + +### Node exporter + +>**Note:** +Available since Omnibus GitLab 8.16. For installations from source you'll +have to install and configure it yourself. + +The [node exporter] allows you to measure various machine resources such as +memory, disk and CPU utilization. + +To enable the node exporter: + +1. [Enable Prometheus](#configuring-prometheus) +1. Edit `/etc/gitlab/gitlab.rb` +1. Find and uncomment the following line, making sure it's set to `true`: + + ```ruby + node_exporter['enable'] = true + ``` + +1. Save the file and [reconfigure GitLab][reconfigure] for the changes to + take effect + +Prometheus it will now automatically begin collecting performance data from +the node exporter. You can visit `<your_domain_name>:9100/metrics` for a real +time representation of the metrics that are collected. Refresh the page and +you will see the data change. + +[grafana]: https://grafana.net +[node exporter]: https://github.com/prometheus/node_exporter +[prometheus]: https://prometheus.io +[prom-query]: https://prometheus.io/docs/querying/basics +[prom-grafana]: https://prometheus.io/docs/visualization/grafana/ +[scrape-config]: https://prometheus.io/docs/operating/configuration/#%3Cscrape_config%3E +[prom-exporters]: https://prometheus.io/docs/instrumenting/exporters/ +[reconfigure]: ../../restart_gitlab.md#omnibus-gitlab-reconfigure diff --git a/doc/api/README.md b/doc/api/README.md index f65b934b9db..20f28e8d30e 100644 --- a/doc/api/README.md +++ b/doc/api/README.md @@ -104,6 +104,13 @@ that needs access to the GitLab API. Once you have your token, pass it to the API using either the `private_token` parameter or the `PRIVATE-TOKEN` header. +> [Introduced][ce-5951] in GitLab 8.15. + +Personal Access Tokens can be created with one or more scopes that allow various actions +that a given token can perform. Although there are only two scopes available at the +moment – `read_user` and `api` – the groundwork has been laid to add more scopes easily. + +At any time you can revoke any personal access token by just clicking **Revoke**. ### Session Cookie @@ -380,3 +387,4 @@ programming languages. Visit the [GitLab website] for a complete list. [GitLab website]: https://about.gitlab.com/applications/#api-clients "Clients using the GitLab API" [lib-api-url]: https://gitlab.com/gitlab-org/gitlab-ce/tree/master/lib/api/api.rb [ce-3749]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/3749 +[ce-5951]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/5951 diff --git a/doc/integration/oauth_provider.md b/doc/integration/oauth_provider.md index 0c53584d201..af8a1c4e5ed 100644 --- a/doc/integration/oauth_provider.md +++ b/doc/integration/oauth_provider.md @@ -74,8 +74,10 @@ in the **Authorized applications** section under **Profile Settings > Applicatio --- -As you can see, the default scope `api` is used, which is the only scope that -GitLab supports so far. At any time you can revoke any access by just clicking -**Revoke**. +GitLab's OAuth applications support scopes, which allow various actions that any given +application can perform. Although there are only two scopes available at the +moment – `read_user` and `api` – the groundwork has been laid to add more scopes easily. + +At any time you can revoke any access by just clicking **Revoke**. [oauth]: http://oauth.net/2/ "OAuth website" diff --git a/features/project/active_tab.feature b/features/project/active_tab.feature index 57dda9c2234..d033e6b167b 100644 --- a/features/project/active_tab.feature +++ b/features/project/active_tab.feature @@ -39,10 +39,10 @@ Feature: Project Active Tab # Sub Tabs: Settings - Scenario: On Project Settings/Hooks + Scenario: On Project Settings/Integrations Given I visit my project's settings page - And I click the "Hooks" tab - Then the active sub nav should be Hooks + And I click the "Integrations" tab + Then the active sub nav should be Integrations And no other sub navs should be active And the active main tab should be Settings diff --git a/features/steps/project/active_tab.rb b/features/steps/project/active_tab.rb index 58225032859..9f701840f1d 100644 --- a/features/steps/project/active_tab.rb +++ b/features/steps/project/active_tab.rb @@ -27,8 +27,8 @@ class Spinach::Features::ProjectActiveTab < Spinach::FeatureSteps end end - step 'I click the "Hooks" tab' do - click_link('Webhooks') + step 'I click the "Integrations" tab' do + click_link('Integrations') end step 'I click the "Deploy Keys" tab' do @@ -39,8 +39,8 @@ class Spinach::Features::ProjectActiveTab < Spinach::FeatureSteps ensure_active_sub_nav('Members') end - step 'the active sub nav should be Hooks' do - ensure_active_sub_nav('Webhooks') + step 'the active sub nav should be Integrations' do + ensure_active_sub_nav('Integrations') end step 'the active sub nav should be Deploy Keys' do diff --git a/features/steps/project/hooks.rb b/features/steps/project/hooks.rb index 13c0713669a..37b608ffbd3 100644 --- a/features/steps/project/hooks.rb +++ b/features/steps/project/hooks.rb @@ -36,12 +36,12 @@ class Spinach::Features::ProjectHooks < Spinach::FeatureSteps end step 'I should see newly created hook' do - expect(current_path).to eq namespace_project_hooks_path(current_project.namespace, current_project) + expect(current_path).to eq namespace_project_settings_integrations_path(current_project.namespace, current_project) expect(page).to have_content(@url) end step 'I should see newly created hook with SSL verification enabled' do - expect(current_path).to eq namespace_project_hooks_path(current_project.namespace, current_project) + expect(current_path).to eq namespace_project_settings_integrations_path(current_project.namespace, current_project) expect(page).to have_content(@url) expect(page).to have_content("SSL Verification: enabled") end @@ -57,7 +57,7 @@ class Spinach::Features::ProjectHooks < Spinach::FeatureSteps end step 'hook should be triggered' do - expect(current_path).to eq namespace_project_hooks_path(current_project.namespace, current_project) + expect(current_path).to eq namespace_project_settings_integrations_path(current_project.namespace, current_project) expect(page).to have_selector '.flash-notice', text: 'Hook executed successfully: HTTP 200' end diff --git a/features/steps/project/services.rb b/features/steps/project/services.rb index a4d29770922..772b07d0ad8 100644 --- a/features/steps/project/services.rb +++ b/features/steps/project/services.rb @@ -4,7 +4,7 @@ class Spinach::Features::ProjectServices < Spinach::FeatureSteps include SharedPaths step 'I visit project "Shop" services page' do - visit namespace_project_services_path(@project.namespace, @project) + visit namespace_project_settings_integrations_path(@project.namespace, @project) end step 'I should see list of available services' do diff --git a/features/steps/shared/paths.rb b/features/steps/shared/paths.rb index 670e6ca49a3..718cf924729 100644 --- a/features/steps/shared/paths.rb +++ b/features/steps/shared/paths.rb @@ -256,7 +256,7 @@ module SharedPaths end step 'I visit project hooks page' do - visit namespace_project_hooks_path(@project.namespace, @project) + visit namespace_project_settings_integrations_path(@project.namespace, @project) end step 'I visit project deploy keys page' do diff --git a/lib/gitlab/import_export/members_mapper.rb b/lib/gitlab/import_export/members_mapper.rb index b790733f4a7..2405b94db50 100644 --- a/lib/gitlab/import_export/members_mapper.rb +++ b/lib/gitlab/import_export/members_mapper.rb @@ -1,13 +1,10 @@ module Gitlab module ImportExport class MembersMapper - attr_reader :missing_author_ids - def initialize(exported_members:, user:, project:) - @exported_members = exported_members + @exported_members = user.admin? ? exported_members : [] @user = user @project = project - @missing_author_ids = [] # This needs to run first, as second call would be from #map # which means project members already exist. @@ -39,7 +36,6 @@ module Gitlab def missing_keys_tracking_hash Hash.new do |_, key| - @missing_author_ids << key default_user_id end end @@ -64,7 +60,7 @@ module Gitlab end def find_project_user_query(member) - user_arel[:username].eq(member['user']['username']).or(user_arel[:email].eq(member['user']['email'])) + user_arel[:email].eq(member['user']['email']).or(user_arel[:username].eq(member['user']['username'])) end def user_arel diff --git a/lib/gitlab/import_export/relation_factory.rb b/lib/gitlab/import_export/relation_factory.rb index 7a649f28340..19e43cce768 100644 --- a/lib/gitlab/import_export/relation_factory.rb +++ b/lib/gitlab/import_export/relation_factory.rb @@ -14,7 +14,7 @@ module Gitlab priorities: :label_priorities, label: :project_label }.freeze - USER_REFERENCES = %w[author_id assignee_id updated_by_id user_id created_by_id merge_user_id].freeze + USER_REFERENCES = %w[author_id assignee_id updated_by_id user_id created_by_id merge_user_id resolved_by_id].freeze PROJECT_REFERENCES = %w[project_id source_project_id gl_project_id target_project_id].freeze @@ -80,17 +80,13 @@ module Gitlab # is left. def set_note_author old_author_id = @relation_hash['author_id'] - - # Users with admin access can map users - @relation_hash['author_id'] = admin_user? ? @members_mapper.map[old_author_id] : @members_mapper.default_user_id - author = @relation_hash.delete('author') - update_note_for_missing_author(author['name']) if missing_author?(old_author_id) + update_note_for_missing_author(author['name']) unless has_author?(old_author_id) end - def missing_author?(old_author_id) - !admin_user? || @members_mapper.missing_author_ids.include?(old_author_id) + def has_author?(old_author_id) + admin_user? && @members_mapper.map.keys.include?(old_author_id) end def missing_author_note(updated_at, author_name) diff --git a/spec/controllers/projects/settings/integrations_controller_spec.rb b/spec/controllers/projects/settings/integrations_controller_spec.rb new file mode 100644 index 00000000000..e0f9a5b24a6 --- /dev/null +++ b/spec/controllers/projects/settings/integrations_controller_spec.rb @@ -0,0 +1,20 @@ +require 'spec_helper' + +describe Projects::Settings::IntegrationsController do + let(:project) { create(:project, :public) } + let(:user) { create(:user) } + + before do + project.team << [user, :master] + sign_in(user) + end + + describe 'GET show' do + it 'renders show with 200 status code' do + get :show, namespace_id: project.namespace, project_id: project + + expect(response).to have_http_status(200) + expect(response).to render_template(:show) + end + end +end diff --git a/spec/features/issues/filtered_search/dropdown_assignee_spec.rb b/spec/features/issues/filtered_search/dropdown_assignee_spec.rb index 3ac9b2e0ae0..16dcc487812 100644 --- a/spec/features/issues/filtered_search/dropdown_assignee_spec.rb +++ b/spec/features/issues/filtered_search/dropdown_assignee_spec.rb @@ -43,6 +43,14 @@ describe 'Dropdown assignee', js: true, feature: true do expect(page).to have_css(js_dropdown_assignee, visible: true) end + it 'shows assigned to me link' do + filtered_search.set('assignee:') + + page.within js_dropdown_assignee do + expect(page).to have_content('Assigned to me') + end + end + it 'closes when the search bar is unfocused' do find('body').click() @@ -121,6 +129,14 @@ describe 'Dropdown assignee', js: true, feature: true do filtered_search.set('assignee:') end + it 'filters by current user' do + page.within js_dropdown_assignee do + click_button 'Assigned to me' + end + + expect(filtered_search.value).to eq("assignee:#{user.to_reference}") + end + it 'fills in the assignee username when the assignee has not been filtered' do click_assignee(user_jacob.name) diff --git a/spec/features/issues/filtered_search/filter_issues_spec.rb b/spec/features/issues/filtered_search/filter_issues_spec.rb index ead43d6784a..1cdac520181 100644 --- a/spec/features/issues/filtered_search/filter_issues_spec.rb +++ b/spec/features/issues/filtered_search/filter_issues_spec.rb @@ -19,9 +19,12 @@ describe 'Filter issues', js: true, feature: true do let!(:closed_issue) { create(:issue, title: 'bug that is closed', project: project, state: :closed) } let(:filtered_search) { find('.filtered-search') } - def input_filtered_search(search_term) + def input_filtered_search(search_term, submit: true) filtered_search.set(search_term) - filtered_search.send_keys(:enter) + + if submit + filtered_search.send_keys(:enter) + end end def expect_filtered_search_input(input) @@ -43,6 +46,10 @@ describe 'Filter issues', js: true, feature: true do end end + def select_search_at_index(pos) + evaluate_script("el = document.querySelector('.filtered-search'); el.focus(); el.setSelectionRange(#{pos}, #{pos});") + end + before do project.team << [user, :master] project.team << [user2, :master] @@ -522,6 +529,44 @@ describe 'Filter issues', js: true, feature: true do end end + describe 'overwrites selected filter' do + it 'changes author' do + input_filtered_search("author:@#{user.username}", submit: false) + + select_search_at_index(3) + + page.within '#js-dropdown-author' do + click_button user2.username + end + + expect(filtered_search.value).to eq("author:@#{user2.username}") + end + + it 'changes label' do + input_filtered_search("author:@#{user.username} label:~#{bug_label.title}", submit: false) + + select_search_at_index(27) + + page.within '#js-dropdown-label' do + click_button label.name + end + + expect(filtered_search.value).to eq("author:@#{user.username} label:~#{label.name}") + end + + it 'changes label correctly space is in previous label' do + input_filtered_search("label:~\"#{multiple_words_label.title}\"", submit: false) + + select_search_at_index(0) + + page.within '#js-dropdown-label' do + click_button label.name + end + + expect(filtered_search.value).to eq("label:~#{label.name}") + end + end + describe 'filter issues by text' do context 'only text' do it 'filters issues by searched text' do diff --git a/spec/features/merge_requests/merge_immediately_with_pipeline_spec.rb b/spec/features/merge_requests/merge_immediately_with_pipeline_spec.rb new file mode 100644 index 00000000000..f2f8f11ab28 --- /dev/null +++ b/spec/features/merge_requests/merge_immediately_with_pipeline_spec.rb @@ -0,0 +1,41 @@ +require 'spec_helper' + +feature 'Merge immediately', :feature, :js do + let(:user) { create(:user) } + let(:project) { create(:project, :public) } + + let(:merge_request) do + create(:merge_request_with_diffs, source_project: project, + author: user, + title: 'Bug NS-04') + end + + let(:pipeline) do + create(:ci_pipeline, project: project, + sha: merge_request.diff_head_sha, + ref: merge_request.source_branch) + end + + before { project.team << [user, :master] } + + context 'when there is active pipeline for merge request' do + background do + create(:ci_build, pipeline: pipeline) + end + + before do + login_as user + visit namespace_project_merge_request_path(merge_request.project.namespace, merge_request.project, merge_request) + end + + it 'enables merge immediately' do + page.within '.mr-widget-body' do + find('.dropdown-toggle').click + + click_link 'Merge Immediately' + + expect(find('.js-merge-button')).to have_content('Merge in progress') + end + end + end +end diff --git a/spec/features/merge_requests/merge_when_pipeline_succeeds_spec.rb b/spec/features/merge_requests/merge_when_pipeline_succeeds_spec.rb index aa24a905001..2ea9c317bd1 100644 --- a/spec/features/merge_requests/merge_when_pipeline_succeeds_spec.rb +++ b/spec/features/merge_requests/merge_when_pipeline_succeeds_spec.rb @@ -32,19 +32,61 @@ feature 'Merge When Pipeline Succeeds', :feature, :js do expect(page).to have_button "Merge When Pipeline Succeeds" end - context "Merge When Pipeline Succeeds enabled" do - before do - click_button "Merge When Pipeline Succeeds" + describe 'enabling Merge When Pipeline Succeeds' do + shared_examples 'Merge When Pipeline Succeeds activator' do + it 'activates the Merge When Pipeline Succeeds feature' do + click_button "Merge When Pipeline Succeeds" + + expect(page).to have_content "Set by #{user.name} to be merged automatically when the pipeline succeeds." + expect(page).to have_content "The source branch will not be removed." + expect(page).to have_link "Cancel Automatic Merge" + visit_merge_request(merge_request) # Needed to refresh the page + expect(page).to have_content /enabled an automatic merge when the pipeline for \h{8} succeeds/i + end end - it 'activates Merge When Pipeline Succeeds feature' do - expect(page).to have_link "Cancel Automatic Merge" + context "when enabled immediately" do + it_behaves_like 'Merge When Pipeline Succeeds activator' + end + + context 'when enabled after pipeline status changed' do + before do + pipeline.run! - expect(page).to have_content "Set by #{user.name} to be merged automatically when the pipeline succeeds." - expect(page).to have_content "The source branch will not be removed." + # We depend on merge request widget being reloaded + # so we have to wait for asynchronous call to reload it + # and have_content expectation handles that. + # + expect(page).to have_content "Pipeline ##{pipeline.id} running" + end + + it_behaves_like 'Merge When Pipeline Succeeds activator' + end + + context 'when enabled after it was previously canceled' do + before do + click_button "Merge When Pipeline Succeeds" + click_link "Cancel Automatic Merge" + end + + it_behaves_like 'Merge When Pipeline Succeeds activator' + end - visit_merge_request(merge_request) # Needed to refresh the page - expect(page).to have_content /enabled an automatic merge when the pipeline for \h{8} succeeds/i + context 'when it was enabled and then canceled' do + let(:merge_request) do + create(:merge_request_with_diffs, + :merge_when_build_succeeds, + source_project: project, + title: 'Bug NS-04', + author: user, + merge_user: user) + end + + before do + click_link "Cancel Automatic Merge" + end + + it_behaves_like 'Merge When Pipeline Succeeds activator' end end end diff --git a/spec/features/security/project/internal_access_spec.rb b/spec/features/security/project/internal_access_spec.rb index ecebabefff8..92d5a2fbc48 100644 --- a/spec/features/security/project/internal_access_spec.rb +++ b/spec/features/security/project/internal_access_spec.rb @@ -262,8 +262,8 @@ describe "Internal Project Access", feature: true do it { is_expected.to be_denied_for(:visitor) } end - describe "GET /:project_path/hooks" do - subject { namespace_project_hooks_path(project.namespace, project) } + describe "GET /:project_path/settings/integrations" do + subject { namespace_project_settings_integrations_path(project.namespace, project) } it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } diff --git a/spec/features/security/project/private_access_spec.rb b/spec/features/security/project/private_access_spec.rb index 9bc59a7c4f9..b616e488487 100644 --- a/spec/features/security/project/private_access_spec.rb +++ b/spec/features/security/project/private_access_spec.rb @@ -234,8 +234,8 @@ describe "Private Project Access", feature: true do it { is_expected.to be_denied_for(:visitor) } end - describe "GET /:project_path/hooks" do - subject { namespace_project_hooks_path(project.namespace, project) } + describe "GET /:project_path/namespace/hooks" do + subject { namespace_project_settings_integrations_path(project.namespace, project) } it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } diff --git a/spec/features/security/project/public_access_spec.rb b/spec/features/security/project/public_access_spec.rb index a8d43b3d581..ded85e837f4 100644 --- a/spec/features/security/project/public_access_spec.rb +++ b/spec/features/security/project/public_access_spec.rb @@ -400,8 +400,8 @@ describe "Public Project Access", feature: true do it { is_expected.to be_allowed_for(:visitor) } end - describe "GET /:project_path/hooks" do - subject { namespace_project_hooks_path(project.namespace, project) } + describe "GET /:project_path/settings/integrations" do + subject { namespace_project_settings_integrations_path(project.namespace, project) } it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } diff --git a/spec/finders/move_to_project_finder_spec.rb b/spec/finders/move_to_project_finder_spec.rb index fdce4e714ff..8488dbd2a16 100644 --- a/spec/finders/move_to_project_finder_spec.rb +++ b/spec/finders/move_to_project_finder_spec.rb @@ -2,13 +2,13 @@ require 'spec_helper' describe MoveToProjectFinder do let(:user) { create(:user) } - let(:project) { create(:project) } + let(:project) { create(:empty_project) } - let(:no_access_project) { create(:project) } - let(:guest_project) { create(:project) } - let(:reporter_project) { create(:project) } - let(:developer_project) { create(:project) } - let(:master_project) { create(:project) } + let(:no_access_project) { create(:empty_project) } + let(:guest_project) { create(:empty_project) } + let(:reporter_project) { create(:empty_project) } + let(:developer_project) { create(:empty_project) } + let(:master_project) { create(:empty_project) } subject { described_class.new(user) } @@ -37,7 +37,7 @@ describe MoveToProjectFinder do it 'does not return archived projects' do reporter_project.team << [user, :reporter] reporter_project.update_attributes(archived: true) - other_reporter_project = create(:project) + other_reporter_project = create(:empty_project) other_reporter_project.team << [user, :reporter] expect(subject.execute(project).to_a).to eq([other_reporter_project]) @@ -46,7 +46,7 @@ describe MoveToProjectFinder do it 'does not return projects for which issues are disabled' do reporter_project.team << [user, :reporter] reporter_project.update_attributes(issues_enabled: false) - other_reporter_project = create(:project) + other_reporter_project = create(:empty_project) other_reporter_project.team << [user, :reporter] expect(subject.execute(project).to_a).to eq([other_reporter_project]) @@ -83,10 +83,10 @@ describe MoveToProjectFinder do end it 'returns projects matching a search query' do - foo_project = create(:project) + foo_project = create(:empty_project) foo_project.team << [user, :master] - wadus_project = create(:project, name: 'wadus') + wadus_project = create(:empty_project, name: 'wadus') wadus_project.team << [user, :master] expect(subject.execute(project).to_a).to eq([wadus_project, foo_project]) diff --git a/spec/javascripts/filtered_search/dropdown_utils_spec.js.es6 b/spec/javascripts/filtered_search/dropdown_utils_spec.js.es6 index ce61b73aa8a..19bd8d53219 100644 --- a/spec/javascripts/filtered_search/dropdown_utils_spec.js.es6 +++ b/spec/javascripts/filtered_search/dropdown_utils_spec.js.es6 @@ -31,41 +31,68 @@ }); describe('filterWithSymbol', () => { + let input; const item = { title: '@root', }; + beforeEach(() => { + setFixtures(` + <input type="text" id="test" /> + `); + + input = document.getElementById('test'); + }); + it('should filter without symbol', () => { - const updatedItem = gl.DropdownUtils.filterWithSymbol('@', item, ':roo'); + input.value = ':roo'; + + const updatedItem = gl.DropdownUtils.filterWithSymbol('@', input, item); expect(updatedItem.droplab_hidden).toBe(false); }); it('should filter with symbol', () => { - const updatedItem = gl.DropdownUtils.filterWithSymbol('@', item, ':@roo'); + input.value = '@roo'; + + const updatedItem = gl.DropdownUtils.filterWithSymbol('@', input, item); expect(updatedItem.droplab_hidden).toBe(false); }); it('should filter with colon', () => { - const updatedItem = gl.DropdownUtils.filterWithSymbol('@', item, ':'); + input.value = 'roo'; + + const updatedItem = gl.DropdownUtils.filterWithSymbol('@', input, item); expect(updatedItem.droplab_hidden).toBe(false); }); }); describe('filterHint', () => { + let input; + + beforeEach(() => { + setFixtures(` + <input type="text" id="test" /> + `); + + input = document.getElementById('test'); + }); + it('should filter', () => { - let updatedItem = gl.DropdownUtils.filterHint({ + input.value = 'l'; + let updatedItem = gl.DropdownUtils.filterHint(input, { hint: 'label', - }, 'l'); + }); expect(updatedItem.droplab_hidden).toBe(false); - updatedItem = gl.DropdownUtils.filterHint({ + input.value = 'o'; + updatedItem = gl.DropdownUtils.filterHint(input, { hint: 'label', }, 'o'); expect(updatedItem.droplab_hidden).toBe(true); }); it('should return droplab_hidden false when item has no hint', () => { - const updatedItem = gl.DropdownUtils.filterHint({}, ''); + const updatedItem = gl.DropdownUtils.filterHint(input, {}, ''); expect(updatedItem.droplab_hidden).toBe(false); }); }); diff --git a/spec/lib/gitlab/import_export/members_mapper_spec.rb b/spec/lib/gitlab/import_export/members_mapper_spec.rb index 1cb02f8e318..b069696b5c7 100644 --- a/spec/lib/gitlab/import_export/members_mapper_spec.rb +++ b/spec/lib/gitlab/import_export/members_mapper_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Gitlab::ImportExport::MembersMapper, services: true do describe 'map members' do - let(:user) { create(:user, authorized_projects_populated: true) } + let(:user) { create(:admin, authorized_projects_populated: true) } let(:project) { create(:project, :public, name: 'searchable_project') } let(:user2) { create(:user, authorized_projects_populated: true) } let(:exported_user_id) { 99 } @@ -24,7 +24,7 @@ describe Gitlab::ImportExport::MembersMapper, services: true do { "id" => exported_user_id, "email" => user2.email, - "username" => user2.username + "username" => 'test' } }, { @@ -48,6 +48,10 @@ describe Gitlab::ImportExport::MembersMapper, services: true do exported_members: exported_members, user: user, project: project) end + it 'includes the exported user ID in the map' do + expect(members_mapper.map.keys).to include(exported_user_id) + end + it 'maps a project member' do expect(members_mapper.map[exported_user_id]).to eq(user2.id) end @@ -56,12 +60,6 @@ describe Gitlab::ImportExport::MembersMapper, services: true do expect(members_mapper.map[-1]).to eq(user.id) end - it 'updates missing author IDs on missing project member' do - members_mapper.map[-1] - - expect(members_mapper.missing_author_ids.first).to eq(-1) - end - it 'has invited members with no user' do members_mapper.map @@ -74,5 +72,25 @@ describe Gitlab::ImportExport::MembersMapper, services: true do expect(user.authorized_project?(project)).to be true expect(user2.authorized_project?(project)).to be true end + + context 'user is not an admin' do + let(:user) { create(:user, authorized_projects_populated: true) } + + it 'does not map a project member' do + expect(members_mapper.map[exported_user_id]).to eq(user.id) + end + + it 'defaults to importer project member if it does not exist' do + expect(members_mapper.map[-1]).to eq(user.id) + end + end + + context 'chooses the one with an email first' do + let(:user3) { create(:user, username: 'test') } + + it 'maps the project member that has a matching email first' do + expect(members_mapper.map[exported_user_id]).to eq(user2.id) + end + end end end diff --git a/spec/lib/gitlab/import_export/relation_factory_spec.rb b/spec/lib/gitlab/import_export/relation_factory_spec.rb index 3aa492a8ab1..db0084d6823 100644 --- a/spec/lib/gitlab/import_export/relation_factory_spec.rb +++ b/spec/lib/gitlab/import_export/relation_factory_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Gitlab::ImportExport::RelationFactory, lib: true do let(:project) { create(:empty_project) } let(:members_mapper) { double('members_mapper').as_null_object } - let(:user) { create(:user) } + let(:user) { create(:admin) } let(:created_object) do described_class.create(relation_sym: relation_sym, relation_hash: relation_hash, @@ -122,4 +122,60 @@ describe Gitlab::ImportExport::RelationFactory, lib: true do expect(created_object.values).not_to include(99) end end + + context 'Notes user references' do + let(:relation_sym) { :notes } + let(:new_user) { create(:user) } + let(:exported_member) do + { + "id" => 111, + "access_level" => 30, + "source_id" => 1, + "source_type" => "Project", + "user_id" => 3, + "notification_level" => 3, + "created_at" => "2016-11-18T09:29:42.634Z", + "updated_at" => "2016-11-18T09:29:42.634Z", + "user" => { + "id" => 999, + "email" => new_user.email, + "username" => new_user.username + } + } + end + + let(:relation_hash) do + { + "id" => 4947, + "note" => "merged", + "noteable_type" => "MergeRequest", + "author_id" => 999, + "created_at" => "2016-11-18T09:29:42.634Z", + "updated_at" => "2016-11-18T09:29:42.634Z", + "project_id" => 1, + "attachment" => { + "url" => nil + }, + "noteable_id" => 377, + "system" => true, + "author" => { + "name" => "Administrator" + }, + "events" => [ + + ] + } + end + + let(:members_mapper) do + Gitlab::ImportExport::MembersMapper.new( + exported_members: [exported_member], + user: user, + project: project) + end + + it 'maps the right author to the imported note' do + expect(created_object.author).to eq(new_user) + end + end end diff --git a/spec/models/key_spec.rb b/spec/models/key_spec.rb index 5eaddd822be..7c40cfd8253 100644 --- a/spec/models/key_spec.rb +++ b/spec/models/key_spec.rb @@ -30,11 +30,30 @@ describe Key, models: true do end describe "#update_last_used_at" do - it "enqueues a UseKeyWorker job" do - key = create(:key) + let(:key) { create(:key) } + + context 'when key was not updated during the last day' do + before do + allow_any_instance_of(Gitlab::ExclusiveLease).to receive(:try_obtain). + and_return('000000') + end + + it 'enqueues a UseKeyWorker job' do + expect(UseKeyWorker).to receive(:perform_async).with(key.id) + key.update_last_used_at + end + end + + context 'when key was updated during the last day' do + before do + allow_any_instance_of(Gitlab::ExclusiveLease).to receive(:try_obtain). + and_return(false) + end - expect(UseKeyWorker).to receive(:perform_async).with(key.id) - key.update_last_used_at + it 'does not enqueue a UseKeyWorker job' do + expect(UseKeyWorker).not_to receive(:perform_async) + key.update_last_used_at + end end end end diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index 38c80ba53ad..32ed1e96749 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -65,7 +65,7 @@ describe MergeRequest, models: true do end describe '#target_branch_sha' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } subject { create(:merge_request, source_project: project, target_project: project) } @@ -150,7 +150,7 @@ describe MergeRequest, models: true do end it 'supports a cross-project reference' do - another_project = build(:project, name: 'another-project', namespace: project.namespace) + another_project = build(:empty_project, name: 'another-project', namespace: project.namespace) expect(merge_request.to_reference(another_project)).to eq "sample-project!1" end @@ -245,8 +245,8 @@ describe MergeRequest, models: true do describe '#for_fork?' do it 'returns true if the merge request is for a fork' do - subject.source_project = create(:project, namespace: create(:group)) - subject.target_project = create(:project, namespace: create(:group)) + subject.source_project = build_stubbed(:empty_project, namespace: create(:group)) + subject.target_project = build_stubbed(:empty_project, namespace: create(:group)) expect(subject.for_fork?).to be_truthy end @@ -501,8 +501,8 @@ describe MergeRequest, models: true do end describe '#diverged_commits_count' do - let(:project) { create(:project) } - let(:fork_project) { create(:project, forked_from_project: project) } + let(:project) { create(:project, :repository) } + let(:fork_project) { create(:project, :repository, forked_from_project: project) } context 'when the target branch does not exist anymore' do subject { create(:merge_request, source_project: project, target_project: project) } @@ -727,7 +727,7 @@ describe MergeRequest, models: true do end describe '#participants' do - let(:project) { create(:project, :public) } + let(:project) { create(:empty_project, :public) } let(:mr) do create(:merge_request, source_project: project, target_project: project) @@ -768,7 +768,7 @@ describe MergeRequest, models: true do end describe '#check_if_can_be_merged' do - let(:project) { create(:project, only_allow_merge_if_build_succeeds: true) } + let(:project) { create(:empty_project, only_allow_merge_if_build_succeeds: true) } subject { create(:merge_request, source_project: project, merge_status: :unchecked) } @@ -789,7 +789,7 @@ describe MergeRequest, models: true do it 'becomes unmergeable' do expect { subject.check_if_can_be_merged }.to change { subject.merge_status }.to('cannot_be_merged') end - + it 'creates Todo on unmergeability' do expect_any_instance_of(TodoService).to receive(:merge_request_became_unmergeable).with(subject) @@ -810,7 +810,7 @@ describe MergeRequest, models: true do end describe '#mergeable?' do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } subject { create(:merge_request, source_project: project) } @@ -830,7 +830,7 @@ describe MergeRequest, models: true do end describe '#mergeable_state?' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } subject { create(:merge_request, source_project: project) } @@ -957,7 +957,7 @@ describe MergeRequest, models: true do let(:merge_request) { create(:merge_request_with_diff_notes, source_project: project) } context 'when project.only_allow_merge_if_all_discussions_are_resolved == true' do - let(:project) { create(:project, only_allow_merge_if_all_discussions_are_resolved: true) } + let(:project) { create(:project, :repository, only_allow_merge_if_all_discussions_are_resolved: true) } context 'with all discussions resolved' do before do @@ -991,7 +991,7 @@ describe MergeRequest, models: true do end context 'when project.only_allow_merge_if_all_discussions_are_resolved == false' do - let(:project) { create(:project, only_allow_merge_if_all_discussions_are_resolved: false) } + let(:project) { create(:project, :repository, only_allow_merge_if_all_discussions_are_resolved: false) } context 'with unresolved discussions' do before do @@ -1006,7 +1006,7 @@ describe MergeRequest, models: true do end describe "#environments" do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:merge_request) { create(:merge_request, source_project: project) } context 'with multiple environments' do @@ -1024,7 +1024,7 @@ describe MergeRequest, models: true do context 'with environments on source project' do let(:source_project) do - create(:project) do |fork_project| + create(:project, :repository) do |fork_project| fork_project.create_forked_project_link(forked_to_project_id: fork_project.id, forked_from_project_id: project.id) end end @@ -1401,8 +1401,8 @@ describe MergeRequest, models: true do end describe "#source_project_missing?" do - let(:project) { create(:project) } - let(:fork_project) { create(:project, forked_from_project: project) } + let(:project) { create(:empty_project) } + let(:fork_project) { create(:empty_project, forked_from_project: project) } let(:user) { create(:user) } let(:unlink_project) { Projects::UnlinkForkService.new(fork_project, user) } @@ -1439,8 +1439,8 @@ describe MergeRequest, models: true do end describe "#closed_without_fork?" do - let(:project) { create(:project) } - let(:fork_project) { create(:project, forked_from_project: project) } + let(:project) { create(:empty_project) } + let(:fork_project) { create(:empty_project, forked_from_project: project) } let(:user) { create(:user) } let(:unlink_project) { Projects::UnlinkForkService.new(fork_project, user) } @@ -1485,9 +1485,9 @@ describe MergeRequest, models: true do end context 'forked project' do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } let(:user) { create(:user) } - let(:fork_project) { create(:project, forked_from_project: project, namespace: user.namespace) } + let(:fork_project) { create(:empty_project, forked_from_project: project, namespace: user.namespace) } let!(:merge_request) do create(:closed_merge_request, @@ -1531,7 +1531,7 @@ describe MergeRequest, models: true do status: status) end - let(:project) { create(:project, :public, only_allow_merge_if_build_succeeds: true) } + let(:project) { create(:project, :public, :repository, only_allow_merge_if_build_succeeds: true) } let(:developer) { create(:user) } let(:user) { create(:user) } let(:merge_request) { create(:merge_request, source_project: project) } diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index e93a4e62244..8048e86fc3a 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -73,9 +73,7 @@ describe Project, models: true do context 'after initialized' do it "has a project_feature" do - project = FactoryGirl.build(:project) - - expect(project.project_feature.present?).to be_present + expect(Project.new.project_feature).to be_present end end @@ -129,7 +127,7 @@ describe Project, models: true do end describe 'validation' do - let!(:project) { create(:project) } + let!(:project) { create(:empty_project) } it { is_expected.to validate_presence_of(:name) } it { is_expected.to validate_uniqueness_of(:name).scoped_to(:namespace_id) } @@ -148,7 +146,7 @@ describe Project, models: true do it { is_expected.to validate_presence_of(:repository_storage) } it 'does not allow new projects beyond user limits' do - project2 = build(:project) + project2 = build(:empty_project) allow(project2).to receive(:creator).and_return(double(can_create_project?: false, projects_limit: 0).as_null_object) expect(project2).not_to be_valid expect(project2.errors[:limit_reached].first).to match(/Personal project creation is not allowed/) @@ -157,7 +155,7 @@ describe Project, models: true do describe 'wiki path conflict' do context "when the new path has been used by the wiki of other Project" do it 'has an error on the name attribute' do - new_project = build_stubbed(:project, namespace_id: project.namespace_id, path: "#{project.path}.wiki") + new_project = build_stubbed(:empty_project, namespace_id: project.namespace_id, path: "#{project.path}.wiki") expect(new_project).not_to be_valid expect(new_project.errors[:name].first).to eq('has already been taken') @@ -166,8 +164,8 @@ describe Project, models: true do context "when the new wiki path has been used by the path of other Project" do it 'has an error on the name attribute' do - project_with_wiki_suffix = create(:project, path: 'foo.wiki') - new_project = build_stubbed(:project, namespace_id: project_with_wiki_suffix.namespace_id, path: 'foo') + project_with_wiki_suffix = create(:empty_project, path: 'foo.wiki') + new_project = build_stubbed(:empty_project, namespace_id: project_with_wiki_suffix.namespace_id, path: 'foo') expect(new_project).not_to be_valid expect(new_project.errors[:name].first).to eq('has already been taken') @@ -176,7 +174,7 @@ describe Project, models: true do end context 'repository storages inclussion' do - let(:project2) { build(:project, repository_storage: 'missing') } + let(:project2) { build(:empty_project, repository_storage: 'missing') } before do storages = { 'custom' => 'tmp/tests/custom_repositories' } @@ -352,7 +350,7 @@ describe Project, models: true do end describe '#repository_storage_path' do - let(:project) { create(:project, repository_storage: 'custom') } + let(:project) { create(:empty_project, repository_storage: 'custom') } before do FileUtils.mkdir('tmp/tests/custom_repositories') @@ -412,7 +410,7 @@ describe Project, models: true do describe 'last_activity methods' do let(:timestamp) { 2.hours.ago } # last_activity_at gets set to created_at upon creation - let(:project) { create(:project, created_at: timestamp, updated_at: timestamp) } + let(:project) { create(:empty_project, created_at: timestamp, updated_at: timestamp) } describe 'last_activity' do it 'alias last_activity to last_event' do @@ -496,7 +494,7 @@ describe Project, models: true do context 'with namespace' do before do @group = create :group, name: 'gitlab' - @project = create(:project, name: 'gitlabhq', namespace: @group) + @project = create(:empty_project, name: 'gitlabhq', namespace: @group) end it { expect(@project.to_param).to eq('gitlabhq') } @@ -522,7 +520,7 @@ describe Project, models: true do end describe '#repository' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } it 'returns valid repo' do expect(project.repository).to be_kind_of(Repository) @@ -530,20 +528,22 @@ describe Project, models: true do end describe '#default_issues_tracker?' do - let(:project) { create(:project) } - let(:ext_project) { create(:redmine_project) } - it "is true if used internal tracker" do + project = build(:empty_project) + expect(project.default_issues_tracker?).to be_truthy end it "is false if used other tracker" do - expect(ext_project.default_issues_tracker?).to be_falsey + # NOTE: The current nature of this factory requires persistence + project = create(:redmine_project) + + expect(project.default_issues_tracker?).to be_falsey end end describe '#external_issue_tracker' do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } let(:ext_project) { create(:redmine_project) } context 'on existing projects with no value for has_external_issue_tracker' do @@ -578,7 +578,7 @@ describe Project, models: true do end describe '#cache_has_external_issue_tracker' do - let(:project) { create(:project, has_external_issue_tracker: nil) } + let(:project) { create(:empty_project, has_external_issue_tracker: nil) } it 'stores true if there is any external_issue_tracker' do services = double(:service, external_issue_trackers: [RedmineService.new]) @@ -600,9 +600,9 @@ describe Project, models: true do end describe '#has_wiki?' do - let(:no_wiki_project) { create(:project, wiki_access_level: ProjectFeature::DISABLED, has_external_wiki: false) } - let(:wiki_enabled_project) { create(:project) } - let(:external_wiki_project) { create(:project, has_external_wiki: true) } + let(:no_wiki_project) { create(:empty_project, wiki_access_level: ProjectFeature::DISABLED, has_external_wiki: false) } + let(:wiki_enabled_project) { create(:empty_project) } + let(:external_wiki_project) { create(:empty_project, has_external_wiki: true) } it 'returns true if project is wiki enabled or has external wiki' do expect(wiki_enabled_project).to have_wiki @@ -612,7 +612,7 @@ describe Project, models: true do end describe '#external_wiki' do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } context 'with an active external wiki' do before do @@ -663,7 +663,7 @@ describe Project, models: true do end describe '#open_branches' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } before do project.protected_branches.create(name: 'master') @@ -685,7 +685,7 @@ describe Project, models: true do it 'counts stars from multiple users' do user1 = create :user user2 = create :user - project = create :project, :public + project = create(:empty_project, :public) expect(project.star_count).to eq(0) @@ -707,8 +707,8 @@ describe Project, models: true do it 'counts stars on the right project' do user = create :user - project1 = create :project, :public - project2 = create :project, :public + project1 = create(:empty_project, :public) + project2 = create(:empty_project, :public) expect(project1.star_count).to eq(0) expect(project2.star_count).to eq(0) @@ -740,7 +740,7 @@ describe Project, models: true do end describe '#avatar_type' do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } it 'is true if avatar is image' do project.update_attribute(:avatar, 'uploads/avatar.png') @@ -756,7 +756,7 @@ describe Project, models: true do describe '#avatar_url' do subject { project.avatar_url } - let(:project) { create(:project) } + let(:project) { create(:empty_project) } context 'When avatar file is uploaded' do before do @@ -791,7 +791,7 @@ describe Project, models: true do end describe '#pipeline_for' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let!(:pipeline) { create_pipeline } shared_examples 'giving the correct pipeline' do @@ -825,7 +825,7 @@ describe Project, models: true do end describe '#builds_enabled' do - let(:project) { create :project } + let(:project) { create(:empty_project) } subject { project.builds_enabled } @@ -877,7 +877,7 @@ describe Project, models: true do end describe '.visible_to_user' do - let!(:project) { create(:project, :private) } + let!(:project) { create(:empty_project, :private) } let!(:user) { create(:user) } subject { described_class.visible_to_user(user) } @@ -975,7 +975,7 @@ describe Project, models: true do end describe '#visibility_level_allowed?' do - let(:project) { create(:project, :internal) } + let(:project) { create(:empty_project, :internal) } context 'when checking on non-forked project' do it { expect(project.visibility_level_allowed?(Gitlab::VisibilityLevel::PRIVATE)).to be_truthy } @@ -984,8 +984,8 @@ describe Project, models: true do end context 'when checking on forked project' do - let(:project) { create(:project, :internal) } - let(:forked_project) { create(:project, forked_from_project: project) } + let(:project) { create(:empty_project, :internal) } + let(:forked_project) { create(:empty_project, forked_from_project: project) } it { expect(forked_project.visibility_level_allowed?(Gitlab::VisibilityLevel::PRIVATE)).to be_truthy } it { expect(forked_project.visibility_level_allowed?(Gitlab::VisibilityLevel::INTERNAL)).to be_truthy } @@ -994,7 +994,7 @@ describe Project, models: true do end describe '.search' do - let(:project) { create(:project, description: 'kitten mittens') } + let(:project) { create(:empty_project, description: 'kitten mittens') } it 'returns projects with a matching name' do expect(described_class.search(project.name)).to eq([project]) @@ -1052,7 +1052,7 @@ describe Project, models: true do end describe '#rename_repo' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:gitlab_shell) { Gitlab::Shell.new } before do @@ -1102,7 +1102,7 @@ describe Project, models: true do end describe '#expire_caches_before_rename' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:repo) { double(:repo, exists?: true) } let(:wiki) { double(:wiki, exists?: true) } @@ -1123,7 +1123,7 @@ describe Project, models: true do end describe '.search_by_title' do - let(:project) { create(:project, name: 'kittens') } + let(:project) { create(:empty_project, name: 'kittens') } it 'returns projects with a matching name' do expect(described_class.search_by_title(project.name)).to eq([project]) @@ -1142,8 +1142,8 @@ describe Project, models: true do let(:private_group) { create(:group, visibility_level: 0) } let(:internal_group) { create(:group, visibility_level: 10) } - let(:private_project) { create :project, :private, group: private_group } - let(:internal_project) { create :project, :internal, group: internal_group } + let(:private_project) { create :empty_project, :private, group: private_group } + let(:internal_project) { create :empty_project, :internal, group: internal_group } context 'when group is private project can not be internal' do it { expect(private_project.visibility_level_allowed?(Gitlab::VisibilityLevel::INTERNAL)).to be_falsey } @@ -1155,7 +1155,7 @@ describe Project, models: true do end describe '#create_repository' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:shell) { Gitlab::Shell.new } before do @@ -1197,7 +1197,7 @@ describe Project, models: true do describe '#protected_branch?' do context 'existing project' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } it 'returns true when the branch matches a protected branch via direct match' do create(:protected_branch, project: project, name: "foo") @@ -1381,7 +1381,7 @@ describe Project, models: true do name: name) end - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:pipeline) { create_pipeline } context 'with many builds' do @@ -1461,7 +1461,7 @@ describe Project, models: true do end context 'not forked' do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } it 'schedules a RepositoryImportWorker job' do expect(RepositoryImportWorker).to receive(:perform_async).with(project.id) @@ -1472,19 +1472,19 @@ describe Project, models: true do end describe '#gitlab_project_import?' do - subject(:project) { build(:project, import_type: 'gitlab_project') } + subject(:project) { build(:empty_project, import_type: 'gitlab_project') } it { expect(project.gitlab_project_import?).to be true } end describe '#gitea_import?' do - subject(:project) { build(:project, import_type: 'gitea') } + subject(:project) { build(:empty_project, import_type: 'gitea') } it { expect(project.gitea_import?).to be true } end describe '#lfs_enabled?' do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } shared_examples 'project overrides group' do it 'returns true when enabled in project' do @@ -1546,7 +1546,7 @@ describe Project, models: true do end describe '#change_head' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } it 'calls the before_change_head and after_change_head methods' do expect(project.repository).to receive(:before_change_head) @@ -1574,7 +1574,7 @@ describe Project, models: true do end describe '#pushes_since_gc' do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } after do project.reset_pushes_since_gc @@ -1596,7 +1596,7 @@ describe Project, models: true do end describe '#increment_pushes_since_gc' do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } after do project.reset_pushes_since_gc @@ -1610,7 +1610,7 @@ describe Project, models: true do end describe '#reset_pushes_since_gc' do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } after do project.reset_pushes_since_gc @@ -1626,7 +1626,7 @@ describe Project, models: true do end describe '#environments_for' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:environment) { create(:environment, project: project) } context 'tagged deployment' do @@ -1678,7 +1678,7 @@ describe Project, models: true do end describe '#environments_recently_updated_on_branch' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:environment) { create(:environment, project: project) } context 'when last deployment to environment is the most recent one' do diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 8b20ee81614..ca3d4ff0aa9 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -48,7 +48,7 @@ describe User, models: true do describe '#project_members' do it 'does not include project memberships for which user is a requester' do user = create(:user) - project = create(:project, :public, :access_requestable) + project = create(:empty_project, :public, :access_requestable) project.request_access(user) expect(user.project_members).to be_empty @@ -386,13 +386,15 @@ describe User, models: true do describe 'projects' do before do - @user = create :user - @project = create :project, namespace: @user.namespace - @project_2 = create :project, group: create(:group) # Grant MASTER access to the user - @project_3 = create :project, group: create(:group) # Grant DEVELOPER access to the user + @user = create(:user) - @project_2.team << [@user, :master] - @project_3.team << [@user, :developer] + @project = create(:empty_project, namespace: @user.namespace) + @project_2 = create(:empty_project, group: create(:group)) do |project| + project.add_master(@user) + end + @project_3 = create(:empty_project, group: create(:group)) do |project| + project.add_developer(@user) + end end it { expect(@user.authorized_projects).to include(@project) } @@ -435,7 +437,7 @@ describe User, models: true do describe 'namespaced' do before do @user = create :user - @project = create :project, namespace: @user.namespace + @project = create(:empty_project, namespace: @user.namespace) end it { expect(@user.several_namespaces?).to be_falsey } @@ -517,7 +519,7 @@ describe User, models: true do before do User.delete_all @user = create :user - @project = create :project + @project = create(:empty_project) end it { expect(User.not_in_project(@project)).to include(@user, @project.owner) } @@ -927,8 +929,8 @@ describe User, models: true do describe "#starred?" do it "determines if user starred a project" do user = create :user - project1 = create :project, :public - project2 = create :project, :public + project1 = create(:empty_project, :public) + project2 = create(:empty_project, :public) expect(user.starred?(project1)).to be_falsey expect(user.starred?(project2)).to be_falsey @@ -954,7 +956,7 @@ describe User, models: true do describe "#toggle_star" do it "toggles stars" do user = create :user - project = create :project, :public + project = create(:empty_project, :public) expect(user.starred?(project)).to be_falsey user.toggle_star(project) @@ -994,9 +996,9 @@ describe User, models: true do describe "#contributed_projects" do subject { create(:user) } - let!(:project1) { create(:project) } - let!(:project2) { create(:project, forked_from_project: project3) } - let!(:project3) { create(:project) } + let!(:project1) { create(:empty_project) } + let!(:project2) { create(:empty_project, forked_from_project: project3) } + let!(:project3) { create(:empty_project) } let!(:merge_request) { create(:merge_request, source_project: project2, target_project: project3, author: subject) } let!(:push_event) { create(:event, action: Event::PUSHED, project: project1, target: project1, author: subject) } let!(:merge_event) { create(:event, action: Event::CREATED, project: project3, target: merge_request, author: subject) } @@ -1038,8 +1040,8 @@ describe User, models: true do describe "#recent_push" do subject { create(:user) } - let!(:project1) { create(:project) } - let!(:project2) { create(:project, forked_from_project: project1) } + let!(:project1) { create(:project, :repository) } + let!(:project2) { create(:project, :repository, forked_from_project: project1) } let!(:push_data) do Gitlab::DataBuilder::Push.build_sample(project2, subject) end @@ -1113,7 +1115,7 @@ describe User, models: true do it "includes user's personal projects" do user = create(:user) - project = create(:project, :private, namespace: user.namespace) + project = create(:empty_project, :private, namespace: user.namespace) expect(user.authorized_projects).to include(project) end @@ -1121,7 +1123,7 @@ describe User, models: true do it "includes personal projects user has been given access to" do user1 = create(:user) user2 = create(:user) - project = create(:project, :private, namespace: user1.namespace) + project = create(:empty_project, :private, namespace: user1.namespace) project.team << [user2, Gitlab::Access::DEVELOPER] @@ -1130,7 +1132,7 @@ describe User, models: true do it "includes projects of groups user has been added to" do group = create(:group) - project = create(:project, group: group) + project = create(:empty_project, group: group) user = create(:user) group.add_developer(user) @@ -1140,7 +1142,7 @@ describe User, models: true do it "does not include projects of groups user has been removed from" do group = create(:group) - project = create(:project, group: group) + project = create(:empty_project, group: group) user = create(:user) member = group.add_developer(user) @@ -1152,7 +1154,7 @@ describe User, models: true do it "includes projects shared with user's group" do user = create(:user) - project = create(:project, :private) + project = create(:empty_project, :private) group = create(:group) group.add_reporter(user) @@ -1164,7 +1166,7 @@ describe User, models: true do it "does not include destroyed projects user had access to" do user1 = create(:user) user2 = create(:user) - project = create(:project, :private, namespace: user1.namespace) + project = create(:empty_project, :private, namespace: user1.namespace) project.team << [user2, Gitlab::Access::DEVELOPER] expect(user2.authorized_projects).to include(project) @@ -1175,7 +1177,7 @@ describe User, models: true do it "does not include projects of destroyed groups user had access to" do group = create(:group) - project = create(:project, namespace: group) + project = create(:empty_project, namespace: group) user = create(:user) group.add_developer(user) @@ -1190,14 +1192,9 @@ describe User, models: true do let(:user) { create(:user) } it 'includes projects for which the user access level is above or equal to reporter' do - create(:project) - reporter_project = create(:project) - developer_project = create(:project) - master_project = create(:project) - - reporter_project.team << [user, :reporter] - developer_project.team << [user, :developer] - master_project.team << [user, :master] + reporter_project = create(:empty_project) { |p| p.add_reporter(user) } + developer_project = create(:empty_project) { |p| p.add_developer(user) } + master_project = create(:empty_project) { |p| p.add_master(user) } expect(user.projects_where_can_admin_issues.to_a).to eq([master_project, developer_project, reporter_project]) expect(user.can?(:admin_issue, master_project)).to eq(true) @@ -1206,10 +1203,8 @@ describe User, models: true do end it 'does not include for which the user access level is below reporter' do - project = create(:project) - guest_project = create(:project) - - guest_project.team << [user, :guest] + project = create(:empty_project) + guest_project = create(:empty_project) { |p| p.add_guest(user) } expect(user.projects_where_can_admin_issues.to_a).to be_empty expect(user.can?(:admin_issue, guest_project)).to eq(false) @@ -1217,15 +1212,14 @@ describe User, models: true do end it 'does not include archived projects' do - project = create(:project) - project.update_attributes(archived: true) + project = create(:empty_project, :archived) expect(user.projects_where_can_admin_issues.to_a).to be_empty expect(user.can?(:admin_issue, project)).to eq(false) end it 'does not include projects for which issues are disabled' do - project = create(:project, issues_access_level: ProjectFeature::DISABLED) + project = create(:empty_project, issues_access_level: ProjectFeature::DISABLED) expect(user.projects_where_can_admin_issues.to_a).to be_empty expect(user.can?(:admin_issue, project)).to eq(false) @@ -1241,7 +1235,7 @@ describe User, models: true do end context 'without any projects' do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } it 'does not load' do expect(user.ci_authorized_runners).to be_empty @@ -1250,7 +1244,7 @@ describe User, models: true do context 'with personal projects runners' do let(:namespace) { create(:namespace, owner: user) } - let(:project) { create(:project, namespace: namespace) } + let(:project) { create(:empty_project, namespace: namespace) } it 'loads' do expect(user.ci_authorized_runners).to contain_exactly(runner) @@ -1281,7 +1275,7 @@ describe User, models: true do context 'with groups projects runners' do let(:group) { create(:group) } - let(:project) { create(:project, group: group) } + let(:project) { create(:empty_project, group: group) } def add_user(access) group.add_user(user, access) @@ -1291,7 +1285,7 @@ describe User, models: true do end context 'with other projects runners' do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } def add_user(access) project.team << [user, access] @@ -1321,8 +1315,8 @@ describe User, models: true do end describe '#projects_with_reporter_access_limited_to' do - let(:project1) { create(:project) } - let(:project2) { create(:project) } + let(:project1) { create(:empty_project) } + let(:project2) { create(:empty_project) } let(:user) { create(:user) } before do diff --git a/spec/requests/projects/cycle_analytics_events_spec.rb b/spec/requests/projects/cycle_analytics_events_spec.rb index e0368e6001f..72978846e93 100644 --- a/spec/requests/projects/cycle_analytics_events_spec.rb +++ b/spec/requests/projects/cycle_analytics_events_spec.rb @@ -1,6 +1,8 @@ require 'spec_helper' describe 'cycle analytics events' do + include ApiHelpers + let(:user) { create(:user) } let(:project) { create(:project, public_builds: false) } let(:issue) { create(:issue, project: project, created_at: 2.days.ago) } @@ -20,19 +22,19 @@ describe 'cycle analytics events' do it 'lists the issue events' do get namespace_project_cycle_analytics_issue_path(project.namespace, project, format: :json) - expect(json_response['events']).not_to be_empty - - first_issue_iid = Issue.order(created_at: :desc).pluck(:iid).first.to_s + first_issue_iid = project.issues.sort(:created_desc).pluck(:iid).first.to_s + expect(json_response['events']).not_to be_empty expect(json_response['events'].first['iid']).to eq(first_issue_iid) end it 'lists the plan events' do get namespace_project_cycle_analytics_plan_path(project.namespace, project, format: :json) - expect(json_response['events']).not_to be_empty + first_mr_short_sha = project.merge_requests.sort(:created_asc).first.commits.first.short_id - expect(json_response['events'].first['short_sha']).to eq(MergeRequest.last.commits.first.short_id) + expect(json_response['events']).not_to be_empty + expect(json_response['events'].first['short_sha']).to eq(first_mr_short_sha) end it 'lists the code events' do @@ -40,7 +42,7 @@ describe 'cycle analytics events' do expect(json_response['events']).not_to be_empty - first_mr_iid = project.merge_requests.order(id: :desc).pluck(:iid).first.to_s + first_mr_iid = project.merge_requests.sort(:created_desc).pluck(:iid).first.to_s expect(json_response['events'].first['iid']).to eq(first_mr_iid) end @@ -49,17 +51,15 @@ describe 'cycle analytics events' do get namespace_project_cycle_analytics_test_path(project.namespace, project, format: :json) expect(json_response['events']).not_to be_empty - expect(json_response['events'].first['date']).not_to be_empty end it 'lists the review events' do get namespace_project_cycle_analytics_review_path(project.namespace, project, format: :json) - expect(json_response['events']).not_to be_empty - - first_mr_iid = MergeRequest.order(created_at: :desc).pluck(:iid).first.to_s + first_mr_iid = project.merge_requests.sort(:created_desc).pluck(:iid).first.to_s + expect(json_response['events']).not_to be_empty expect(json_response['events'].first['iid']).to eq(first_mr_iid) end @@ -67,35 +67,32 @@ describe 'cycle analytics events' do get namespace_project_cycle_analytics_staging_path(project.namespace, project, format: :json) expect(json_response['events']).not_to be_empty - expect(json_response['events'].first['date']).not_to be_empty end it 'lists the production events' do get namespace_project_cycle_analytics_production_path(project.namespace, project, format: :json) - expect(json_response['events']).not_to be_empty - - first_issue_iid = Issue.order(created_at: :desc).pluck(:iid).first.to_s + first_issue_iid = project.issues.sort(:created_desc).pluck(:iid).first.to_s + expect(json_response['events']).not_to be_empty expect(json_response['events'].first['iid']).to eq(first_issue_iid) end context 'specific branch' do it 'lists the test events' do - branch = MergeRequest.first.source_branch + branch = project.merge_requests.first.source_branch get namespace_project_cycle_analytics_test_path(project.namespace, project, format: :json, branch: branch) expect(json_response['events']).not_to be_empty - expect(json_response['events'].first['date']).not_to be_empty end end context 'with private project and builds' do before do - ProjectMember.first.update(access_level: Gitlab::Access::GUEST) + project.members.first.update(access_level: Gitlab::Access::GUEST) end it 'does not list the test events' do @@ -118,10 +115,6 @@ describe 'cycle analytics events' do end end - def json_response - JSON.parse(response.body) - end - def create_cycle milestone = create(:milestone, project: project) issue.update(milestone: milestone) diff --git a/spec/serializers/pipeline_entity_spec.rb b/spec/serializers/pipeline_entity_spec.rb index b19464c7117..ccb72973f9c 100644 --- a/spec/serializers/pipeline_entity_spec.rb +++ b/spec/serializers/pipeline_entity_spec.rb @@ -134,5 +134,17 @@ describe PipelineEntity do expect(subject).not_to have_key(:yaml_errors) end end + + context 'when pipeline ref is empty' do + let(:pipeline) { create(:ci_empty_pipeline) } + + before do + allow(pipeline).to receive(:ref).and_return(nil) + end + + it 'does not generate branch path' do + expect(subject[:ref][:path]).to be_nil + end + end end end diff --git a/spec/services/ci/update_build_queue_service_spec.rb b/spec/services/ci/update_build_queue_service_spec.rb new file mode 100644 index 00000000000..f01a388b895 --- /dev/null +++ b/spec/services/ci/update_build_queue_service_spec.rb @@ -0,0 +1,47 @@ +require 'spec_helper' + +describe Ci::UpdateBuildQueueService, :services do + let(:project) { create(:project) } + let(:build) { create(:ci_build, pipeline: pipeline) } + let(:pipeline) { create(:ci_pipeline, project: project) } + + context 'when updating specific runners' do + let(:runner) { create(:ci_runner) } + + context 'when there are runner that can pick build' do + before { build.project.runners << runner } + + it 'ticks runner queue value' do + expect { subject.execute(build) } + .to change { runner.ensure_runner_queue_value } + end + end + + context 'when there are no runners that can pick build' do + it 'does not tick runner queue value' do + expect { subject.execute(build) } + .not_to change { runner.ensure_runner_queue_value } + end + end + end + + context 'when updating shared runners' do + let(:runner) { create(:ci_runner, :shared) } + + context 'when there are runner that can pick build' do + it 'ticks runner queue value' do + expect { subject.execute(build) } + .to change { runner.ensure_runner_queue_value } + end + end + + context 'when there are no runners that can pick build' do + before { build.tag_list = [:docker] } + + it 'does not tick runner queue value' do + expect { subject.execute(build) } + .not_to change { runner.ensure_runner_queue_value } + end + end + end +end diff --git a/vendor/gitlab-ci-yml/autodeploy/Kubernetes.gitlab-ci.yml b/vendor/gitlab-ci-yml/autodeploy/Kubernetes.gitlab-ci.yml new file mode 100644 index 00000000000..36dfc539b3b --- /dev/null +++ b/vendor/gitlab-ci-yml/autodeploy/Kubernetes.gitlab-ci.yml @@ -0,0 +1,76 @@ +# Explaination on the scripts: +# https://gitlab.com/gitlab-examples/kubernetes-deploy/blob/master/README.md +image: registry.gitlab.com/gitlab-examples/kubernetes-deploy + +variables: + # Application deployment domain + KUBE_DOMAIN: domain.example.com + +stages: + - build + - test + - review + - staging + - production + +build: + stage: build + script: + - command build + only: + - branches + +production: + stage: production + variables: + CI_ENVIRONMENT_URL: http://production.$KUBE_DOMAIN + script: + - command deploy + environment: + name: production + url: http://production.$KUBE_DOMAIN + when: manual + only: + - master + +staging: + stage: staging + variables: + CI_ENVIRONMENT_URL: http://staging.$KUBE_DOMAIN + script: + - command deploy + environment: + name: staging + url: http://staging.$KUBE_DOMAIN + only: + - master + +review: + stage: review + variables: + CI_ENVIRONMENT_URL: http://$CI_ENVIRONMENT_SLUG.$KUBE_DOMAIN + script: + - command deploy + environment: + name: review/$CI_BUILD_REF_NAME + url: http://$CI_ENVIRONMENT_SLUG.$KUBE_DOMAIN + on_stop: stop_review + only: + - branches + except: + - master + +stop_review: + stage: review + variables: + GIT_STRATEGY: none + script: + - command destroy + environment: + name: review/$CI_BUILD_REF_NAME + action: stop + when: manual + only: + - branches + except: + - master |