diff options
144 files changed, 2646 insertions, 900 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 6a5050b553f..5710effc39d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -453,6 +453,7 @@ db:migrate:reset-mysql: stage: test variables: SETUP_DB: "false" + CREATE_DB_USER: "true" script: - git fetch https://gitlab.com/gitlab-org/gitlab-ce.git v9.3.0 - git checkout -f FETCH_HEAD @@ -497,6 +498,7 @@ db:rollback-mysql: variables: SIZE: "1" SETUP_DB: "false" + CREATE_DB_USER: "true" script: - git clone https://gitlab.com/gitlab-org/gitlab-test.git /home/git/repositories/gitlab-org/gitlab-test.git @@ -532,7 +534,6 @@ gitlab:assets:compile: NODE_ENV: "production" RAILS_ENV: "production" SETUP_DB: "false" - USE_DB: "false" SKIP_STORAGE_VALIDATION: "true" WEBPACK_REPORT: "true" NO_COMPRESSION: "true" diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f13eca2caf..4294ccaf9b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,28 @@ documentation](doc/development/changelog.md) for instructions on adding your own entry. +## 10.1.3 (2017-11-10) + +- [SECURITY] Prevent OAuth phishing attack by presenting detailed wording about app to user during authorization. +- [FIXED] Fix cancel button not working while uploading on the new issue page. !15137 +- [FIXED] Fix webhooks recent deliveries. !15146 (Alexander Randa (@randaalex)) +- [FIXED] Fix issues with forked projects of which the source was deleted. !15150 +- [FIXED] Fix GPG signature popup info in Safari and Firefox. !15228 +- [FIXED] Make sure group and project creation is blocked for new users that are external by default. +- [FIXED] Fix arguments Import/Export error importing project merge requests. +- [FIXED] Fix diff parser so it tolerates to diff special markers in the content. +- [FIXED] Fix a migration that adds merge_requests_ff_only_enabled column to MR table. +- [FIXED] Render 404 when polling commit notes without having permissions. +- [FIXED] Show error message when fast-forward merge is not possible. +- [FIXED] Avoid regenerating the ref path for the environment. +- [PERFORMANCE] Remove Filesystem check metrics that use too much CPU to handle requests. + +## 10.1.2 (2017-11-08) + +- [SECURITY] Add X-Content-Type-Options header in API responses to make it more difficult to find other vulnerabilities. +- [SECURITY] Properly translate IP addresses written in decimal, octal, or other formats in SSRF protections in project imports. +- [FIXED] Fix TRIGGER checks for MySQL. + ## 10.1.1 (2017-10-31) - [FIXED] Auto Devops kubernetes default namespace is now correctly built out of gitlab project group-name. !14642 (Mircea Danila Dumitrescu) diff --git a/PROCESS.md b/PROCESS.md index 06963243b25..7c8db689256 100644 --- a/PROCESS.md +++ b/PROCESS.md @@ -141,21 +141,29 @@ the stable branch are: * Fixes for security issues * New or updated translations (as long as they do not touch application code) -During the feature freeze all merge requests that are meant to go into the upcoming -release should have the correct milestone assigned _and_ have the label -~"Pick into Stable" set, so that release managers can find and pick them. -Merge requests without a milestone and this label will -not be merged into any stable branches. - -Fixes marked like this will be shipped in the next RC for that release. Once -the final RC has been prepared ready for release on the 22nd, further fixes -marked ~"Pick into Stable" will go into a patch for that release. - -If a merge request is to be picked into more than one release it will also need -the ~"Pick into Backports" label set to remind the release manager to change -the milestone after cherry-picking. As before, it should still have the -~"Pick into Stable" label and the milestone of the highest release it will be -picked into. +During the feature freeze all merge requests that are meant to go into the +upcoming release should have the correct milestone assigned _and_ the +`Pick into X.Y` label where `X.Y` is equal to the milestone, so that release +managers can find and pick them. +Merge requests without this label will not be picked into the stable release. + +For example, if the upcoming release is `10.2.0` you will need to set the +`Pick into 10.2` label. + +Fixes marked like this will be shipped in the next RC (before the 22nd), or the +next patch release. + +If a merge request is to be picked into more than one release it will need one +`Pick into X.Y` label per release where the merge request should be back-ported +to. + +For example, if the current patch release is `10.1.1` and a regression fix needs +to be backported down to the `9.5` release, you will need to assign it the +`10.1` milestone and the following labels: + +- `Pick into 10.1` +- `Pick into 10.0` +- `Pick into 9.5` ### Asking for an exception diff --git a/app/assets/javascripts/abuse_reports.js b/app/assets/javascripts/abuse_reports.js index 3de192d56eb..d2d3a257c0d 100644 --- a/app/assets/javascripts/abuse_reports.js +++ b/app/assets/javascripts/abuse_reports.js @@ -1,3 +1,5 @@ +import { truncate } from './lib/utils/text_utility'; + const MAX_MESSAGE_LENGTH = 500; const MESSAGE_CELL_SELECTOR = '.abuse-reports .message'; @@ -15,7 +17,7 @@ export default class AbuseReports { if (reportMessage.length > MAX_MESSAGE_LENGTH) { $messageCellElement.data('original-message', reportMessage); $messageCellElement.data('message-truncated', 'true'); - $messageCellElement.text(window.gl.text.truncate(reportMessage, MAX_MESSAGE_LENGTH)); + $messageCellElement.text(truncate(reportMessage, MAX_MESSAGE_LENGTH)); } } diff --git a/app/assets/javascripts/boards/components/modal/footer.js b/app/assets/javascripts/boards/components/modal/footer.js index de9e44cef35..182957113a2 100644 --- a/app/assets/javascripts/boards/components/modal/footer.js +++ b/app/assets/javascripts/boards/components/modal/footer.js @@ -3,6 +3,7 @@ import Vue from 'vue'; import Flash from '../../../flash'; import './lists_dropdown'; +import { pluralize } from '../../../lib/utils/text_utility'; const ModalStore = gl.issueBoards.ModalStore; @@ -21,7 +22,7 @@ gl.issueBoards.ModalFooter = Vue.extend({ submitText() { const count = ModalStore.selectedCount(); - return `Add ${count > 0 ? count : ''} ${gl.text.pluralize('issue', count)}`; + return `Add ${count > 0 ? count : ''} ${pluralize('issue', count)}`; }, }, methods: { diff --git a/app/assets/javascripts/commits.js b/app/assets/javascripts/commits.js index ae6b8902032..9b952ea7b60 100644 --- a/app/assets/javascripts/commits.js +++ b/app/assets/javascripts/commits.js @@ -3,6 +3,8 @@ prefer-template, object-shorthand, prefer-arrow-callback */ /* global Pager */ +import { pluralize } from './lib/utils/text_utility'; + export default (function () { const CommitsList = {}; @@ -86,7 +88,7 @@ export default (function () { // Update commits count in the previous commits header. commitsCount += Number($(processedData).nextUntil('li.js-commit-header').first().find('li.commit').length); - $commitsHeadersLast.find('span.commits-count').text(`${commitsCount} ${gl.text.pluralize('commit', commitsCount)}`); + $commitsHeadersLast.find('span.commits-count').text(`${commitsCount} ${pluralize('commit', commitsCount)}`); } gl.utils.localTimeAgo($processedData.find('.js-timeago')); diff --git a/app/assets/javascripts/create_label.js b/app/assets/javascripts/create_label.js index 3bed0678350..9a4c9bfcc80 100644 --- a/app/assets/javascripts/create_label.js +++ b/app/assets/javascripts/create_label.js @@ -1,5 +1,6 @@ /* eslint-disable func-names, prefer-arrow-callback */ import Api from './api'; +import { humanize } from './lib/utils/text_utility'; export default class CreateLabelDropdown { constructor($el, namespacePath, projectPath) { @@ -107,7 +108,7 @@ export default class CreateLabelDropdown { errors = label.message; } else { errors = Object.keys(label.message).map(key => - `${gl.text.humanize(key)} ${label.message[key].join(', ')}`, + `${humanize(key)} ${label.message[key].join(', ')}`, ).join('<br/>'); } diff --git a/app/assets/javascripts/cycle_analytics/cycle_analytics_store.js b/app/assets/javascripts/cycle_analytics/cycle_analytics_store.js index 8bf9ae17de0..a8cd8c20f8f 100644 --- a/app/assets/javascripts/cycle_analytics/cycle_analytics_store.js +++ b/app/assets/javascripts/cycle_analytics/cycle_analytics_store.js @@ -1,7 +1,7 @@ /* eslint-disable no-param-reassign */ import { __ } from '../locale'; -import '../lib/utils/text_utility'; +import { dasherize } from '../lib/utils/text_utility'; import DEFAULT_EVENT_OBJECTS from './default_event_objects'; const EMPTY_STAGE_TEXTS = { @@ -36,7 +36,7 @@ export default { }); newData.stages.forEach((item) => { - const stageSlug = gl.text.dasherize(item.name.toLowerCase()); + const stageSlug = dasherize(item.name.toLowerCase()); item.active = false; item.isUserAllowed = data.permissions[stageSlug]; item.emptyStageText = EMPTY_STAGE_TEXTS[stageSlug]; diff --git a/app/assets/javascripts/environments/components/environment_item.vue b/app/assets/javascripts/environments/components/environment_item.vue index fc0308b81ba..9d25f806c0d 100644 --- a/app/assets/javascripts/environments/components/environment_item.vue +++ b/app/assets/javascripts/environments/components/environment_item.vue @@ -2,7 +2,7 @@ import Timeago from 'timeago.js'; import _ from 'underscore'; import userAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue'; -import '../../lib/utils/text_utility'; +import { humanize } from '../../lib/utils/text_utility'; import ActionsComponent from './environment_actions.vue'; import ExternalUrlComponent from './environment_external_url.vue'; import StopComponent from './environment_stop.vue'; @@ -139,7 +139,7 @@ export default { if (this.hasManualActions) { return this.model.last_deployment.manual_actions.map((action) => { const parsedAction = { - name: gl.text.humanize(action.name), + name: humanize(action.name), play_path: action.play_path, playable: action.playable, }; diff --git a/app/assets/javascripts/gl_dropdown.js b/app/assets/javascripts/gl_dropdown.js index c4202f92443..4e7a6e54f90 100644 --- a/app/assets/javascripts/gl_dropdown.js +++ b/app/assets/javascripts/gl_dropdown.js @@ -331,7 +331,7 @@ GitLabDropdown = (function() { if (_this.dropdown.find('.dropdown-toggle-page').length) { selector = ".dropdown-page-one " + selector; } - return $(selector); + return $(selector, this.instance.dropdown); }; })(this), data: (function(_this) { diff --git a/app/assets/javascripts/gl_form.js b/app/assets/javascripts/gl_form.js index 48cd43d3348..d0f9e6af0f8 100644 --- a/app/assets/javascripts/gl_form.js +++ b/app/assets/javascripts/gl_form.js @@ -2,6 +2,7 @@ import GfmAutoComplete from './gfm_auto_complete'; import dropzoneInput from './dropzone_input'; +import textUtils from './lib/utils/text_markdown'; export default class GLForm { constructor(form, enableGFM = false) { @@ -46,7 +47,7 @@ export default class GLForm { } // form and textarea event listeners this.addEventListeners(); - gl.text.init(this.form); + textUtils.init(this.form); // hide discard button this.form.find('.js-note-discard').hide(); this.form.show(); @@ -85,7 +86,7 @@ export default class GLForm { clearEventListeners() { this.textarea.off('focus'); this.textarea.off('blur'); - gl.text.removeListeners(this.form); + textUtils.removeListeners(this.form); } addEventListeners() { diff --git a/app/assets/javascripts/issue.js b/app/assets/javascripts/issue.js index acd5730cf3c..7de07e9403d 100644 --- a/app/assets/javascripts/issue.js +++ b/app/assets/javascripts/issue.js @@ -1,6 +1,6 @@ /* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, one-var, no-underscore-dangle, one-var-declaration-per-line, object-shorthand, no-unused-vars, no-new, comma-dangle, consistent-return, quotes, dot-notation, quote-props, prefer-arrow-callback, max-len */ import 'vendor/jquery.waitforimages'; -import '~/lib/utils/text_utility'; +import { addDelimiter } from './lib/utils/text_utility'; import Flash from './flash'; import TaskList from './task_list'; import CreateMergeRequestDropdown from './create_merge_request_dropdown'; @@ -73,7 +73,7 @@ export default class Issue { let numProjectIssues = Number(projectIssuesCounter.first().text().trim().replace(/[^\d]/, '')); numProjectIssues = isClosed ? numProjectIssues - 1 : numProjectIssues + 1; - projectIssuesCounter.text(gl.text.addDelimiter(numProjectIssues)); + projectIssuesCounter.text(addDelimiter(numProjectIssues)); if (this.createMergeRequestDropdown) { if (isClosed) { diff --git a/app/assets/javascripts/job.js b/app/assets/javascripts/job.js index c6b5844dff6..cf8fda9a4fa 100644 --- a/app/assets/javascripts/job.js +++ b/app/assets/javascripts/job.js @@ -14,8 +14,8 @@ export default class Job { this.state = this.options.logState; this.buildStage = this.options.buildStage; this.$document = $(document); + this.$window = $(window); this.logBytes = 0; - this.hasBeenScrolled = false; this.updateDropdown = this.updateDropdown.bind(this); this.$buildTrace = $('#build-trace'); @@ -54,23 +54,18 @@ export default class Job { this.scrollThrottled = _.throttle(this.toggleScroll.bind(this), 100); - $(window) + this.$window .off('scroll') .on('scroll', () => { - const contentHeight = this.$buildTraceOutput.height(); - if (contentHeight > this.windowSize) { - // means the user did not scroll, the content was updated. - this.windowSize = contentHeight; - } else { - // User scrolled - this.hasBeenScrolled = true; + if (!this.isScrolledToBottom()) { this.toggleScrollAnimation(false); + } else if (this.isScrolledToBottom() && !this.isLogComplete) { + this.toggleScrollAnimation(true); } - this.scrollThrottled(); }); - $(window) + this.$window .off('resize.build') .on('resize.build', _.throttle(this.sidebarOnResize.bind(this), 100)); @@ -99,14 +94,14 @@ export default class Job { // eslint-disable-next-line class-methods-use-this canScroll() { - return $(document).height() > $(window).height(); + return this.$document.height() > this.$window.height(); } toggleScroll() { - const currentPosition = $(document).scrollTop(); - const scrollHeight = $(document).height(); + const currentPosition = this.$document.scrollTop(); + const scrollHeight = this.$document.height(); - const windowHeight = $(window).height(); + const windowHeight = this.$window.height(); if (this.canScroll()) { if (currentPosition > 0 && (scrollHeight - currentPosition !== windowHeight)) { @@ -119,7 +114,7 @@ export default class Job { this.toggleDisableButton(this.$scrollTopBtn, true); this.toggleDisableButton(this.$scrollBottomBtn, false); - } else if (scrollHeight - currentPosition === windowHeight) { + } else if (this.isScrolledToBottom()) { // User is at the bottom of the build log. this.toggleDisableButton(this.$scrollTopBtn, false); @@ -131,9 +126,17 @@ export default class Job { } } + isScrolledToBottom() { + const currentPosition = this.$document.scrollTop(); + const scrollHeight = this.$document.height(); + + const windowHeight = this.$window.height(); + return scrollHeight - currentPosition === windowHeight; + } + // eslint-disable-next-line class-methods-use-this scrollDown() { - $(document).scrollTop($(document).height()); + this.$document.scrollTop(this.$document.height()); } scrollToBottom() { @@ -143,7 +146,7 @@ export default class Job { } scrollToTop() { - $(document).scrollTop(0); + this.$document.scrollTop(0); this.hasBeenScrolled = true; this.toggleScroll(); } @@ -174,7 +177,7 @@ export default class Job { this.state = log.state; } - this.windowSize = this.$buildTraceOutput.height(); + this.isScrollInBottom = this.isScrolledToBottom(); if (log.append) { this.$buildTraceOutput.append(log.html); @@ -194,14 +197,9 @@ export default class Job { } else { this.$truncatedInfo.addClass('hidden'); } + this.isLogComplete = log.complete; if (!log.complete) { - if (!this.hasBeenScrolled) { - this.toggleScrollAnimation(true); - } else { - this.toggleScrollAnimation(false); - } - this.timeout = setTimeout(() => { this.getBuildTrace(); }, 4000); @@ -218,7 +216,7 @@ export default class Job { this.$buildRefreshAnimation.remove(); }) .then(() => { - if (!this.hasBeenScrolled) { + if (this.isScrollInBottom) { this.scrollDown(); } }) diff --git a/app/assets/javascripts/lib/utils/common_utils.js b/app/assets/javascripts/lib/utils/common_utils.js index 07899777a1e..5c4926d6ac8 100644 --- a/app/assets/javascripts/lib/utils/common_utils.js +++ b/app/assets/javascripts/lib/utils/common_utils.js @@ -172,7 +172,6 @@ export const getSelectedFragment = () => { return documentFragment; }; -// TODO: Update this name, there is a gl.text.insertText function. export const insertText = (target, text) => { // Firefox doesn't support `document.execCommand('insertText', false, text)` on textareas const selectionStart = target.selectionStart; diff --git a/app/assets/javascripts/lib/utils/datetime_utility.js b/app/assets/javascripts/lib/utils/datetime_utility.js index 29fc91733b3..5679b8c9a09 100644 --- a/app/assets/javascripts/lib/utils/datetime_utility.js +++ b/app/assets/javascripts/lib/utils/datetime_utility.js @@ -2,6 +2,7 @@ import timeago from 'timeago.js'; import dateFormat from 'vendor/date.format'; +import { pluralize } from './text_utility'; import { lang, @@ -143,9 +144,9 @@ export function timeIntervalInWords(intervalInSeconds) { let text = ''; if (minutes >= 1) { - text = `${minutes} ${gl.text.pluralize('minute', minutes)} ${seconds} ${gl.text.pluralize('second', seconds)}`; + text = `${minutes} ${pluralize('minute', minutes)} ${seconds} ${pluralize('second', seconds)}`; } else { - text = `${seconds} ${gl.text.pluralize('second', seconds)}`; + text = `${seconds} ${pluralize('second', seconds)}`; } return text; } diff --git a/app/assets/javascripts/lib/utils/text_markdown.js b/app/assets/javascripts/lib/utils/text_markdown.js new file mode 100644 index 00000000000..2dc9cf0cc29 --- /dev/null +++ b/app/assets/javascripts/lib/utils/text_markdown.js @@ -0,0 +1,153 @@ +/* eslint-disable import/prefer-default-export, func-names, space-before-function-paren, wrap-iife, no-var, no-param-reassign, no-cond-assign, quotes, one-var, one-var-declaration-per-line, operator-assignment, no-else-return, prefer-template, prefer-arrow-callback, no-empty, max-len, consistent-return, no-unused-vars, no-return-assign, max-len, vars-on-top */ + +const textUtils = {}; + +textUtils.selectedText = function(text, textarea) { + return text.substring(textarea.selectionStart, textarea.selectionEnd); +}; + +textUtils.lineBefore = function(text, textarea) { + var split; + split = text.substring(0, textarea.selectionStart).trim().split('\n'); + return split[split.length - 1]; +}; + +textUtils.lineAfter = function(text, textarea) { + return text.substring(textarea.selectionEnd).trim().split('\n')[0]; +}; + +textUtils.blockTagText = function(text, textArea, blockTag, selected) { + var lineAfter, lineBefore; + lineBefore = this.lineBefore(text, textArea); + lineAfter = this.lineAfter(text, textArea); + if (lineBefore === blockTag && lineAfter === blockTag) { + // To remove the block tag we have to select the line before & after + if (blockTag != null) { + textArea.selectionStart = textArea.selectionStart - (blockTag.length + 1); + textArea.selectionEnd = textArea.selectionEnd + (blockTag.length + 1); + } + return selected; + } else { + return blockTag + "\n" + selected + "\n" + blockTag; + } +}; + +textUtils.insertText = function(textArea, text, tag, blockTag, selected, wrap) { + var insertText, inserted, selectedSplit, startChar, removedLastNewLine, removedFirstNewLine, currentLineEmpty, lastNewLine; + removedLastNewLine = false; + removedFirstNewLine = false; + currentLineEmpty = false; + + // Remove the first newline + if (selected.indexOf('\n') === 0) { + removedFirstNewLine = true; + selected = selected.replace(/\n+/, ''); + } + + // Remove the last newline + if (textArea.selectionEnd - textArea.selectionStart > selected.replace(/\n$/, '').length) { + removedLastNewLine = true; + selected = selected.replace(/\n$/, ''); + } + + selectedSplit = selected.split('\n'); + + if (!wrap) { + lastNewLine = textArea.value.substr(0, textArea.selectionStart).lastIndexOf('\n'); + + // Check whether the current line is empty or consists only of spaces(=handle as empty) + if (/^\s*$/.test(textArea.value.substring(lastNewLine, textArea.selectionStart))) { + currentLineEmpty = true; + } + } + + startChar = !wrap && !currentLineEmpty && textArea.selectionStart > 0 ? '\n' : ''; + + if (selectedSplit.length > 1 && (!wrap || (blockTag != null && blockTag !== ''))) { + if (blockTag != null && blockTag !== '') { + insertText = this.blockTagText(text, textArea, blockTag, selected); + } else { + insertText = selectedSplit.map(function(val) { + if (val.indexOf(tag) === 0) { + return "" + (val.replace(tag, '')); + } else { + return "" + tag + val; + } + }).join('\n'); + } + } else { + insertText = "" + startChar + tag + selected + (wrap ? tag : ' '); + } + + if (removedFirstNewLine) { + insertText = '\n' + insertText; + } + + if (removedLastNewLine) { + insertText += '\n'; + } + + if (document.queryCommandSupported('insertText')) { + inserted = document.execCommand('insertText', false, insertText); + } + if (!inserted) { + try { + document.execCommand("ms-beginUndoUnit"); + } catch (error) {} + textArea.value = this.replaceRange(text, textArea.selectionStart, textArea.selectionEnd, insertText); + try { + document.execCommand("ms-endUndoUnit"); + } catch (error) {} + } + return this.moveCursor(textArea, tag, wrap, removedLastNewLine); +}; + +textUtils.moveCursor = function(textArea, tag, wrapped, removedLastNewLine) { + var pos; + if (!textArea.setSelectionRange) { + return; + } + if (textArea.selectionStart === textArea.selectionEnd) { + if (wrapped) { + pos = textArea.selectionStart - tag.length; + } else { + pos = textArea.selectionStart; + } + + if (removedLastNewLine) { + pos -= 1; + } + + return textArea.setSelectionRange(pos, pos); + } +}; + +textUtils.updateText = function(textArea, tag, blockTag, wrap) { + var $textArea, selected, text; + $textArea = $(textArea); + textArea = $textArea.get(0); + text = $textArea.val(); + selected = this.selectedText(text, textArea); + $textArea.focus(); + return this.insertText(textArea, text, tag, blockTag, selected, wrap); +}; + +textUtils.init = function(form) { + var self; + self = this; + return $('.js-md', form).off('click').on('click', function() { + var $this; + $this = $(this); + return self.updateText($this.closest('.md-area').find('textarea'), $this.data('md-tag'), $this.data('md-block'), !$this.data('md-prepend')); + }); +}; + +textUtils.removeListeners = function(form) { + return $('.js-md', form).off('click'); +}; + +textUtils.replaceRange = function(s, start, end, substitute) { + return s.substring(0, start) + substitute + s.substring(end); +}; + +export default textUtils; diff --git a/app/assets/javascripts/lib/utils/text_utility.js b/app/assets/javascripts/lib/utils/text_utility.js index f776829f69c..28ab9dddc4c 100644 --- a/app/assets/javascripts/lib/utils/text_utility.js +++ b/app/assets/javascripts/lib/utils/text_utility.js @@ -1,18 +1,13 @@ -/* eslint-disable import/prefer-default-export, func-names, space-before-function-paren, wrap-iife, no-var, no-param-reassign, no-cond-assign, quotes, one-var, one-var-declaration-per-line, operator-assignment, no-else-return, prefer-template, prefer-arrow-callback, no-empty, max-len, consistent-return, no-unused-vars, no-return-assign, max-len, vars-on-top */ - -import 'vendor/latinise'; - -var base; -var w = window; -if (w.gl == null) { - w.gl = {}; -} -if ((base = w.gl).text == null) { - base.text = {}; -} -gl.text.addDelimiter = function(text) { - return text ? text.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") : text; -}; +/** + * Adds a , to a string composed by numbers, at every 3 chars. + * + * 2333 -> 2,333 + * 232324 -> 232,324 + * + * @param {String} text + * @returns {String} + */ +export const addDelimiter = text => (text ? text.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',') : text); /** * Returns '99+' for numbers bigger than 99. @@ -20,178 +15,43 @@ gl.text.addDelimiter = function(text) { * @param {Number} count * @return {Number|String} */ -export function highCountTrim(count) { - return count > 99 ? '99+' : count; -} - -gl.text.randomString = function() { - return Math.random().toString(36).substring(7); -}; -gl.text.replaceRange = function(s, start, end, substitute) { - return s.substring(0, start) + substitute + s.substring(end); -}; -gl.text.getTextWidth = function(text, font) { - /** - * Uses canvas.measureText to compute and return the width of the given text of given font in pixels. - * - * @param {String} text The text to be rendered. - * @param {String} font The css font descriptor that text is to be rendered with (e.g. "bold 14px verdana"). - * - * @see http://stackoverflow.com/questions/118241/calculate-text-width-with-javascript/21015393#21015393 - */ - // re-use canvas object for better performance - var canvas = gl.text.getTextWidth.canvas || (gl.text.getTextWidth.canvas = document.createElement('canvas')); - var context = canvas.getContext('2d'); - context.font = font; - return context.measureText(text).width; -}; -gl.text.selectedText = function(text, textarea) { - return text.substring(textarea.selectionStart, textarea.selectionEnd); -}; -gl.text.lineBefore = function(text, textarea) { - var split; - split = text.substring(0, textarea.selectionStart).trim().split('\n'); - return split[split.length - 1]; -}; -gl.text.lineAfter = function(text, textarea) { - return text.substring(textarea.selectionEnd).trim().split('\n')[0]; -}; -gl.text.blockTagText = function(text, textArea, blockTag, selected) { - var lineAfter, lineBefore; - lineBefore = this.lineBefore(text, textArea); - lineAfter = this.lineAfter(text, textArea); - if (lineBefore === blockTag && lineAfter === blockTag) { - // To remove the block tag we have to select the line before & after - if (blockTag != null) { - textArea.selectionStart = textArea.selectionStart - (blockTag.length + 1); - textArea.selectionEnd = textArea.selectionEnd + (blockTag.length + 1); - } - return selected; - } else { - return blockTag + "\n" + selected + "\n" + blockTag; - } -}; -gl.text.insertText = function(textArea, text, tag, blockTag, selected, wrap) { - var insertText, inserted, selectedSplit, startChar, removedLastNewLine, removedFirstNewLine, currentLineEmpty, lastNewLine; - removedLastNewLine = false; - removedFirstNewLine = false; - currentLineEmpty = false; - - // Remove the first newline - if (selected.indexOf('\n') === 0) { - removedFirstNewLine = true; - selected = selected.replace(/\n+/, ''); - } - - // Remove the last newline - if (textArea.selectionEnd - textArea.selectionStart > selected.replace(/\n$/, '').length) { - removedLastNewLine = true; - selected = selected.replace(/\n$/, ''); - } - - selectedSplit = selected.split('\n'); - - if (!wrap) { - lastNewLine = textArea.value.substr(0, textArea.selectionStart).lastIndexOf('\n'); - - // Check whether the current line is empty or consists only of spaces(=handle as empty) - if (/^\s*$/.test(textArea.value.substring(lastNewLine, textArea.selectionStart))) { - currentLineEmpty = true; - } - } - - startChar = !wrap && !currentLineEmpty && textArea.selectionStart > 0 ? '\n' : ''; +export const highCountTrim = count => (count > 99 ? '99+' : count); - if (selectedSplit.length > 1 && (!wrap || (blockTag != null && blockTag !== ''))) { - if (blockTag != null && blockTag !== '') { - insertText = this.blockTagText(text, textArea, blockTag, selected); - } else { - insertText = selectedSplit.map(function(val) { - if (val.indexOf(tag) === 0) { - return "" + (val.replace(tag, '')); - } else { - return "" + tag + val; - } - }).join('\n'); - } - } else { - insertText = "" + startChar + tag + selected + (wrap ? tag : ' '); - } +/** + * Converst first char to uppercase and replaces undercores with spaces + * @param {String} string + * @requires {String} + */ +export const humanize = string => string.charAt(0).toUpperCase() + string.replace(/_/g, ' ').slice(1); - if (removedFirstNewLine) { - insertText = '\n' + insertText; - } +/** + * Adds an 's' to the end of the string when count is bigger than 0 + * @param {String} str + * @param {Number} count + * @returns {String} + */ +export const pluralize = (str, count) => str + (count > 1 || count === 0 ? 's' : ''); - if (removedLastNewLine) { - insertText += '\n'; - } +/** + * Replaces underscores with dashes + * @param {*} str + * @returns {String} + */ +export const dasherize = str => str.replace(/[_\s]+/g, '-'); - if (document.queryCommandSupported('insertText')) { - inserted = document.execCommand('insertText', false, insertText); - } - if (!inserted) { - try { - document.execCommand("ms-beginUndoUnit"); - } catch (error) {} - textArea.value = this.replaceRange(text, textArea.selectionStart, textArea.selectionEnd, insertText); - try { - document.execCommand("ms-endUndoUnit"); - } catch (error) {} - } - return this.moveCursor(textArea, tag, wrap, removedLastNewLine); -}; -gl.text.moveCursor = function(textArea, tag, wrapped, removedLastNewLine) { - var pos; - if (!textArea.setSelectionRange) { - return; - } - if (textArea.selectionStart === textArea.selectionEnd) { - if (wrapped) { - pos = textArea.selectionStart - tag.length; - } else { - pos = textArea.selectionStart; - } +/** + * Removes accents and converts to lower case + * @param {String} str + * @returns {String} + */ +export const slugify = str => str.trim().toLowerCase(); - if (removedLastNewLine) { - pos -= 1; - } +/** + * Truncates given text + * + * @param {String} string + * @param {Number} maxLength + * @returns {String} + */ +export const truncate = (string, maxLength) => `${string.substr(0, (maxLength - 3))}...`; - return textArea.setSelectionRange(pos, pos); - } -}; -gl.text.updateText = function(textArea, tag, blockTag, wrap) { - var $textArea, selected, text; - $textArea = $(textArea); - textArea = $textArea.get(0); - text = $textArea.val(); - selected = this.selectedText(text, textArea); - $textArea.focus(); - return this.insertText(textArea, text, tag, blockTag, selected, wrap); -}; -gl.text.init = function(form) { - var self; - self = this; - return $('.js-md', form).off('click').on('click', function() { - var $this; - $this = $(this); - return self.updateText($this.closest('.md-area').find('textarea'), $this.data('md-tag'), $this.data('md-block'), !$this.data('md-prepend')); - }); -}; -gl.text.removeListeners = function(form) { - return $('.js-md', form).off('click'); -}; -gl.text.humanize = function(string) { - return string.charAt(0).toUpperCase() + string.replace(/_/g, ' ').slice(1); -}; -gl.text.pluralize = function(str, count) { - return str + (count > 1 || count === 0 ? 's' : ''); -}; -gl.text.truncate = function(string, maxLength) { - return string.substr(0, (maxLength - 3)) + '...'; -}; -gl.text.dasherize = function(str) { - return str.replace(/[_\s]+/g, '-'); -}; -gl.text.slugify = function(str) { - return str.trim().toLowerCase().latinise(); -}; diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js index 31c5cfc5e55..127fddcf8d3 100644 --- a/app/assets/javascripts/main.js +++ b/app/assets/javascripts/main.js @@ -30,7 +30,6 @@ import './commit/image_file'; import { handleLocationHash } from './lib/utils/common_utils'; import './lib/utils/datetime_utility'; import './lib/utils/pretty_time'; -import './lib/utils/text_utility'; import './lib/utils/url_utility'; // behaviors diff --git a/app/assets/javascripts/merge_request.js b/app/assets/javascripts/merge_request.js index af0658eb668..d30ff12bb59 100644 --- a/app/assets/javascripts/merge_request.js +++ b/app/assets/javascripts/merge_request.js @@ -5,6 +5,7 @@ import 'vendor/jquery.waitforimages'; import TaskList from './task_list'; import './merge_request_tabs'; import IssuablesHelper from './helpers/issuables_helper'; +import { addDelimiter } from './lib/utils/text_utility'; (function() { this.MergeRequest = (function() { @@ -124,7 +125,7 @@ import IssuablesHelper from './helpers/issuables_helper'; const $el = $('.nav-links .js-merge-counter'); const count = Math.max((parseInt($el.text().replace(/[^\d]/, ''), 10) - by), 0); - $el.text(gl.text.addDelimiter(count)); + $el.text(addDelimiter(count)); }; MergeRequest.prototype.hideCloseButton = function() { diff --git a/app/assets/javascripts/notes/components/issue_comment_form.vue b/app/assets/javascripts/notes/components/issue_comment_form.vue index db8f85759b2..30e02554b65 100644 --- a/app/assets/javascripts/notes/components/issue_comment_form.vue +++ b/app/assets/javascripts/notes/components/issue_comment_form.vue @@ -357,7 +357,8 @@ @click="handleSave(true)" v-if="canUpdateIssue" :class="actionButtonClassNames" - class="btn btn-comment btn-comment-and-close"> + :disabled="isSubmitting" + class="btn btn-comment btn-comment-and-close js-action-button"> {{issueActionButtonTitle}} </button> <button diff --git a/app/assets/javascripts/pipelines/components/graph/action_component.vue b/app/assets/javascripts/pipelines/components/graph/action_component.vue index 547140b1a43..19d8e1f49cf 100644 --- a/app/assets/javascripts/pipelines/components/graph/action_component.vue +++ b/app/assets/javascripts/pipelines/components/graph/action_component.vue @@ -1,7 +1,7 @@ <script> import tooltip from '../../../vue_shared/directives/tooltip'; import icon from '../../../vue_shared/components/icon.vue'; - + import { dasherize } from '../../../lib/utils/text_utility'; /** * Renders either a cancel, retry or play icon pointing to the given path. * TODO: Remove UJS from here and use an async request instead. @@ -39,7 +39,7 @@ computed: { cssClass() { - const actionIconDash = gl.text.dasherize(this.actionIcon); + const actionIconDash = dasherize(this.actionIcon); return `${actionIconDash} js-icon-${actionIconDash}`; }, }, diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.js b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.js index 219ff94924e..13e4cb5717e 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.js +++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.js @@ -1,5 +1,5 @@ import tooltip from '../../vue_shared/directives/tooltip'; -import '../../lib/utils/text_utility'; +import { pluralize } from '../../lib/utils/text_utility'; export default { name: 'MRWidgetHeader', @@ -14,7 +14,7 @@ export default { return this.mr.divergedCommitsCount > 0; }, commitsText() { - return gl.text.pluralize('commit', this.mr.divergedCommitsCount); + return pluralize('commit', this.mr.divergedCommitsCount); }, branchNameClipboardData() { // This supports code in app/assets/javascripts/copy_to_clipboard.js that diff --git a/app/assets/javascripts/wikis.js b/app/assets/javascripts/wikis.js index a0025ddb598..7a865587444 100644 --- a/app/assets/javascripts/wikis.js +++ b/app/assets/javascripts/wikis.js @@ -1,4 +1,5 @@ import bp from './breakpoints'; +import { slugify } from './lib/utils/text_utility'; export default class Wikis { constructor() { @@ -23,7 +24,7 @@ export default class Wikis { if (!this.newWikiForm) return; const slugInput = this.newWikiForm.querySelector('#new_wiki_path'); - const slug = gl.text.slugify(slugInput.value); + const slug = slugify(slugInput.value); if (slug.length > 0) { const wikisPath = slugInput.getAttribute('data-wikis-path'); diff --git a/app/assets/stylesheets/framework/header.scss b/app/assets/stylesheets/framework/header.scss index 1cdfa904374..f0139b5f33a 100644 --- a/app/assets/stylesheets/framework/header.scss +++ b/app/assets/stylesheets/framework/header.scss @@ -401,10 +401,13 @@ .breadcrumbs-list { display: -webkit-flex; display: flex; - flex-wrap: wrap; margin-bottom: 0; line-height: 16px; + @media (max-width: $screen-xs-max) { + flex-wrap: wrap; + } + > li { display: flex; align-items: center; @@ -412,24 +415,35 @@ padding: 2px 0; &:not(:last-child) { - margin-right: 20px; + padding-right: 20px; + + &:not(.dropdown) { + overflow: hidden; + } } > a { font-size: 12px; color: currentColor; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + flex: 0 1 auto; } } } .breadcrumb-item-text { - @include str-truncated(128px); text-decoration: inherit; + + @media (max-width: $screen-xs-max) { + @include str-truncated(128px); + } } .breadcrumbs-list-angle { position: absolute; - right: -12px; + right: 7px; top: 50%; color: $gl-text-color-tertiary; transform: translateY(-50%); diff --git a/app/assets/stylesheets/pages/settings.scss b/app/assets/stylesheets/pages/settings.scss index 8b9b47a41bc..5d630c7d61e 100644 --- a/app/assets/stylesheets/pages/settings.scss +++ b/app/assets/stylesheets/pages/settings.scss @@ -249,3 +249,22 @@ } } } + +.modal-doorkeepr-auth, +.doorkeeper-app-form { + .scope-description { + color: $theme-gray-700; + } +} + +.modal-doorkeepr-auth { + .modal-body { + padding: $gl-padding; + } +} + +.doorkeeper-app-form { + .scope-description { + margin: 0 0 5px 17px; + } +} diff --git a/app/controllers/dashboard/todos_controller.rb b/app/controllers/dashboard/todos_controller.rb index 02c5857eea7..e89eaf7edda 100644 --- a/app/controllers/dashboard/todos_controller.rb +++ b/app/controllers/dashboard/todos_controller.rb @@ -76,7 +76,7 @@ class Dashboard::TodosController < Dashboard::ApplicationController def redirect_out_of_range(todos) total_pages = if todo_params.except(:sort, :page).empty? - (current_user.todos_pending_count / todos.limit_value).ceil + (current_user.todos_pending_count.to_f / todos.limit_value).ceil else todos.total_pages end diff --git a/app/helpers/icons_helper.rb b/app/helpers/icons_helper.rb index ec779c1c447..c6a83f21ceb 100644 --- a/app/helpers/icons_helper.rb +++ b/app/helpers/icons_helper.rb @@ -23,10 +23,17 @@ module IconsHelper render "shared/icons/#{icon_name}.svg", size: size end + def sprite_icon_path + # SVG Sprites currently don't work across domains, so in the case of a CDN + # we have to set the current path deliberately to prevent addition of asset_host + sprite_base_url = Gitlab.config.gitlab.url if ActionController::Base.asset_host + ActionController::Base.helpers.image_path('icons.svg', host: sprite_base_url) + end + def sprite_icon(icon_name, size: nil, css_class: nil) css_classes = size ? "s#{size}" : "" css_classes << " #{css_class}" unless css_class.blank? - content_tag(:svg, content_tag(:use, "", { "xlink:href" => "#{image_path('icons.svg')}##{icon_name}" } ), class: css_classes.empty? ? nil : css_classes) + content_tag(:svg, content_tag(:use, "", { "xlink:href" => "#{sprite_icon_path}##{icon_name}" } ), class: css_classes.empty? ? nil : css_classes) end def audit_icon(names, options = {}) diff --git a/app/models/concerns/avatarable.rb b/app/models/concerns/avatarable.rb index 2ec70203710..10659030910 100644 --- a/app/models/concerns/avatarable.rb +++ b/app/models/concerns/avatarable.rb @@ -4,15 +4,26 @@ module Avatarable def avatar_path(only_path: true) return unless self[:avatar].present? - # If only_path is true then use the relative path of avatar. - # Otherwise use full path (including host). asset_host = ActionController::Base.asset_host - gitlab_host = only_path ? gitlab_config.relative_url_root : gitlab_config.url + use_asset_host = asset_host.present? - # If asset_host is set then it is expected that assets are handled by a standalone host. - # That means we do not want to get GitLab's relative_url_root option anymore. - host = (asset_host.present? && (!respond_to?(:public?) || public?)) ? asset_host : gitlab_host + # Avatars for private and internal groups and projects require authentication to be viewed, + # which means they can only be served by Rails, on the regular GitLab host. + # If an asset host is configured, we need to return the fully qualified URL + # instead of only the avatar path, so that Rails doesn't prefix it with the asset host. + if use_asset_host && respond_to?(:public?) && !public? + use_asset_host = false + only_path = false + end - [host, avatar.url].join + url_base = "" + if use_asset_host + url_base << asset_host unless only_path + else + url_base << gitlab_config.base_url unless only_path + url_base << gitlab_config.relative_url_root + end + + url_base + avatar.url end end diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index efd8cca2947..dd4e67bc9da 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -865,7 +865,19 @@ class MergeRequest < ActiveRecord::Base # def all_commit_shas if persisted? - column_shas = MergeRequestDiffCommit.where(merge_request_diff: merge_request_diffs).limit(10_000).pluck('sha') + # MySQL doesn't support LIMIT in a subquery. + diffs_relation = + if Gitlab::Database.postgresql? + merge_request_diffs.order(id: :desc).limit(100) + else + merge_request_diffs + end + + column_shas = MergeRequestDiffCommit + .where(merge_request_diff: diffs_relation) + .limit(10_000) + .pluck('sha') + serialised_shas = merge_request_diffs.where.not(st_commits: nil).flat_map(&:commit_shas) (column_shas + serialised_shas).uniq diff --git a/app/models/repository.rb b/app/models/repository.rb index 6bdee538172..3a89fa9264b 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -1062,6 +1062,10 @@ class Repository blob_data_at(sha, path) end + def fetch_ref(source_repository, source_ref:, target_ref:) + raw_repository.fetch_ref(source_repository.raw_repository, source_ref: source_ref, target_ref: target_ref) + end + private # TODO Generice finder, later split this on finders by Ref or Oid diff --git a/app/serializers/issue_entity.rb b/app/serializers/issue_entity.rb index 5f47592e4ad..9d52b8d9752 100644 --- a/app/serializers/issue_entity.rb +++ b/app/serializers/issue_entity.rb @@ -3,7 +3,6 @@ class IssueEntity < IssuableEntity expose :state expose :deleted_at - expose :branch_name expose :confidential expose :discussion_locked expose :assignees, using: API::Entities::UserBasic diff --git a/app/services/merge_requests/merge_service.rb b/app/services/merge_requests/merge_service.rb index 156e7b2f078..1da4dbd9e96 100644 --- a/app/services/merge_requests/merge_service.rb +++ b/app/services/merge_requests/merge_service.rb @@ -18,15 +18,7 @@ module MergeRequests @merge_request = merge_request - unless @merge_request.mergeable? - return handle_merge_error(log_message: 'Merge request is not mergeable', save_message_on_model: true) - end - - @source = find_merge_source - - unless @source - return handle_merge_error(log_message: 'No source for merge', save_message_on_model: true) - end + error_check! merge_request.in_locked_state do if commit @@ -41,6 +33,19 @@ module MergeRequests private + def error_check! + error = + if @merge_request.should_be_rebased? + 'Only fast-forward merge is allowed for your project. Please update your source branch' + elsif !@merge_request.mergeable? + 'Merge request is not mergeable' + elsif !source + 'No source for merge' + end + + raise MergeError, error if error + end + def commit message = params[:commit_message] || merge_request.merge_commit_message @@ -91,8 +96,8 @@ module MergeRequests merge_request.to_reference(full: true) end - def find_merge_source - merge_request.diff_head_sha + def source + @source ||= @merge_request.diff_head_sha end end end diff --git a/app/views/doorkeeper/applications/_form.html.haml b/app/views/doorkeeper/applications/_form.html.haml index b3313c7c985..cf0e0de1ca4 100644 --- a/app/views/doorkeeper/applications/_form.html.haml +++ b/app/views/doorkeeper/applications/_form.html.haml @@ -1,4 +1,4 @@ -= form_for application, url: doorkeeper_submit_path(application), html: {role: 'form'} do |f| += form_for application, url: doorkeeper_submit_path(application), html: { role: 'form', class: 'doorkeeper-app-form' } do |f| = form_errors(application) .form-group diff --git a/app/views/doorkeeper/authorizations/new.html.haml b/app/views/doorkeeper/authorizations/new.html.haml index 8ba88906714..85e4170aee9 100644 --- a/app/views/doorkeeper/authorizations/new.html.haml +++ b/app/views/doorkeeper/authorizations/new.html.haml @@ -1,5 +1,7 @@ +- auth_app_owner = @pre_auth.client.application.owner + %main{ :role => "main" } - .modal-no-backdrop + .modal-no-backdrop.modal-doorkeepr-auth .modal-content .modal-header %h3.page-title @@ -16,14 +18,21 @@ %strong= @pre_auth.client.name will allow them to interact with GitLab as an admin as well. Proceed with caution. %p - You are about to authorize + An application called = link_to @pre_auth.client.name, @pre_auth.redirect_uri, target: '_blank', rel: 'noopener noreferrer' - to use your account. - - if @pre_auth.scopes + is requesting access to your GitLab account. This application was created by + = succeed "." do + = link_to auth_app_owner.name, user_path(auth_app_owner) + Please note that this application is not provided by GitLab and you should verify its authenticity before + allowing access. + - if @pre_auth.scopes + %p This application will be able to: %ul - @pre_auth.scopes.each do |scope| - %li= t scope, scope: [:doorkeeper, :scopes] + %li + %strong= t scope, scope: [:doorkeeper, :scopes] + .scope-description= t scope, scope: [:doorkeeper, :scope_desc] .form-actions.text-right = form_tag oauth_authorization_path, method: :delete, class: 'inline' do = hidden_field_tag :client_id, @pre_auth.client.uid diff --git a/app/views/shared/tokens/_scopes_form.html.haml b/app/views/shared/tokens/_scopes_form.html.haml index 8bbaf431536..ae437dd16d6 100644 --- a/app/views/shared/tokens/_scopes_form.html.haml +++ b/app/views/shared/tokens/_scopes_form.html.haml @@ -7,3 +7,4 @@ = check_box_tag "#{prefix}[scopes][]", scope, token.scopes.include?(scope), id: "#{prefix}_scopes_#{scope}" = label_tag ("#{prefix}_scopes_#{scope}"), scope %span= t(scope, scope: [:doorkeeper, :scopes]) + .scope-description= t scope, scope: [:doorkeeper, :scope_desc] diff --git a/app/workers/update_merge_requests_worker.rb b/app/workers/update_merge_requests_worker.rb index 150788ca611..89ae17cef37 100644 --- a/app/workers/update_merge_requests_worker.rb +++ b/app/workers/update_merge_requests_worker.rb @@ -2,10 +2,6 @@ class UpdateMergeRequestsWorker include Sidekiq::Worker include DedicatedSidekiqQueue - def metrics_tags - @metrics_tags || {} - end - def perform(project_id, user_id, oldrev, newrev, ref) project = Project.find_by(id: project_id) return unless project @@ -13,11 +9,6 @@ class UpdateMergeRequestsWorker user = User.find_by(id: user_id) return unless user - @metrics_tags = { - project_id: project_id, - user_id: user_id - } - MergeRequests::RefreshService.new(project, user).execute(oldrev, newrev, ref) end end diff --git a/changelogs/unreleased/.yml b/changelogs/unreleased/.yml new file mode 100644 index 00000000000..acf0bb80c72 --- /dev/null +++ b/changelogs/unreleased/.yml @@ -0,0 +1,5 @@ +--- +title: Remove update merge request worker tagging. +merge_request: +author: +type: removed diff --git a/changelogs/unreleased/38385-gpg-tooltips-not-working-in-safari.yml b/changelogs/unreleased/38385-gpg-tooltips-not-working-in-safari.yml deleted file mode 100644 index c7e840f0723..00000000000 --- a/changelogs/unreleased/38385-gpg-tooltips-not-working-in-safari.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix GPG signature popup info in Safari and Firefox -merge_request: 15228 -author: -type: fixed diff --git a/changelogs/unreleased/39109-reenable-scroll-job.yml b/changelogs/unreleased/39109-reenable-scroll-job.yml new file mode 100644 index 00000000000..a771f8f8941 --- /dev/null +++ b/changelogs/unreleased/39109-reenable-scroll-job.yml @@ -0,0 +1,5 @@ +--- +title: Enables scroll to bottom once user has scrolled back to bottom in job log +merge_request: +author: +type: fixed diff --git a/changelogs/unreleased/39704_fix_webhooks_log_time.yml b/changelogs/unreleased/39704_fix_webhooks_log_time.yml deleted file mode 100644 index 1234663e66b..00000000000 --- a/changelogs/unreleased/39704_fix_webhooks_log_time.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix webhooks recent deliveries -merge_request: 15146 -author: Alexander Randa (@randaalex) -type: fixed diff --git a/changelogs/unreleased/39895-cant-set-mattermost-username-channel-from-api.yml b/changelogs/unreleased/39895-cant-set-mattermost-username-channel-from-api.yml new file mode 100644 index 00000000000..358c007387e --- /dev/null +++ b/changelogs/unreleased/39895-cant-set-mattermost-username-channel-from-api.yml @@ -0,0 +1,5 @@ +--- +title: Fix acceptance of username for Mattermost service update +merge_request: 15275 +author: +type: fixed diff --git a/changelogs/unreleased/add-typescript.yml b/changelogs/unreleased/add-typescript.yml deleted file mode 100644 index a048f240855..00000000000 --- a/changelogs/unreleased/add-typescript.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Adds typescript support -merge_request: -author: -type: added diff --git a/changelogs/unreleased/bvl-unlink-fixes.yml b/changelogs/unreleased/bvl-unlink-fixes.yml deleted file mode 100644 index 685d78f479d..00000000000 --- a/changelogs/unreleased/bvl-unlink-fixes.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix issues with forked projects of which the source was deleted -merge_request: 15150 -author: -type: fixed diff --git a/changelogs/unreleased/cleanup-issues-schema.yml b/changelogs/unreleased/cleanup-issues-schema.yml new file mode 100644 index 00000000000..9f5fb0bdf82 --- /dev/null +++ b/changelogs/unreleased/cleanup-issues-schema.yml @@ -0,0 +1,5 @@ +--- +title: Clean up schema of the "issues" table +merge_request: +author: +type: other diff --git a/changelogs/unreleased/dm-avatarable-with-asset-host.yml b/changelogs/unreleased/dm-avatarable-with-asset-host.yml new file mode 100644 index 00000000000..6cf8d719afb --- /dev/null +++ b/changelogs/unreleased/dm-avatarable-with-asset-host.yml @@ -0,0 +1,6 @@ +--- +title: Always return full avatar URL for private/internal groups/projects when asset + host is set +merge_request: +author: +type: fixed diff --git a/changelogs/unreleased/dm-block-group-and-project-creation-when-external-by-default.yml b/changelogs/unreleased/dm-block-group-and-project-creation-when-external-by-default.yml deleted file mode 100644 index 42bcf9b1edd..00000000000 --- a/changelogs/unreleased/dm-block-group-and-project-creation-when-external-by-default.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Make sure group and project creation is blocked for new users that are external - by default -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/fix-502-mrs-with-lots-of-versions.yml b/changelogs/unreleased/fix-502-mrs-with-lots-of-versions.yml new file mode 100644 index 00000000000..32cdfba4eec --- /dev/null +++ b/changelogs/unreleased/fix-502-mrs-with-lots-of-versions.yml @@ -0,0 +1,6 @@ +--- +title: Ensure merge requests with lots of version don't time out when searching for + pipelines +merge_request: +author: +type: performance diff --git a/changelogs/unreleased/fix-import-export-arguments.yml b/changelogs/unreleased/fix-import-export-arguments.yml deleted file mode 100644 index eee87e313ea..00000000000 --- a/changelogs/unreleased/fix-import-export-arguments.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix arguments Import/Export error importing project merge requests -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/fix-mysql-grant-check.yml b/changelogs/unreleased/fix-mysql-grant-check.yml deleted file mode 100644 index a1c1aa67d79..00000000000 --- a/changelogs/unreleased/fix-mysql-grant-check.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix TRIGGER checks for MySQL -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/fix-todos-last-page.yml b/changelogs/unreleased/fix-todos-last-page.yml new file mode 100644 index 00000000000..efcdbb75e6e --- /dev/null +++ b/changelogs/unreleased/fix-todos-last-page.yml @@ -0,0 +1,5 @@ +--- +title: Fix access to the final page of todos +merge_request: +author: +type: fixed diff --git a/changelogs/unreleased/fix_diff_parsing.yml b/changelogs/unreleased/fix_diff_parsing.yml deleted file mode 100644 index 7a26b4f9ff5..00000000000 --- a/changelogs/unreleased/fix_diff_parsing.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix diff parser so it tolerates to diff special markers in the content -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/fix_migration_that_adds_ff_merge_field.yml b/changelogs/unreleased/fix_migration_that_adds_ff_merge_field.yml deleted file mode 100644 index a1685497331..00000000000 --- a/changelogs/unreleased/fix_migration_that_adds_ff_merge_field.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix a migration that adds merge_requests_ff_only_enabled column to MR table -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/issue_39176.yml b/changelogs/unreleased/issue_39176.yml deleted file mode 100644 index 6255b51c094..00000000000 --- a/changelogs/unreleased/issue_39176.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Render 404 when polling commit notes without having permissions -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/jivl-fix-cancel-button-file-upload-new-issue.yml b/changelogs/unreleased/jivl-fix-cancel-button-file-upload-new-issue.yml deleted file mode 100644 index 0205d9626b1..00000000000 --- a/changelogs/unreleased/jivl-fix-cancel-button-file-upload-new-issue.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix cancel button not working while uploading on the new issue page -merge_request: 15137 -author: -type: fixed diff --git a/changelogs/unreleased/pawel-disable_nfs_metrics_checks_39730.yml b/changelogs/unreleased/pawel-disable_nfs_metrics_checks_39730.yml deleted file mode 100644 index 556d7d069d3..00000000000 --- a/changelogs/unreleased/pawel-disable_nfs_metrics_checks_39730.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Remove Filesystem check metrics that use too much CPU to handle requests -merge_request: -author: -type: performance diff --git a/changelogs/unreleased/sh-fix-environment-slug-generation.yml b/changelogs/unreleased/sh-fix-environment-slug-generation.yml deleted file mode 100644 index 8a9c670c52c..00000000000 --- a/changelogs/unreleased/sh-fix-environment-slug-generation.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Avoid regenerating the ref path for the environment -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/text-utils.yml b/changelogs/unreleased/text-utils.yml new file mode 100644 index 00000000000..b95bb82fe01 --- /dev/null +++ b/changelogs/unreleased/text-utils.yml @@ -0,0 +1,5 @@ +--- +title: Export text utils functions as es6 module and add tests +merge_request: +author: +type: other diff --git a/changelogs/unreleased/winh-subgroups-api.yml b/changelogs/unreleased/winh-subgroups-api.yml new file mode 100644 index 00000000000..c49e3621e9c --- /dev/null +++ b/changelogs/unreleased/winh-subgroups-api.yml @@ -0,0 +1,5 @@ +--- +title: Add /groups/:id/subgroups endpoint to API +merge_request: 15142 +author: marbemac +type: added diff --git a/config/locales/doorkeeper.en.yml b/config/locales/doorkeeper.en.yml index 0da6b14c29e..b1c71095d4f 100644 --- a/config/locales/doorkeeper.en.yml +++ b/config/locales/doorkeeper.en.yml @@ -62,7 +62,15 @@ en: read_user: Read the authenticated user's personal information openid: Authenticate using OpenID Connect sudo: Perform API actions as any user in the system (if the authenticated user is an admin) - + scope_desc: + api: + Full access to GitLab as the user, including read/write on all their groups and projects + read_user: + Read-only access to the user's profile information, like username, public email and full name + openid: + The ability to authenticate using GitLab, and read-only access to the user's profile information + sudo: + Access to the Sudo feature, to perform API actions as any user in the system (only available for admins) flash: applications: create: diff --git a/config/webpack.config.js b/config/webpack.config.js index 67d7cae3ccf..f7a7182a627 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -108,10 +108,6 @@ var config = { loader: 'vue-loader', }, { - test: /\.ts$/, - loader: 'ts-loader', - }, - { test: /\.svg$/, loader: 'raw-loader', }, @@ -256,7 +252,7 @@ var config = { ], resolve: { - extensions: ['.js', '.ts'], + extensions: ['.js'], alias: { '~': path.join(ROOT_PATH, 'app/assets/javascripts'), 'emojis': path.join(ROOT_PATH, 'fixtures/emojis'), diff --git a/db/migrate/20171106132212_issues_confidential_not_null.rb b/db/migrate/20171106132212_issues_confidential_not_null.rb new file mode 100644 index 00000000000..c959d2dd938 --- /dev/null +++ b/db/migrate/20171106132212_issues_confidential_not_null.rb @@ -0,0 +1,23 @@ +# See http://doc.gitlab.com/ce/development/migration_style_guide.html +# for more information on how to write migrations for GitLab. + +class IssuesConfidentialNotNull < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + # Set this constant to true if this migration requires downtime. + DOWNTIME = false + + class Issue < ActiveRecord::Base + self.table_name = 'issues' + end + + def up + Issue.where('confidential IS NULL').update_all(confidential: false) + + change_column_null :issues, :confidential, false + end + + def down + # There's no way / point to revert this. + end +end diff --git a/db/migrate/20171106135924_issues_milestone_id_foreign_key.rb b/db/migrate/20171106135924_issues_milestone_id_foreign_key.rb new file mode 100644 index 00000000000..e6a780d0964 --- /dev/null +++ b/db/migrate/20171106135924_issues_milestone_id_foreign_key.rb @@ -0,0 +1,38 @@ +# See http://doc.gitlab.com/ce/development/migration_style_guide.html +# for more information on how to write migrations for GitLab. + +class IssuesMilestoneIdForeignKey < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + # Set this constant to true if this migration requires downtime. + DOWNTIME = false + + disable_ddl_transaction! + + class Issue < ActiveRecord::Base + include EachBatch + + self.table_name = 'issues' + + def self.with_orphaned_milestones + where('NOT EXISTS (SELECT true FROM milestones WHERE milestones.id = issues.milestone_id)') + end + end + + def up + Issue.with_orphaned_milestones.each_batch(of: 100) do |batch| + batch.update_all(milestone_id: nil) + end + + add_concurrent_foreign_key( + :issues, + :milestones, + column: :milestone_id, + on_delete: :nullify + ) + end + + def down + remove_foreign_key_without_error(:issues, column: :milestone_id) + end +end diff --git a/db/migrate/20171106150657_issues_updated_by_id_foreign_key.rb b/db/migrate/20171106150657_issues_updated_by_id_foreign_key.rb new file mode 100644 index 00000000000..3b8844d7d9f --- /dev/null +++ b/db/migrate/20171106150657_issues_updated_by_id_foreign_key.rb @@ -0,0 +1,45 @@ +# See http://doc.gitlab.com/ce/development/migration_style_guide.html +# for more information on how to write migrations for GitLab. + +class IssuesUpdatedByIdForeignKey < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + # Set this constant to true if this migration requires downtime. + DOWNTIME = false + + disable_ddl_transaction! + + class Issue < ActiveRecord::Base + include EachBatch + + self.table_name = 'issues' + + def self.with_orphaned_updaters + where('NOT EXISTS (SELECT true FROM users WHERE users.id = issues.updated_by_id)') + .where('updated_by_id IS NOT NULL') + end + end + + def up + Issue.with_orphaned_updaters.each_batch(of: 100) do |batch| + batch.update_all(updated_by_id: nil) + end + + # This index is only used for foreign keys, and those in turn will always + # specify a value. As such we can add a WHERE condition to make the index + # smaller. + add_concurrent_index(:issues, :updated_by_id, where: 'updated_by_id IS NOT NULL') + + add_concurrent_foreign_key( + :issues, + :users, + column: :updated_by_id, + on_delete: :nullify + ) + end + + def down + remove_foreign_key_without_error(:issues, column: :updated_by_id) + remove_concurrent_index(:issues, :updated_by_id) + end +end diff --git a/db/migrate/20171106151218_issues_moved_to_id_foreign_key.rb b/db/migrate/20171106151218_issues_moved_to_id_foreign_key.rb new file mode 100644 index 00000000000..8d2ceb8cc18 --- /dev/null +++ b/db/migrate/20171106151218_issues_moved_to_id_foreign_key.rb @@ -0,0 +1,44 @@ +# See http://doc.gitlab.com/ce/development/migration_style_guide.html +# for more information on how to write migrations for GitLab. + +class IssuesMovedToIdForeignKey < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + # Set this constant to true if this migration requires downtime. + DOWNTIME = false + + disable_ddl_transaction! + + class Issue < ActiveRecord::Base + include EachBatch + + self.table_name = 'issues' + + def self.with_orphaned_moved_to_issues + where('NOT EXISTS (SELECT true FROM issues WHERE issues.id = issues.moved_to_id)') + .where('moved_to_id IS NOT NULL') + end + end + + def up + Issue.with_orphaned_moved_to_issues.each_batch(of: 100) do |batch| + batch.update_all(moved_to_id: nil) + end + + add_concurrent_foreign_key( + :issues, + :issues, + column: :moved_to_id, + on_delete: :nullify + ) + + # We're using a partial index here so we only index the data we actually + # care about. + add_concurrent_index(:issues, :moved_to_id, where: 'moved_to_id IS NOT NULL') + end + + def down + remove_foreign_key_without_error(:issues, column: :moved_to_id) + remove_concurrent_index(:issues, :moved_to_id) + end +end diff --git a/db/migrate/20171106154015_remove_issues_branch_name.rb b/db/migrate/20171106154015_remove_issues_branch_name.rb new file mode 100644 index 00000000000..3d08225c96d --- /dev/null +++ b/db/migrate/20171106154015_remove_issues_branch_name.rb @@ -0,0 +1,13 @@ +# See http://doc.gitlab.com/ce/development/migration_style_guide.html +# for more information on how to write migrations for GitLab. + +class RemoveIssuesBranchName < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + # Set this constant to true if this migration requires downtime. + DOWNTIME = false + + def change + remove_column :issues, :branch_name, :string + end +end diff --git a/db/migrate/20171106155656_turn_issues_due_date_index_to_partial_index.rb b/db/migrate/20171106155656_turn_issues_due_date_index_to_partial_index.rb new file mode 100644 index 00000000000..e4bed778695 --- /dev/null +++ b/db/migrate/20171106155656_turn_issues_due_date_index_to_partial_index.rb @@ -0,0 +1,37 @@ +# See http://doc.gitlab.com/ce/development/migration_style_guide.html +# for more information on how to write migrations for GitLab. + +class TurnIssuesDueDateIndexToPartialIndex < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + # Set this constant to true if this migration requires downtime. + DOWNTIME = false + + NEW_INDEX_NAME = 'idx_issues_on_project_id_and_due_date_and_id_and_state_partial' + OLD_INDEX_NAME = 'index_issues_on_project_id_and_due_date_and_id_and_state' + + disable_ddl_transaction! + + def up + add_concurrent_index( + :issues, + [:project_id, :due_date, :id, :state], + where: 'due_date IS NOT NULL', + name: NEW_INDEX_NAME + ) + + # We set the column name to nil as otherwise Rails will ignore the custom + # index name and remove the wrong index. + remove_concurrent_index(:issues, nil, name: OLD_INDEX_NAME) + end + + def down + add_concurrent_index( + :issues, + [:project_id, :due_date, :id, :state], + name: OLD_INDEX_NAME + ) + + remove_concurrent_index(:issues, nil, name: NEW_INDEX_NAME) + end +end diff --git a/db/migrate/20171106171453_add_timezone_to_issues_closed_at.rb b/db/migrate/20171106171453_add_timezone_to_issues_closed_at.rb new file mode 100644 index 00000000000..ad540b1e509 --- /dev/null +++ b/db/migrate/20171106171453_add_timezone_to_issues_closed_at.rb @@ -0,0 +1,19 @@ +# See http://doc.gitlab.com/ce/development/migration_style_guide.html +# for more information on how to write migrations for GitLab. + +class AddTimezoneToIssuesClosedAt < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + # Set this constant to true if this migration requires downtime. + DOWNTIME = false + + disable_ddl_transaction! + + def up + change_column_type_concurrently(:issues, :closed_at, :datetime_with_timezone) + end + + def down + cleanup_concurrent_column_type_change(:issues, :closed_at) + end +end diff --git a/db/post_migrate/20171106180641_cleanup_add_timezone_to_issues_closed_at.rb b/db/post_migrate/20171106180641_cleanup_add_timezone_to_issues_closed_at.rb new file mode 100644 index 00000000000..88dd8f89ba6 --- /dev/null +++ b/db/post_migrate/20171106180641_cleanup_add_timezone_to_issues_closed_at.rb @@ -0,0 +1,19 @@ +# See http://doc.gitlab.com/ce/development/migration_style_guide.html +# for more information on how to write migrations for GitLab. + +class CleanupAddTimezoneToIssuesClosedAt < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + disable_ddl_transaction! + + def up + cleanup_concurrent_column_type_change(:issues, :closed_at) + end + + # rubocop:disable Migration/Datetime + def down + change_column_type_concurrently(:issues, :closed_at, :datetime) + end +end diff --git a/db/schema.rb b/db/schema.rb index c60cb729b75..37e08d453c8 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: 20171106101200) do +ActiveRecord::Schema.define(version: 20171106180641) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -817,13 +817,12 @@ ActiveRecord::Schema.define(version: 20171106101200) do t.integer "project_id" t.datetime "created_at" t.datetime "updated_at" - t.string "branch_name" t.text "description" t.integer "milestone_id" t.string "state" t.integer "iid" t.integer "updated_by_id" - t.boolean "confidential", default: false + t.boolean "confidential", default: false, null: false t.datetime "deleted_at" t.date "due_date" t.integer "moved_to_id" @@ -832,11 +831,11 @@ ActiveRecord::Schema.define(version: 20171106101200) do t.text "description_html" t.integer "time_estimate" t.integer "relative_position" - t.datetime "closed_at" t.integer "cached_markdown_version" t.datetime "last_edited_at" t.integer "last_edited_by_id" t.boolean "discussion_locked" + t.datetime_with_timezone "closed_at" end add_index "issues", ["assignee_id"], name: "index_issues_on_assignee_id", using: :btree @@ -845,13 +844,15 @@ ActiveRecord::Schema.define(version: 20171106101200) do add_index "issues", ["deleted_at"], name: "index_issues_on_deleted_at", using: :btree add_index "issues", ["description"], name: "index_issues_on_description_trigram", using: :gin, opclasses: {"description"=>"gin_trgm_ops"} add_index "issues", ["milestone_id"], name: "index_issues_on_milestone_id", using: :btree + add_index "issues", ["moved_to_id"], name: "index_issues_on_moved_to_id", where: "(moved_to_id IS NOT NULL)", using: :btree add_index "issues", ["project_id", "created_at", "id", "state"], name: "index_issues_on_project_id_and_created_at_and_id_and_state", using: :btree - add_index "issues", ["project_id", "due_date", "id", "state"], name: "index_issues_on_project_id_and_due_date_and_id_and_state", using: :btree + add_index "issues", ["project_id", "due_date", "id", "state"], name: "idx_issues_on_project_id_and_due_date_and_id_and_state_partial", where: "(due_date IS NOT NULL)", using: :btree add_index "issues", ["project_id", "iid"], name: "index_issues_on_project_id_and_iid", unique: true, using: :btree add_index "issues", ["project_id", "updated_at", "id", "state"], name: "index_issues_on_project_id_and_updated_at_and_id_and_state", using: :btree add_index "issues", ["relative_position"], name: "index_issues_on_relative_position", using: :btree add_index "issues", ["state"], name: "index_issues_on_state", using: :btree add_index "issues", ["title"], name: "index_issues_on_title_trigram", using: :gin, opclasses: {"title"=>"gin_trgm_ops"} + add_index "issues", ["updated_by_id"], name: "index_issues_on_updated_by_id", where: "(updated_by_id IS NOT NULL)", using: :btree create_table "keys", force: :cascade do |t| t.integer "user_id" @@ -1937,8 +1938,11 @@ ActiveRecord::Schema.define(version: 20171106101200) do add_foreign_key "issue_assignees", "issues", name: "fk_b7d881734a", on_delete: :cascade add_foreign_key "issue_assignees", "users", name: "fk_5e0c8d9154", on_delete: :cascade add_foreign_key "issue_metrics", "issues", on_delete: :cascade + add_foreign_key "issues", "issues", column: "moved_to_id", name: "fk_a194299be1", on_delete: :nullify + add_foreign_key "issues", "milestones", name: "fk_96b1dd429c", on_delete: :nullify add_foreign_key "issues", "projects", name: "fk_899c8f3231", on_delete: :cascade add_foreign_key "issues", "users", column: "author_id", name: "fk_05f1e72feb", on_delete: :nullify + add_foreign_key "issues", "users", column: "updated_by_id", name: "fk_ffed080f01", on_delete: :nullify add_foreign_key "label_priorities", "labels", on_delete: :cascade add_foreign_key "label_priorities", "projects", on_delete: :cascade add_foreign_key "labels", "namespaces", column: "group_id", on_delete: :cascade diff --git a/doc/api/groups.md b/doc/api/groups.md index 16db9c2f259..6a6e94195a7 100644 --- a/doc/api/groups.md +++ b/doc/api/groups.md @@ -9,13 +9,13 @@ Parameters: | Attribute | Type | Required | Description | | --------- | ---- | -------- | ----------- | -| `skip_groups` | array of integers | no | Skip the group IDs passes | -| `all_available` | boolean | no | Show all the groups you have access to | -| `search` | string | no | Return list of authorized groups matching the search criteria | +| `skip_groups` | array of integers | no | Skip the group IDs passed | +| `all_available` | boolean | no | Show all the groups you have access to (defaults to `false` for authenticated users) | +| `search` | string | no | Return the list of authorized groups matching the search criteria | | `order_by` | string | no | Order groups by `name` or `path`. Default is `name` | | `sort` | string | no | Order groups in `asc` or `desc` order. Default is `asc` | | `statistics` | boolean | no | Include group statistics (admins only) | -| `owned` | boolean | no | Limit by groups owned by the current user | +| `owned` | boolean | no | Limit to groups owned by the current user | ``` GET /groups @@ -80,6 +80,47 @@ You can filter by [custom attributes](custom_attributes.md) with: GET /groups?custom_attributes[key]=value&custom_attributes[other_key]=other_value ``` +## List a groups's subgroups + +Get a list of visible direct subgroups in this group. +When accessed without authentication, only public groups are returned. + +Parameters: + +| Attribute | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) of the parent group | +| `skip_groups` | array of integers | no | Skip the group IDs passed | +| `all_available` | boolean | no | Show all the groups you have access to (defaults to `false` for authenticated users) | +| `search` | string | no | Return the list of authorized groups matching the search criteria | +| `order_by` | string | no | Order groups by `name` or `path`. Default is `name` | +| `sort` | string | no | Order groups in `asc` or `desc` order. Default is `asc` | +| `statistics` | boolean | no | Include group statistics (admins only) | +| `owned` | boolean | no | Limit to groups owned by the current user | + +``` +GET /groups/:id/subgroups +``` + +```json +[ + { + "id": 1, + "name": "Foobar Group", + "path": "foo-bar", + "description": "An interesting group", + "visibility": "public", + "lfs_enabled": true, + "avatar_url": "http://gitlab.example.com/uploads/group/avatar/1/foo.jpg", + "web_url": "http://gitlab.example.com/groups/foo-bar", + "request_access_enabled": false, + "full_name": "Foobar Group", + "full_path": "foo-bar", + "parent_id": 123 + } +] +``` + ## List a group's projects Get a list of projects in this group. When accessed without authentication, only diff --git a/doc/api/services.md b/doc/api/services.md index e642ec964de..08df26db3ec 100644 --- a/doc/api/services.md +++ b/doc/api/services.md @@ -490,6 +490,41 @@ Remove all previously JIRA settings from a project. DELETE /projects/:id/services/jira ``` +## Kubernetes + +Kubernetes / Openshift integration + +### Create/Edit Kubernetes service + +Set Kubernetes service for a project. + +``` +PUT /projects/:id/services/kubernetes +``` + +Parameters: + +- `namespace` (**required**) - The Kubernetes namespace to use +- `api_url` (**required**) - The URL to the Kubernetes cluster API, e.g., https://kubernetes.example.com +- `token` (**required**) - The service token to authenticate against the Kubernetes cluster with +- `ca_pem` (optional) - A custom certificate authority bundle to verify the Kubernetes cluster with (PEM format) + +### Delete Kubernetes service + +Delete Kubernetes service for a project. + +``` +DELETE /projects/:id/services/kubernetes +``` + +### Get Kubernetes service settings + +Get Kubernetes service settings for a project. + +``` +GET /projects/:id/services/kubernetes +``` + ## Slack slash commands Ability to receive slash commands from a Slack chat instance. @@ -572,7 +607,7 @@ Parameters: | Attribute | Type | Required | Description | | --------- | ---- | -------- | ----------- | | `token` | string | yes | The Mattermost token | - +| `username` | string | no | The username to use to post the message | ### Delete Mattermost slash command service diff --git a/doc/install/installation.md b/doc/install/installation.md index 2a004152d5e..4efe911b778 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -299,9 +299,9 @@ sudo usermod -aG redis git ### Clone the Source # Clone GitLab repository - sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-ce.git -b 10-1-stable gitlab + sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-ce.git -b 10-2-stable gitlab -**Note:** You can change `10-1-stable` to `master` if you want the *bleeding edge* version, but never install master on a production server! +**Note:** You can change `10-2-stable` to `master` if you want the *bleeding edge* version, but never install master on a production server! ### Configure It diff --git a/doc/university/glossary/README.md b/doc/university/glossary/README.md index c6a91c8d5c2..076fbf6f710 100644 --- a/doc/university/glossary/README.md +++ b/doc/university/glossary/README.md @@ -23,6 +23,10 @@ A Microsoft-based [directory service](https://msdn.microsoft.com/en-us/library/b Building and [delivering software](http://agilemethodology.org/) in phases/parts rather than trying to build everything at once then delivering to the user/client. The latter is known as the WaterFall model. +### Amazon RDS + +External reference: <http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/CHAP_Storage.html> + ### Application Lifecycle Management (ALM) The entire product lifecycle management process for an application, from requirements management, development, and testing until deployment. GitLab has [advantages](https://docs.google.com/presentation/d/1vCU-NbZWz8NTNK8Vu3y4zGMAHb5DpC8PE5mHtw1PWfI/edit#slide=id.g72f2e4906_2_288) over both legacy and modern ALM tools. @@ -68,7 +72,7 @@ A branch is a parallel version of a repository. This allows you to work on the r Having your own logo on [your GitLab instance login page](https://docs.gitlab.com/ee/customization/branded_login_page.html) instead of the GitLab logo. -### Job triggers +### Job triggers (Build Triggers) These protect your code base against breaks, for instance when a team is working on the same project. Learn about [setting up](https://docs.gitlab.com/ce/ci/triggers/README.html) job triggers. ### CEPH @@ -109,15 +113,15 @@ Atlassian's product for collaboration on documents and projects. ### Continuous Delivery -A [software engineering approach](https://about.gitlab.com/2016/08/05/continuous-integration-delivery-and-deployment-with-gitlab/) in which continuous integration, automated testing, and automated deployment capabilities allow software to be developed and deployed rapidly, reliably and repeatedly with minimal human intervention. Still, the deployment to production is defined strategically and triggered manually. +A [software engineering approach](https://about.gitlab.com/2016/08/05/continuous-integration-delivery-and-deployment-with-gitlab/) in which continuous integration, automated testing, and automated deployment capabilities allow software to be developed and deployed rapidly, reliably and repeatedly with minimal human intervention. Still, the deployment to production is defined strategically and triggered manually. [Amazon moves toward continuous delivery](https://www.youtube.com/watch?v=esEFaY0FDKc) ### Continuous Deployment -A [software development practice](https://about.gitlab.com/2016/08/05/continuous-integration-delivery-and-deployment-with-gitlab/) in which every code change goes through the entire pipeline and is put into production automatically, resulting in many production deployments every day. It does everything that Continuous Delivery does, but the process is fully automated, there's no human intervention at all. +A [software development practice](https://about.gitlab.com/2016/08/05/continuous-integration-delivery-and-deployment-with-gitlab/) in which every code change goes through the entire pipeline and is put into production automatically, resulting in many production deployments every day. It does everything that Continuous Delivery does, but the process is fully automated, there's no human intervention at all. [The difference between Continuous Delivery and Continuous Integration.](https://www.youtube.com/watch?v=igwFj8PPSnw) ### Continuous Integration -A [software development practice](https://about.gitlab.com/2016/08/05/continuous-integration-delivery-and-deployment-with-gitlab/) in which you build and test software every time a developer pushes code to the application, and it happens several times a day. +A [software development practice](https://about.gitlab.com/2016/08/05/continuous-integration-delivery-and-deployment-with-gitlab/) in which you build and test software every time a developer pushes code to the application, and it happens several times a day. [Thoughtworks discusses continuous integration.](https://www.thoughtworks.com/continuous-integration) ### Contributor @@ -127,6 +131,10 @@ Term used for a person contributing to an open source project. A [natural evolution](https://about.gitlab.com/2016/09/14/gitlab-live-event-recap/) of software development that carries a conversation across functional groups throughout the development process, enabling developers to track the full path of development in a cohesive and intuitive way. ConvDev accelerates the development lifecycle by fostering collaboration and knowledge sharing from idea to production. +### Cycle Analytics + +See <https://gitlab.com/gitlab-org/gitlab-ce/issues/22458> + ### Cycle Time The time it takes to move from [idea to production](https://about.gitlab.com/2016/08/05/continuous-integration-delivery-and-deployment-with-gitlab/#from-idea-to-production-with-gitlab). @@ -135,6 +143,10 @@ The time it takes to move from [idea to production](https://about.gitlab.com/201 Atlassian product for High Availability. +### Dependencies + +As in "specify [dependencies](https://gitlab.com/gitlab-org/gitlab-ce/issues/14728) between stages." + ### Deploy Keys A [SSH key](https://docs.gitlab.com/ce/gitlab-basics/create-your-ssh-keys.html)stored on your server that grants access to a single GitLab repository. This is used by a GitLab runner to clone a project's code so that tests can be run against the checked out code. @@ -151,15 +163,17 @@ The intersection of software engineering, quality assurance, and technology oper The difference between two commits, or saved changes. This will also be shown visually after the changes. -#### Directory +### Directory A folder used for storing multiple files. ### Docker Container Registry -A [feature](https://docs.gitlab.com/ce/user/project/container_registry.html) of GitLab projects. Containers wrap up a piece of software in a complete filesystem that contains everything it needs to run: code, runtime, system tools, system libraries – anything you can install on a server. This guarantees that it will always run the same, regardless of the environment it is running in. +A [feature](https://docs.gitlab.com/ce/user/project/container_registry.html) of [GitLab projects](https://about.gitlab.com/2016/05/23/gitlab-container-registry/). Containers wrap up a piece of software in a complete filesystem that contains everything it needs to run: code, runtime, system tools, system libraries – anything you can install on a server. This guarantees that it will always run the same, regardless of the environment it is running in. -### Dynamic Environment +### Dynamic Environment (review apps) + +### EC2 Instance ### ElasticSearch @@ -167,10 +181,26 @@ Elasticsearch is a flexible, scalable and powerful search service. When [enabled ### Emacs +External reference: <https://www.masteringemacs.org/article/mastering-key-bindings-emacs> + +### First Byte + +External reference: <https://en.wikipedia.org/wiki/Time_To_First_Byte> + +First Byte (sometimes referred to as time to first byte or [TTFB](https://en.wikipedia.org/wiki/Time_To_First_Byte)) measures the time between making a request and receiving the first byte of information in return. As a result, First Byte encompasses everything that is the backend as well as network transit issues. It differs from [_Speed Index_](#speed-index) mostly by frontend related issues which are included in Speed Index such as javascript loading, page rendering, and so on. + ### Fork Your [own copy](https://docs.gitlab.com/ce/workflow/forking_workflow.html) of a repository that allows you to make changes to the repository without affecting the original. +### Funnel, or: TOFU, MOFU, BOFU + +External reference: [Blog post](https://www.weidert.com/whole_brain_marketing_blog/bid/113688/ToFu-MoFu-BoFu-Serving-Up-The-Right-Content-for-Lead-Nurturing) + +TOFU: top of funnel +MOFU: middle of funnel +BOFU: bottom of funnel + ### Gerrit A code review [tool](https://www.gerritcodereview.com/) built on top of Git. @@ -183,6 +213,8 @@ A [git attributes file](https://git-scm.com/docs/gitattributes) is a simple text [Scripts](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks) you can use to trigger actions at certain points. +Difference between a [webhook](#webhooks) and a git hook: a git hook is local to its repo (usually) while a webhook is not (it can make API or http calls). So for example if you want your linter to fire before you commit, you can set that up with a git hook. If the linter fails, the commit does not go through. A git hook _can_ be configured to go beyond its repo, e.g. by having it make an API call. + ### GitHost.io A single-tenant solution that provides GitLab CE or EE as a managed service. GitLab Inc. is responsible for installing, updating, hosting, and backing up customers' own private and secure GitLab instance. @@ -211,9 +243,20 @@ Our free SaaS for public and private repositories. Allows you to replicate your GitLab instance to other geographical locations as a read-only fully operational version. It [can be used](https://docs.gitlab.com/ee/gitlab-geo/README.html) for cloning and fetching projects, in addition to reading any data. This will make working with large repositories over large distances much faster. +### GitLab High Availability + +### GitLab Master Plan + +Related blog post: <https://about.gitlab.com/2016/09/13/gitlab-master-plan/>. + ### GitLab Pages + These allow you to [create websites](https://gitlab.com/help/pages/README.md) for your GitLab projects, groups, or user account. +### GitLab Runner + +Related project: <https://gitlab.com/gitlab-org/gitlab-runner> + ### Gitolite An [access layer](https://git-scm.com/book/en/v1/Git-on-the-Server-Gitolite) that sits on top of Git. Users are granted access to repos via a simple config file. As an admin, you only need the users' public SSH key and a username. @@ -226,6 +269,10 @@ A web-based hosting service for projects using Git. It was acquired by GitLab an An open source programming [language](https://golang.org/). +### Gogs + +External reference: <https://gogs.io/> + ### GUI/ Git GUI A portable [graphical interface](https://git-scm.com/docs/git-gui) to Git that allows users to make changes to their repository by making new commits, amending existing ones, creating branches, performing local merges, and fetching/pushing to remote repositories. @@ -256,7 +303,7 @@ A [tool](https://docs.gitlab.com/ee/integration/external-issue-tracker.html) use ### Jenkins -An Open Source CI tool written using the Java programming language. [Jenkins](https://jenkins-ci.org/) does the same job as GitLab CI, Bamboo, and Travis CI. It is extremely popular. +An Open Source CI tool written using the Java programming language. [Jenkins](https://jenkins-ci.org/) does the same job as GitLab CI, Bamboo, and Travis CI. It is extremely popular. Related [documentation](https://docs.gitlab.com/ee/integration/jenkins.html). ### Jira @@ -290,6 +337,10 @@ GitLab [integrates](https://docs.gitlab.com/ce/administration/auth/ldap.html) wi Allows you to synchronize the members of a GitLab group with one or more LDAP groups. +### Lint + +Static code analysis for our various file types. For example, we use [scss-lint](https://github.com/brigade/scss-lint) to ensure that a consistent code styling is respected. Similar tools: rubocop / eslint. + ### Load Balancer A [device](https://en.wikipedia.org/wiki/Load_balancing_(computing)) that distributes network or application traffic across multiple servers. @@ -330,6 +381,10 @@ Takes changes from one branch, and [applies them](https://git-scm.com/docs/git-m [Arises](https://about.gitlab.com/2016/09/06/resolving-merge-conflicts-from-the-gitlab-ui/) when a merge can't be performed cleanly between two versions of the same file. +#### Merge Request + +[Takes changes](https://docs.gitlab.com/ce/gitlab-basics/add-merge-request.html) from one branch, and applies them into another branch. + ### Meteor A [platform](https://www.meteor.com) for building javascript apps. @@ -350,6 +405,14 @@ A type of software license. It lets people do anything with your code with prope A free disaster recovery [software](https://help.ubuntu.com/community/MondoMindi). +#### Mount + +External reference: + +As stated on the [wikipedia page](https://en.wikipedia.org/wiki/Mount_(Unix)), "Mounting makes file systems, files, directories, devices and special files available for use and available to the user." + +For example, we have NFS servers where the _git files_ reside. In order for a worker node to "see" or "use" the git files, the NFS server needs to be _mounted_ on the worker; that is, the worker needs to know that the NFS server exists and how to connect to it. Think of it as getting a shared drive to show up in your Finder (on Mac) or Explorer (on Windows). + ### MySQL A relational [database](http://www.mysql.com/) owned by Oracle. Currently only supported if you are using EE. @@ -360,7 +423,7 @@ A set of symbols that are used to organize objects of various kinds so that thes ### Nginx -A web [server](https://www.nginx.com/resources/wiki/) (pronounced "engine x"). It can act as a reverse proxy server for HTTP, HTTPS, SMTP, POP3, and IMAP protocols, as well as a load balancer and an HTTP cache. +A web [server](https://www.nginx.com/resources/wiki/) (pronounced "engine x"). [It can act]((https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/doc/settings/nginx.md) as a reverse proxy server for HTTP, HTTPS, SMTP, POP3, and IMAP protocols, as well as a load balancer and an HTTP cache. ### OAuth @@ -380,7 +443,11 @@ GitLab's [business model](https://about.gitlab.com/2016/07/20/gitlab-is-open-cor ### Open Source Software -Software for which the original source code is freely [available](https://opensource.org/docs/osd) and may be redistributed and modified. GitLab prioritizes open source [stewardship](https://about.gitlab.com/2016/01/11/being-a-good-open-source-steward/). +Software for which the original source code is freely [available](https://opensource.org/docs/osd) and may be redistributed and modified. GitLab prioritizes open source [stewardship](https://about.gitlab.com/2016/01/11/being-a-good-open-source-steward/). Including to providing access to the source code, open source software must comply with a number of criteria, among them free distribution and no discrimination against persons, groups, or fields of endeavor. + +#### Open Source Stewardship + +[Related blog post](https://about.gitlab.com/2016/01/11/being-a-good-open-source-steward/). ### Owner @@ -430,6 +497,8 @@ A popular DevOps [automation tool](https://puppet.com/product/how-puppet-works). Git [command](https://git-scm.com/docs/git-push) to send commits from the local repository to the remote repository. Read about [advanced push rules](https://gitlab.com/help/pages/README.md) in GitLab. +### Raketasks + ### RE Read Only Permissions to see a file and its contents, but not change it. @@ -438,10 +507,24 @@ Permissions to see a file and its contents, but not change it. In addition to the merge, the [rebase](https://git-scm.com/book/en/v2/Git-Branching-Rebasing) is a main way to integrate changes from one branch into another. +### Regression + +A regression is something that used to work one way in the last release and then we made a **breaking change** and it no longer works the same way. + +_or_ + +A regression is defined as a change that results in a negative impact on the functionality of an existing feature due to recent changes, i.e. the latest release. + +### Remote mirroring + ### (Git) Repository A directory where Git [has been initiatlized](https://git-scm.com/book/en/v2/Git-Basics-Getting-a-Git-Repository) to start version controlling your files. The history of your work is stored here. A remote repository is not on your machine, but usually online (like on GitLab.com, for instance). The main remote repository is usually called "Origin." +##### Remote repository + +A [repository](https://about.gitlab.com/2015/05/18/simple-words-for-a-gitlab-newbie/) that is not-on-your-machine, so it's anything that is not your computer. Usually, it is online, GitLab.com for instance. The main remote repository is usually called “Origin”. + ### Requirements management Gives your distributed teams a single shared repository to collaborate and share requirements, understand their relationship to tests, and evaluate linked defects. It includes multiple, preconfigured requirement types. @@ -474,7 +557,11 @@ Software that is hosted centrally and accessed on-demand (i.e. whenever you want This term is often used by people when they mean "Version Control." -## Scrum +#### SCLAU + +Abbreviation for SQO Count [Large And Up](https://about.gitlab.com/handbook/sales/#market-segmentation). This is the number of opportunities in large and strategic organizations passed from marketing to sales. + +### Scrum An Agile [framework](https://www.scrum.org/Resources/What-is-Scrum) designed to typically help complete complex software projects. It's made up of several parts: product requirements backlog, sprint planning, sprint (development), sprint review, and retrospec (analyzing the sprint). The goal is to end up with potentially shippable products. @@ -484,7 +571,9 @@ The board used to track the status and progress of each of the sprint backlog it ### Shell -Terminal on Mac OSX, GitBash on Windows, or Linux Terminal on Linux. You [use git]() and make changes to GitLab projects in your shell. You [use git](https://docs.gitlab.com/ce/gitlab-basics/start-using-git.html) and make changes to GitLab projects in your shell. +Terminal on Mac OSX, GitBash on Windows, or Linux Terminal on Linux. You [use git](https://docs.gitlab.com/ce/gitlab-basics/start-using-git.html) and make changes to GitLab projects in your shell. You [use git](https://docs.gitlab.com/ce/gitlab-basics/start-using-git.html) and make changes to GitLab projects in your shell. + +### Shell command runner ### Single-tenant @@ -494,6 +583,8 @@ The tenant purchases their own copy of the software and the software can be cust Real time messaging app for teams that is used internally by GitLab team members. GitLab users can enable [Slack integration](https://docs.gitlab.com/ce/project_services/slack.html) to trigger push, issue, and merge request events among others. +### Slash commands + ### Slave Servers Also known as secondary servers, these help to spread the load over multiple machines. They also provide backups when the master/primary server crashes. @@ -502,6 +593,10 @@ Also known as secondary servers, these help to spread the load over multiple mac Program code as typed by a computer programmer (i.e. it has not yet been compiled/translated by the computer to machine language). +### Speed Index + +[Speed Index](https://sites.google.com/a/webpagetest.org/docs/using-webpagetest/metrics/speed-index) is "the average time at which visible parts of the page are displayed". + ### SSH Key A unique identifier of a computer. It is used to identify computers without the need for a password (e.g., On GitLab I have [added the ssh key](https://docs.gitlab.com/ce/gitlab-basics/create-your-ssh-keys.html) of all my work machines so that the GitLab instance knows that it can accept code pushes and pulls from this trusted machines whose keys are I have added.) @@ -542,6 +637,16 @@ An open source version control system. Read about [migrating from SVN](https://d [Represents](https://docs.gitlab.com/ce/api/tags.html) a version of a particular branch at a moment in time. +### Tenancy + +#### Multi-tenant + +A [multi-tenant](http://whatis.techtarget.com/definition/multi-tenancy) GitLab instance can have any number of customers - such as companies or groups of users using it. GitLab.com is an example of a multi-tenant GitLab instance. + +#### Single-tenant + +A [single-tenant](http://searchcloudapplications.techtarget.com/definition/single-tenancy) GitLab instance has only one customer - such as a company - using it. On premise GitLab instances are almost exclusively single-tenant. + ### Tool Stack The set of tools used in a process to achieve a common outcome (e.g. set of tools used in Application Lifecycle Management). @@ -550,9 +655,17 @@ The set of tools used in a process to achieve a common outcome (e.g. set of tool An open source project management and bug tracking web [application](https://trac.edgewall.org/). +### True-Up licensing model + +### Ubuntu + ### Untracked files -New files that Git has not [been told](https://git-scm.com/book/en/v2/Git-Basics-Recording-Changes-to-the-Repository) to track previously. +New files that Git has not [been told](https://git-scm.com/book/en/v2/Git-Basics-Recording-Changes-to-the-Repository) to track previously. Add them by using the command "git add [file path]" + +### Upstream repository vs. GitLab repository + +[External conversation](https://news.ycombinator.com/item?id=12487112) ### User @@ -560,11 +673,11 @@ Anyone interacting with the software. ### Version Control Software (VCS) -Version control is a system that records changes to a file or set of files over time so that you can recall specific versions later. VCS [has evolved](https://docs.google.com/presentation/d/16sX7hUrCZyOFbpvnrAFrg6tVO5_yT98IgdAqOmXwBho/edit#slide=id.gd69537a19_0_32) from local version control systems, to centralized version control systems, to the present distributed version control systems like Git, Mercurial, Bazaar, and Darcs. +Version control is a system that records changes to a file or set of files over time so that you can recall specific versions later. VCS [has evolved](https://docs.google.com/presentation/d/16sX7hUrCZyOFbpvnrAFrg6tVO5_yT98IgdAqOmXwBho/edit#slide=id.gd69537a19_0_32) from local version control systems, to centralized version control systems, to the present [distributed version control systems](https://en.wikipedia.org/wiki/Distributed_version_control) like Git, Mercurial, Bazaar, and Darcs. If any server dies, and these systems were collaborating via it, any of the client repositories can be copied back up to the server to restore it. ### Virtual Private Cloud (VPC) -An on demand configurable pool of shared computing resources allocated within a public cloud environment, providing some isolation between the different users using the resources. GitLab users need to create a new Amazon VPC in order to [setup High Availability](https://docs.gitlab.com/ce/university/high-availability/aws/). +A [VPC](https://docs.gitlab.com/ce/university/glossary/README.html#virtual-private-cloud-vpc) is an on demand configurable pool of shared computing resources allocated within a public cloud environment, providing some isolation between the different users using the resources. GitLab users need to create a new Amazon VPC in order to [setup High Availability](https://docs.gitlab.com/ce/university/high-availability/aws/). ### Virtual private server (VPS) @@ -572,7 +685,7 @@ A [virtual machine](https://en.wikipedia.org/wiki/Virtual_private_server) sold a ### VM Instance -In object-oriented programming, an [instance](http://stackoverflow.com/questions/20461907/what-is-meaning-of-instance-in-programming) is a specific realization of any object. An object may be varied in a number of ways. Each realized variation of that object is an instance. Therefore, a VM instance is an instance of a virtual machine, which is an emulation of a computer system. +In object-oriented programming, an [instance](http://stackoverflow.com/questions/20461907/what-is-meaning-of-instance-in-programming) is a specific realization of any [object](https://cloud.google.com/compute/docs/instances/). An object may be varied in a number of ways. Each realized variation of that object is an instance. Therefore, a VM instance is an instance of a virtual machine, which is an emulation of a computer system. ### Waterfall @@ -586,6 +699,10 @@ A way for for an app to [provide](https://docs.gitlab.com/ce/user/project/integr A [website/system](http://www.wiki.com/) that allows for collaborative editing of its content by the users. In programming, wikis usually contain documentation of how to use the software. +### Working area + +Files that have been modified but are not committed. Check them by using the command "git status". + ### Working Tree [Consists of files](http://stackoverflow.com/questions/3689838/difference-between-head-working-tree-index-in-git) that you are currently working on. diff --git a/doc/update/10.1-to-10.2.md b/doc/update/10.1-to-10.2.md new file mode 100644 index 00000000000..9e0d8f79522 --- /dev/null +++ b/doc/update/10.1-to-10.2.md @@ -0,0 +1,360 @@ +--- +comments: false +--- + +# From 10.1 to 10.2 + +Make sure you view this update guide from the tag (version) of GitLab you would +like to install. In most cases this should be the highest numbered production +tag (without rc in it). You can select the tag in the version dropdown at the +top left corner of GitLab (below the menu bar). + +If the highest number stable branch is unclear please check the +[GitLab Blog](https://about.gitlab.com/blog/archives.html) for installation +guide links by version. + +### 1. Stop server + +```bash +sudo service gitlab stop +``` + +### 2. Backup + +```bash +cd /home/git/gitlab + +sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production +``` + +### 3. Update Ruby + +NOTE: GitLab 9.0 and higher only support Ruby 2.3.x and dropped support for Ruby 2.1.x. Be +sure to upgrade your interpreter if necessary. + +You can check which version you are running with `ruby -v`. + +Download and compile Ruby: + +```bash +mkdir /tmp/ruby && cd /tmp/ruby +curl --remote-name --progress https://cache.ruby-lang.org/pub/ruby/2.3/ruby-2.3.5.tar.gz +echo '3247e217d6745c27ef23bdc77b6abdb4b57a118f ruby-2.3.5.tar.gz' | shasum -c - && tar xzf ruby-2.3.5.tar.gz +cd ruby-2.3.5 +./configure --disable-install-rdoc +make +sudo make install +``` + +Install Bundler: + +```bash +sudo gem install bundler --no-ri --no-rdoc +``` + +### 4. Update Node + +GitLab now runs [webpack](http://webpack.js.org) to compile frontend assets and +it has a minimum requirement of node v4.3.0. + +You can check which version you are running with `node -v`. If you are running +a version older than `v4.3.0` you will need to update to a newer version. You +can find instructions to install from community maintained packages or compile +from source at the nodejs.org website. + +<https://nodejs.org/en/download/> + + +Since 8.17, GitLab requires the use of yarn `>= v0.17.0` to manage +JavaScript dependencies. + +```bash +curl --silent --show-error https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add - +echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list +sudo apt-get update +sudo apt-get install yarn +``` + +More information can be found on the [yarn website](https://yarnpkg.com/en/docs/install). + +### 5. Update Go + +NOTE: GitLab 9.2 and higher only supports Go 1.8.3 and dropped support for Go +1.5.x through 1.7.x. Be sure to upgrade your installation if necessary. + +You can check which version you are running with `go version`. + +Download and install Go: + +```bash +# Remove former Go installation folder +sudo rm -rf /usr/local/go + +curl --remote-name --progress https://storage.googleapis.com/golang/go1.8.3.linux-amd64.tar.gz +echo '1862f4c3d3907e59b04a757cfda0ea7aa9ef39274af99a784f5be843c80c6772 go1.8.3.linux-amd64.tar.gz' | shasum -a256 -c - && \ + sudo tar -C /usr/local -xzf go1.8.3.linux-amd64.tar.gz +sudo ln -sf /usr/local/go/bin/{go,godoc,gofmt} /usr/local/bin/ +rm go1.8.3.linux-amd64.tar.gz +``` + +### 6. Get latest code + +```bash +cd /home/git/gitlab + +sudo -u git -H git fetch --all +sudo -u git -H git checkout -- db/schema.rb # local changes will be restored automatically +sudo -u git -H git checkout -- locale +``` + +For GitLab Community Edition: + +```bash +cd /home/git/gitlab + +sudo -u git -H git checkout 10-2-stable +``` + +OR + +For GitLab Enterprise Edition: + +```bash +cd /home/git/gitlab + +sudo -u git -H git checkout 10-2-stable-ee +``` + +### 7. Update gitlab-shell + +```bash +cd /home/git/gitlab-shell + +sudo -u git -H git fetch --all --tags +sudo -u git -H git checkout v$(</home/git/gitlab/GITLAB_SHELL_VERSION) +sudo -u git -H bin/compile +``` + +### 8. Update gitlab-workhorse + +Install and compile gitlab-workhorse. GitLab-Workhorse uses +[GNU Make](https://www.gnu.org/software/make/). +If you are not using Linux you may have to run `gmake` instead of +`make` below. + +```bash +cd /home/git/gitlab-workhorse + +sudo -u git -H git fetch --all --tags +sudo -u git -H git checkout v$(</home/git/gitlab/GITLAB_WORKHORSE_VERSION) +sudo -u git -H make +``` + +### 9. Update Gitaly + +#### New Gitaly configuration options required + +In order to function Gitaly needs some additional configuration information. Below we assume you installed Gitaly in `/home/git/gitaly` and GitLab Shell in `/home/git/gitlab-shell`. + +```shell +echo ' +[gitaly-ruby] +dir = "/home/git/gitaly/ruby" + +[gitlab-shell] +dir = "/home/git/gitlab-shell" +' | sudo -u git tee -a /home/git/gitaly/config.toml +``` + +#### Check Gitaly configuration + +Due to a bug in the `rake gitlab:gitaly:install` script your Gitaly +configuration file may contain syntax errors. The block name +`[[storages]]`, which may occur more than once in your `config.toml` +file, should be `[[storage]]` instead. + +```shell +sudo -u git -H sed -i.pre-10.1 's/\[\[storages\]\]/[[storage]]/' /home/git/gitaly/config.toml +``` + +#### Compile Gitaly + +```shell +cd /home/git/gitaly +sudo -u git -H git fetch --all --tags +sudo -u git -H git checkout v$(</home/git/gitlab/GITALY_SERVER_VERSION) +sudo -u git -H make +``` + +### 10. Update MySQL permissions + +If you are using MySQL you need to grant the GitLab user the necessary +permissions on the database: + +```bash +mysql -u root -p -e "GRANT TRIGGER ON \`gitlabhq_production\`.* TO 'git'@'localhost';" +``` + +If you use MySQL with replication, or just have MySQL configured with binary logging, +you will need to also run the following on all of your MySQL servers: + +```bash +mysql -u root -p -e "SET GLOBAL log_bin_trust_function_creators = 1;" +``` + +You can make this setting permanent by adding it to your `my.cnf`: + +``` +log_bin_trust_function_creators=1 +``` + +### 11. Update configuration files + +#### New configuration options for `gitlab.yml` + +There might be configuration options available for [`gitlab.yml`][yaml]. View them with the command below and apply them manually to your current `gitlab.yml`: + +```sh +cd /home/git/gitlab + +git diff origin/10-1-stable:config/gitlab.yml.example origin/10-2-stable:config/gitlab.yml.example +``` + +#### Nginx configuration + +Ensure you're still up-to-date with the latest NGINX configuration changes: + +```sh +cd /home/git/gitlab + +# For HTTPS configurations +git diff origin/10-1-stable:lib/support/nginx/gitlab-ssl origin/10-2-stable:lib/support/nginx/gitlab-ssl + +# For HTTP configurations +git diff origin/10-1-stable:lib/support/nginx/gitlab origin/10-2-stable:lib/support/nginx/gitlab +``` + +If you are using Strict-Transport-Security in your installation to continue using it you must enable it in your Nginx +configuration as GitLab application no longer handles setting it. + +If you are using Apache instead of NGINX please see the updated [Apache templates]. +Also note that because Apache does not support upstreams behind Unix sockets you +will need to let gitlab-workhorse listen on a TCP port. You can do this +via [/etc/default/gitlab]. + +[Apache templates]: https://gitlab.com/gitlab-org/gitlab-recipes/tree/master/web-server/apache +[/etc/default/gitlab]: https://gitlab.com/gitlab-org/gitlab-ce/blob/10-2-stable/lib/support/init.d/gitlab.default.example#L38 + +#### SMTP configuration + +If you're installing from source and use SMTP to deliver mail, you will need to add the following line +to config/initializers/smtp_settings.rb: + +```ruby +ActionMailer::Base.delivery_method = :smtp +``` + +See [smtp_settings.rb.sample] as an example. + +[smtp_settings.rb.sample]: https://gitlab.com/gitlab-org/gitlab-ce/blob/10-2-stable/config/initializers/smtp_settings.rb.sample#L13 + +#### Init script + +There might be new configuration options available for [`gitlab.default.example`][gl-example]. View them with the command below and apply them manually to your current `/etc/default/gitlab`: + +```sh +cd /home/git/gitlab + +git diff origin/10-1-stable:lib/support/init.d/gitlab.default.example origin/10-2-stable:lib/support/init.d/gitlab.default.example +``` + +Ensure you're still up-to-date with the latest init script changes: + +```bash +cd /home/git/gitlab + +sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab +``` + +For Ubuntu 16.04.1 LTS: + +```bash +sudo systemctl daemon-reload +``` + +### 12. Install libs, migrations, etc. + +```bash +cd /home/git/gitlab + +# MySQL installations (note: the line below states '--without postgres') +sudo -u git -H bundle install --without postgres development test --deployment + +# PostgreSQL installations (note: the line below states '--without mysql') +sudo -u git -H bundle install --without mysql development test --deployment + +# Optional: clean up old gems +sudo -u git -H bundle clean + +# Run database migrations +sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production + +# Compile GetText PO files + +sudo -u git -H bundle exec rake gettext:compile RAILS_ENV=production + +# Update node dependencies and recompile assets +sudo -u git -H bundle exec rake yarn:install gitlab:assets:clean gitlab:assets:compile RAILS_ENV=production NODE_ENV=production + +# Clean up cache +sudo -u git -H bundle exec rake cache:clear RAILS_ENV=production +``` + +**MySQL installations**: Run through the `MySQL strings limits` and `Tables and data conversion to utf8mb4` [tasks](../install/database_mysql.md). + +### 13. Start application + +```bash +sudo service gitlab start +sudo service nginx restart +``` + +### 14. Check application status + +Check if GitLab and its environment are configured correctly: + +```bash +cd /home/git/gitlab + +sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production +``` + +To make sure you didn't miss anything run a more thorough check: + +```bash +cd /home/git/gitlab + +sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production +``` + +If all items are green, then congratulations, the upgrade is complete! + +## Things went south? Revert to previous version (10.0) + +### 1. Revert the code to the previous version + +Follow the [upgrade guide from 9.5 to 10.0](9.5-to-10.0.md), except for the +database migration (the backup is already migrated to the previous version). + +### 2. Restore from the backup + +```bash +cd /home/git/gitlab + +sudo -u git -H bundle exec rake gitlab:backup:restore RAILS_ENV=production +``` + +If you have more than one backup `*.tar` file(s) please add `BACKUP=timestamp_of_backup` to the command above. + +[yaml]: https://gitlab.com/gitlab-org/gitlab-ce/blob/10-2-stable/config/gitlab.yml.example +[gl-example]: https://gitlab.com/gitlab-org/gitlab-ce/blob/10-2-stable/lib/support/init.d/gitlab.default.example diff --git a/doc/user/project/members/index.md b/doc/user/project/members/index.md index b8dd96087f1..43713855e26 100644 --- a/doc/user/project/members/index.md +++ b/doc/user/project/members/index.md @@ -21,7 +21,7 @@ want to add. --- -Select the user and the [permission level](../../user/permissions.md) +Select the user and the [permission level](../../permissions.md) that you'd like to give the user. Note that you can select more than one user. ![Give user permissions](img/add_user_give_permissions.png) diff --git a/lib/api/groups.rb b/lib/api/groups.rb index 340a7cecf09..bcf2e6dae1d 100644 --- a/lib/api/groups.rb +++ b/lib/api/groups.rb @@ -25,24 +25,7 @@ module API optional :statistics, type: Boolean, default: false, desc: 'Include project statistics' end - def present_groups(groups, options = {}) - options = options.reverse_merge( - with: Entities::Group, - current_user: current_user - ) - - groups = groups.with_statistics if options[:statistics] - present paginate(groups), options - end - end - - resource :groups do - include CustomAttributesEndpoints - - desc 'Get a groups list' do - success Entities::Group - end - params do + params :group_list_params do use :statistics_params optional :skip_groups, type: Array[Integer], desc: 'Array of group ids to exclude from list' optional :all_available, type: Boolean, desc: 'Show all group that you have access to' @@ -52,19 +35,47 @@ module API optional :sort, type: String, values: %w[asc desc], default: 'asc', desc: 'Sort by asc (ascending) or desc (descending)' use :pagination end - get do + + def find_groups(params) find_params = { all_available: params[:all_available], - owned: params[:owned], - custom_attributes: params[:custom_attributes] + custom_attributes: params[:custom_attributes], + owned: params[:owned] } + find_params[:parent] = find_group!(params[:id]) if params[:id] groups = GroupsFinder.new(current_user, find_params).execute groups = groups.search(params[:search]) if params[:search].present? groups = groups.where.not(id: params[:skip_groups]) if params[:skip_groups].present? groups = groups.reorder(params[:order_by] => params[:sort]) - present_groups groups, statistics: params[:statistics] && current_user.admin? + groups + end + + def present_groups(params, groups) + options = { + with: Entities::Group, + current_user: current_user, + statistics: params[:statistics] && current_user.admin? + } + + groups = groups.with_statistics if options[:statistics] + present paginate(groups), options + end + end + + resource :groups do + include CustomAttributesEndpoints + + desc 'Get a groups list' do + success Entities::Group + end + params do + use :group_list_params + end + get do + groups = find_groups(params) + present_groups params, groups end desc 'Create a group. Available only for users who can create groups.' do @@ -166,6 +177,17 @@ module API present paginate(projects), with: entity, current_user: current_user end + desc 'Get a list of subgroups in this group.' do + success Entities::Group + end + params do + use :group_list_params + end + get ":id/subgroups" do + groups = find_groups(params) + present_groups params, groups + end + desc 'Transfer a project to the group namespace. Available only for admin.' do success Entities::GroupDetail end diff --git a/lib/api/services.rb b/lib/api/services.rb index 6454e475036..bbcc851d07a 100644 --- a/lib/api/services.rb +++ b/lib/api/services.rb @@ -522,6 +522,12 @@ module API name: :webhook, type: String, desc: 'The Mattermost webhook. e.g. http://mattermost_host/hooks/...' + }, + { + required: false, + name: :username, + type: String, + desc: 'The username to use to post the message' } ], 'teamcity' => [ diff --git a/lib/gitlab/git/operation_service.rb b/lib/gitlab/git/operation_service.rb index ab94ba8a73a..e36d5410431 100644 --- a/lib/gitlab/git/operation_service.rb +++ b/lib/gitlab/git/operation_service.rb @@ -72,7 +72,7 @@ module Gitlab # Whenever `start_branch_name` is passed, if `branch_name` doesn't exist, # it would be created from `start_branch_name`. - # If `start_project` is passed, and the branch doesn't exist, + # If `start_repository` is passed, and the branch doesn't exist, # it would try to find the commits from it instead of current repository. def with_branch( branch_name, @@ -80,15 +80,13 @@ module Gitlab start_repository: repository, &block) - # Refactoring aid - unless start_repository.is_a?(Gitlab::Git::Repository) - raise "expected a Gitlab::Git::Repository, got #{start_repository}" - end + Gitlab::Git.check_namespace!(start_repository) + start_repository = RemoteRepository.new(start_repository) unless start_repository.is_a?(RemoteRepository) start_branch_name = nil if start_repository.empty_repo? if start_branch_name && !start_repository.branch_exists?(start_branch_name) - raise ArgumentError, "Cannot find branch #{start_branch_name} in #{start_repository.full_path}" + raise ArgumentError, "Cannot find branch #{start_branch_name} in #{start_repository.relative_path}" end update_branch_with_hooks(branch_name) do diff --git a/lib/gitlab/git/remote_repository.rb b/lib/gitlab/git/remote_repository.rb new file mode 100644 index 00000000000..3685aa20669 --- /dev/null +++ b/lib/gitlab/git/remote_repository.rb @@ -0,0 +1,82 @@ +module Gitlab + module Git + # + # When a Gitaly call involves two repositories instead of one we cannot + # assume that both repositories are on the same Gitaly server. In this + # case we need to make a distinction between the repository that the + # call is being made on (a Repository instance), and the "other" + # repository (a RemoteRepository instance). This is the reason why we + # have the RemoteRepository class in Gitlab::Git. + # + # When you make changes, be aware that gitaly-ruby sub-classes this + # class. + # + class RemoteRepository + attr_reader :path, :relative_path, :gitaly_repository + + def initialize(repository) + @relative_path = repository.relative_path + @gitaly_repository = repository.gitaly_repository + + # These instance variables will not be available in gitaly-ruby, where + # we have no disk access to this repository. + @repository = repository + @path = repository.path + end + + def empty_repo? + # We will override this implementation in gitaly-ruby because we cannot + # use '@repository' there. + @repository.empty_repo? + end + + def commit_id(revision) + # We will override this implementation in gitaly-ruby because we cannot + # use '@repository' there. + @repository.commit(revision)&.sha + end + + def branch_exists?(name) + # We will override this implementation in gitaly-ruby because we cannot + # use '@repository' there. + @repository.branch_exists?(name) + end + + # Compares self to a Gitlab::Git::Repository. This implementation uses + # 'self.gitaly_repository' so that it will also work in the + # GitalyRemoteRepository subclass defined in gitaly-ruby. + def same_repository?(other_repository) + gitaly_repository.storage_name == other_repository.storage && + gitaly_repository.relative_path == other_repository.relative_path + end + + def fetch_env + gitaly_ssh = File.absolute_path(File.join(Gitlab.config.gitaly.client_path, 'gitaly-ssh')) + gitaly_address = gitaly_client.address(storage) + gitaly_token = gitaly_client.token(storage) + + request = Gitaly::SSHUploadPackRequest.new(repository: gitaly_repository) + env = { + 'GITALY_ADDRESS' => gitaly_address, + 'GITALY_PAYLOAD' => request.to_json, + 'GITALY_WD' => Dir.pwd, + 'GIT_SSH_COMMAND' => "#{gitaly_ssh} upload-pack" + } + env['GITALY_TOKEN'] = gitaly_token if gitaly_token.present? + + env + end + + private + + # Must return an object that responds to 'address' and 'storage'. + def gitaly_client + Gitlab::GitalyClient + end + + def storage + gitaly_repository.storage_name + end + end + end +end diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb index 359547cf63d..cfb88a0c12b 100644 --- a/lib/gitlab/git/repository.rb +++ b/lib/gitlab/git/repository.rb @@ -58,7 +58,7 @@ module Gitlab # Rugged repo object attr_reader :rugged - attr_reader :storage, :gl_repository, :relative_path, :gitaly_resolver + attr_reader :storage, :gl_repository, :relative_path # This initializer method is only used on the client side (gitlab-ce). # Gitaly-ruby uses a different initializer. @@ -66,7 +66,6 @@ module Gitlab @storage = storage @relative_path = relative_path @gl_repository = gl_repository - @gitaly_resolver = Gitlab::GitalyClient storage_path = Gitlab.config.repositories.storages[@storage]['path'] @path = File.join(storage_path, @relative_path) @@ -1014,23 +1013,22 @@ module Gitlab def with_repo_branch_commit(start_repository, start_branch_name) Gitlab::Git.check_namespace!(start_repository) + start_repository = RemoteRepository.new(start_repository) unless start_repository.is_a?(RemoteRepository) return yield nil if start_repository.empty_repo? - if start_repository == self + if start_repository.same_repository?(self) yield commit(start_branch_name) else - start_commit = start_repository.commit(start_branch_name) + start_commit_id = start_repository.commit_id(start_branch_name) - return yield nil unless start_commit + return yield nil unless start_commit_id - sha = start_commit.sha - - if branch_commit = commit(sha) + if branch_commit = commit(start_commit_id) yield branch_commit else with_repo_tmp_commit( - start_repository, start_branch_name, sha) do |tmp_commit| + start_repository, start_branch_name, start_commit_id) do |tmp_commit| yield tmp_commit end end @@ -1087,6 +1085,9 @@ module Gitlab end def fetch_ref(source_repository, source_ref:, target_ref:) + Gitlab::Git.check_namespace!(source_repository) + source_repository = RemoteRepository.new(source_repository) unless source_repository.is_a?(RemoteRepository) + message, status = GitalyClient.migrate(:fetch_ref) do |is_enabled| if is_enabled gitaly_fetch_ref(source_repository, source_ref: source_ref, target_ref: target_ref) @@ -1620,22 +1621,9 @@ module Gitlab end def gitaly_fetch_ref(source_repository, source_ref:, target_ref:) - gitaly_ssh = File.absolute_path(File.join(Gitlab.config.gitaly.client_path, 'gitaly-ssh')) - gitaly_address = gitaly_resolver.address(source_repository.storage) - gitaly_token = gitaly_resolver.token(source_repository.storage) - - request = Gitaly::SSHUploadPackRequest.new(repository: source_repository.gitaly_repository) - env = { - 'GITALY_ADDRESS' => gitaly_address, - 'GITALY_PAYLOAD' => request.to_json, - 'GITALY_WD' => Dir.pwd, - 'GIT_SSH_COMMAND' => "#{gitaly_ssh} upload-pack" - } - env['GITALY_TOKEN'] = gitaly_token if gitaly_token.present? - args = %W(fetch --no-tags -f ssh://gitaly/internal.git #{source_ref}:#{target_ref}) - run_git(args, env: env) + run_git(args, env: source_repository.fetch_env) end def gitaly_ff_merge(user, source_sha, target_branch) diff --git a/lib/gitlab/github_import/client.rb b/lib/gitlab/github_import/client.rb index c1c338487a7..5da9befa08e 100644 --- a/lib/gitlab/github_import/client.rb +++ b/lib/gitlab/github_import/client.rb @@ -129,6 +129,8 @@ module Gitlab # whether we are running in parallel mode or not. For more information see # `#rate_or_wait_for_rate_limit`. def with_rate_limit + return yield unless rate_limiting_enabled? + request_count_counter.increment raise_or_wait_for_rate_limit unless requests_remaining? @@ -170,6 +172,10 @@ module Gitlab octokit.rate_limit.resets_in + 5 end + def rate_limiting_enabled? + @rate_limiting_enabled ||= api_endpoint.include?('.github.com') + end + def api_endpoint custom_api_endpoint || default_api_endpoint end diff --git a/lib/gitlab/gon_helper.rb b/lib/gitlab/gon_helper.rb index 3a666c2268b..dfcdfc307b6 100644 --- a/lib/gitlab/gon_helper.rb +++ b/lib/gitlab/gon_helper.rb @@ -20,7 +20,7 @@ module Gitlab gon.gitlab_url = Gitlab.config.gitlab.url gon.revision = Gitlab::REVISION gon.gitlab_logo = ActionController::Base.helpers.asset_path('gitlab_logo.png') - gon.sprite_icons = ActionController::Base.helpers.asset_path('icons.svg') + gon.sprite_icons = IconsHelper.sprite_icon_path if current_user gon.current_user_id = current_user.id diff --git a/lib/gitlab/hook_data/issue_builder.rb b/lib/gitlab/hook_data/issue_builder.rb index de9cab80a02..196f2b6b34c 100644 --- a/lib/gitlab/hook_data/issue_builder.rb +++ b/lib/gitlab/hook_data/issue_builder.rb @@ -4,7 +4,6 @@ module Gitlab SAFE_HOOK_ATTRIBUTES = %i[ assignee_id author_id - branch_name closed_at confidential created_at diff --git a/lib/gitlab/metrics/sidekiq_middleware.rb b/lib/gitlab/metrics/sidekiq_middleware.rb index 55c707d5386..df4bdf16847 100644 --- a/lib/gitlab/metrics/sidekiq_middleware.rb +++ b/lib/gitlab/metrics/sidekiq_middleware.rb @@ -11,8 +11,6 @@ module Gitlab # Old gitlad-shell messages don't provide enqueued_at/created_at attributes trans.set(:sidekiq_queue_duration, Time.now.to_f - (message['enqueued_at'] || message['created_at'] || 0)) trans.run { yield } - - worker.metrics_tags.each { |tag, value| trans.add_tag(tag, value) } if worker.respond_to?(:metrics_tags) rescue Exception => error # rubocop: disable Lint/RescueException trans.add_event(:sidekiq_exception) diff --git a/lib/tasks/import.rake b/lib/tasks/import.rake index 943cbe6d80c..aafbe52e5f8 100644 --- a/lib/tasks/import.rake +++ b/lib/tasks/import.rake @@ -101,8 +101,8 @@ end class GithubRepos def initialize(token, current_user, github_repo) - @client = Octokit::Client - .new(access_token: token, auto_paginate: true, per_page: 100) + @client = Gitlab::GithubImport::Client.new(token) + @client.octokit.auto_paginate = true @current_user = current_user @github_repo = github_repo @@ -130,7 +130,7 @@ class GithubRepos end def repos - @client.list_repositories + @client.octokit.list_repositories end end diff --git a/package.json b/package.json index 6315f9eced9..e607981143d 100644 --- a/package.json +++ b/package.json @@ -61,8 +61,6 @@ "three-orbit-controls": "^82.1.0", "three-stl-loader": "^1.0.4", "timeago.js": "^2.0.5", - "ts-loader": "^3.1.1", - "typescript": "^2.6.1", "underscore": "^1.8.3", "url-loader": "^0.5.8", "visibilityjs": "^1.2.4", diff --git a/qa/.gitignore b/qa/.gitignore index 3fec32c8427..19ec17d0005 100644 --- a/qa/.gitignore +++ b/qa/.gitignore @@ -1 +1,2 @@ tmp/ +.ruby-version diff --git a/qa/bin/qa b/qa/bin/qa index cecdeac14db..6a772e93cee 100755 --- a/qa/bin/qa +++ b/qa/bin/qa @@ -4,4 +4,4 @@ require_relative '../qa' QA::Scenario .const_get(ARGV.shift) - .perform(*ARGV) + .launch!(ARGV) @@ -18,6 +18,7 @@ module QA ## # Support files # + autoload :Bootable, 'qa/scenario/bootable' autoload :Actable, 'qa/scenario/actable' autoload :Entrypoint, 'qa/scenario/entrypoint' autoload :Template, 'qa/scenario/template' @@ -61,6 +62,7 @@ module QA module Main autoload :Entry, 'qa/page/main/entry' + autoload :Login, 'qa/page/main/login' autoload :Menu, 'qa/page/main/menu' end diff --git a/qa/qa/git/repository.rb b/qa/qa/git/repository.rb index b9e199000d6..59cd147e055 100644 --- a/qa/qa/git/repository.rb +++ b/qa/qa/git/repository.rb @@ -23,7 +23,7 @@ module QA def password=(pass) @password = pass - @uri.password = pass + @uri.password = CGI.escape(pass) end def use_default_credentials diff --git a/qa/qa/page/base.rb b/qa/qa/page/base.rb index d55326c5262..bdddfb877c5 100644 --- a/qa/qa/page/base.rb +++ b/qa/qa/page/base.rb @@ -5,7 +5,7 @@ module QA include Scenario::Actable def refresh - visit current_path + visit current_url end end end diff --git a/qa/qa/page/main/entry.rb b/qa/qa/page/main/entry.rb index a9810beeb29..ac939732b1d 100644 --- a/qa/qa/page/main/entry.rb +++ b/qa/qa/page/main/entry.rb @@ -2,9 +2,14 @@ module QA module Page module Main class Entry < Page::Base - def initialize - visit('/') + def visit_login_page + visit("#{Runtime::Scenario.gitlab_address}/users/sign_in") + wait_for_instance_to_be_ready + end + + private + def wait_for_instance_to_be_ready # This resolves cold boot / background tasks problems # start = Time.now @@ -14,18 +19,6 @@ module QA refresh end end - - def sign_in_using_credentials - if page.has_content?('Change your password') - fill_in :user_password, with: Runtime::User.password - fill_in :user_password_confirmation, with: Runtime::User.password - click_button 'Change your password' - end - - fill_in :user_login, with: Runtime::User.name - fill_in :user_password, with: Runtime::User.password - click_button 'Sign in' - end end end end diff --git a/qa/qa/page/main/login.rb b/qa/qa/page/main/login.rb new file mode 100644 index 00000000000..8b0111a78a2 --- /dev/null +++ b/qa/qa/page/main/login.rb @@ -0,0 +1,19 @@ +module QA + module Page + module Main + class Login < Page::Base + def sign_in_using_credentials + if page.has_content?('Change your password') + fill_in :user_password, with: Runtime::User.password + fill_in :user_password_confirmation, with: Runtime::User.password + click_button 'Change your password' + end + + fill_in :user_login, with: Runtime::User.name + fill_in :user_password, with: Runtime::User.password + click_button 'Sign in' + end + end + end + end +end diff --git a/qa/qa/page/mattermost/login.rb b/qa/qa/page/mattermost/login.rb index 2001dc5b230..42ab9c6f675 100644 --- a/qa/qa/page/mattermost/login.rb +++ b/qa/qa/page/mattermost/login.rb @@ -3,7 +3,7 @@ module QA module Mattermost class Login < Page::Base def initialize - visit(Runtime::Scenario.mattermost + '/login') + visit(Runtime::Scenario.mattermost_address + '/login') end def sign_in_using_oauth diff --git a/qa/qa/page/mattermost/main.rb b/qa/qa/page/mattermost/main.rb index e636d7676f4..4b8fc28e53f 100644 --- a/qa/qa/page/mattermost/main.rb +++ b/qa/qa/page/mattermost/main.rb @@ -3,7 +3,7 @@ module QA module Mattermost class Main < Page::Base def initialize - visit(Runtime::Scenario.mattermost) + visit(Runtime::Scenario.mattermost_address) end end end diff --git a/qa/qa/runtime/scenario.rb b/qa/qa/runtime/scenario.rb index 0c5e9787e17..7ef59046640 100644 --- a/qa/qa/runtime/scenario.rb +++ b/qa/qa/runtime/scenario.rb @@ -1,8 +1,28 @@ module QA module Runtime + ## + # Singleton approach to global test scenario arguments. + # module Scenario extend self - attr_accessor :mattermost + + attr_reader :attributes + + def define(attribute, value) + (@attributes ||= {}).store(attribute.to_sym, value) + + define_singleton_method(attribute) do + @attributes[attribute.to_sym].tap do |value| + if value.to_s.empty? + raise ArgumentError, "Empty `#{attribute}` attribute!" + end + end + end + end + + def method_missing(name, *) + raise ArgumentError, "Scenario attribute `#{name}` not defined!" + end end end end diff --git a/qa/qa/scenario/bootable.rb b/qa/qa/scenario/bootable.rb new file mode 100644 index 00000000000..cf8996cd597 --- /dev/null +++ b/qa/qa/scenario/bootable.rb @@ -0,0 +1,45 @@ +require 'optparse' + +module QA + module Scenario + module Bootable + Option = Struct.new(:name, :arg, :desc) + + def self.included(base) + base.extend(ClassMethods) + end + + module ClassMethods + def launch!(argv) + return self.perform(*argv) unless has_attributes? + + arguments = OptionParser.new do |parser| + options.to_a.each do |opt| + parser.on(opt.arg, opt.desc) do |value| + Runtime::Scenario.define(opt.name, value) + end + end + end + + arguments.parse!(argv) + + self.perform(**Runtime::Scenario.attributes) + end + + private + + def attribute(name, arg, desc) + options.push(Option.new(name, arg, desc)) + end + + def options + @options ||= [] + end + + def has_attributes? + options.any? + end + end + end + end +end diff --git a/qa/qa/scenario/entrypoint.rb b/qa/qa/scenario/entrypoint.rb index 33cb2696f8f..ae099fd911e 100644 --- a/qa/qa/scenario/entrypoint.rb +++ b/qa/qa/scenario/entrypoint.rb @@ -5,18 +5,10 @@ module QA # including staging and on-premises installation. # class Entrypoint < Template - def self.tags(*tags) - @tags = tags - end - - def self.get_tags - @tags - end + include Bootable def perform(address, *files) - Specs::Config.perform do |specs| - specs.address = address - end + Runtime::Scenario.define(:gitlab_address, address) ## # Perform before hooks, which are different for CE and EE @@ -24,13 +16,19 @@ module QA Runtime::Release.perform_before_hooks Specs::Runner.perform do |specs| - specs.rspec( - tty: true, - tags: self.class.get_tags, - files: files.any? ? files : 'qa/specs/features' - ) + specs.tty = true + specs.tags = self.class.get_tags + specs.files = files.any? ? files : 'qa/specs/features' end end + + def self.tags(*tags) + @tags = tags + end + + def self.get_tags + @tags + end end end end diff --git a/qa/qa/scenario/test/integration/mattermost.rb b/qa/qa/scenario/test/integration/mattermost.rb index 0220da929ce..7d0702afdb1 100644 --- a/qa/qa/scenario/test/integration/mattermost.rb +++ b/qa/qa/scenario/test/integration/mattermost.rb @@ -10,7 +10,8 @@ module QA tags :core, :mattermost def perform(address, mattermost, *files) - Runtime::Scenario.mattermost = mattermost + Runtime::Scenario.define(:mattermost_address, mattermost) + super(address, *files) end end diff --git a/qa/qa/specs/config.rb b/qa/qa/specs/config.rb index 79c681168cc..591ddde8ab9 100644 --- a/qa/qa/specs/config.rb +++ b/qa/qa/specs/config.rb @@ -9,15 +9,7 @@ require 'selenium-webdriver' module QA module Specs class Config < Scenario::Template - attr_writer :address - - def initialize - @address = ENV['GITLAB_URL'] - end - def perform - raise 'Please configure GitLab address!' unless @address - configure_rspec! configure_capybara! end @@ -56,7 +48,6 @@ module QA end Capybara.configure do |config| - config.app_host = @address config.default_driver = :chrome config.javascript_driver = :chrome config.default_max_wait_time = 4 diff --git a/qa/qa/specs/features/login/standard_spec.rb b/qa/qa/specs/features/login/standard_spec.rb index ba19ce17ee5..b155708c387 100644 --- a/qa/qa/specs/features/login/standard_spec.rb +++ b/qa/qa/specs/features/login/standard_spec.rb @@ -1,7 +1,8 @@ module QA feature 'standard root login', :core do scenario 'user logs in using credentials' do - Page::Main::Entry.act { sign_in_using_credentials } + Page::Main::Entry.act { visit_login_page } + Page::Main::Login.act { sign_in_using_credentials } # TODO, since `Signed in successfully` message was removed # this is the only way to tell if user is signed in correctly. diff --git a/qa/qa/specs/features/mattermost/group_create_spec.rb b/qa/qa/specs/features/mattermost/group_create_spec.rb index c4afd83c8e4..853a9a6a4f4 100644 --- a/qa/qa/specs/features/mattermost/group_create_spec.rb +++ b/qa/qa/specs/features/mattermost/group_create_spec.rb @@ -1,7 +1,8 @@ module QA feature 'create a new group', :mattermost do scenario 'creating a group with a mattermost team' do - Page::Main::Entry.act { sign_in_using_credentials } + Page::Main::Entry.act { visit_login_page } + Page::Main::Login.act { sign_in_using_credentials } Page::Main::Menu.act { go_to_groups } Page::Dashboard::Groups.perform do |page| diff --git a/qa/qa/specs/features/mattermost/login_spec.rb b/qa/qa/specs/features/mattermost/login_spec.rb index a89a6a3d1cf..92f91cb2725 100644 --- a/qa/qa/specs/features/mattermost/login_spec.rb +++ b/qa/qa/specs/features/mattermost/login_spec.rb @@ -1,7 +1,8 @@ module QA feature 'logging in to Mattermost', :mattermost do scenario 'can use gitlab oauth' do - Page::Main::Entry.act { sign_in_using_credentials } + Page::Main::Entry.act { visit_login_page } + Page::Main::Login.act { sign_in_using_credentials } Page::Mattermost::Login.act { sign_in_using_oauth } Page::Mattermost::Main.perform do |page| diff --git a/qa/qa/specs/features/project/create_spec.rb b/qa/qa/specs/features/project/create_spec.rb index 27eb22f15a6..aba0c2b4c14 100644 --- a/qa/qa/specs/features/project/create_spec.rb +++ b/qa/qa/specs/features/project/create_spec.rb @@ -1,7 +1,8 @@ module QA feature 'create a new project', :core do scenario 'user creates a new project' do - Page::Main::Entry.act { sign_in_using_credentials } + Page::Main::Entry.act { visit_login_page } + Page::Main::Login.act { sign_in_using_credentials } Scenario::Gitlab::Project::Create.perform do |project| project.name = 'awesome-project' diff --git a/qa/qa/specs/features/repository/clone_spec.rb b/qa/qa/specs/features/repository/clone_spec.rb index 3571173783d..5cc3b3b9c1b 100644 --- a/qa/qa/specs/features/repository/clone_spec.rb +++ b/qa/qa/specs/features/repository/clone_spec.rb @@ -9,7 +9,8 @@ module QA end before do - Page::Main::Entry.act { sign_in_using_credentials } + Page::Main::Entry.act { visit_login_page } + Page::Main::Login.act { sign_in_using_credentials } Scenario::Gitlab::Project::Create.perform do |scenario| scenario.name = 'project-with-code' diff --git a/qa/qa/specs/features/repository/push_spec.rb b/qa/qa/specs/features/repository/push_spec.rb index 0e691fb0d75..30935dc1e13 100644 --- a/qa/qa/specs/features/repository/push_spec.rb +++ b/qa/qa/specs/features/repository/push_spec.rb @@ -2,7 +2,8 @@ module QA feature 'push code to repository', :core do context 'with regular account over http' do scenario 'user pushes code to the repository' do - Page::Main::Entry.act { sign_in_using_credentials } + Page::Main::Entry.act { visit_login_page } + Page::Main::Login.act { sign_in_using_credentials } Scenario::Gitlab::Project::Create.perform do |scenario| scenario.name = 'project_with_code' diff --git a/qa/qa/specs/runner.rb b/qa/qa/specs/runner.rb index 2aa18d5d3a1..f98b8f88e9a 100644 --- a/qa/qa/specs/runner.rb +++ b/qa/qa/specs/runner.rb @@ -2,16 +2,22 @@ require 'rspec/core' module QA module Specs - class Runner - include Scenario::Actable + class Runner < Scenario::Template + attr_accessor :tty, :tags, :files - def rspec(tty: false, tags: [], files: ['qa/specs/features']) + def initialize + @tty = false + @tags = [] + @files = ['qa/specs/features'] + end + + def perform args = [] - args << '--tty' if tty - tags.to_a.each do |tag| - args << ['-t', tag.to_s] - end - args << files + args.push('--tty') if tty + tags.to_a.each { |tag| args.push(['-t', tag.to_s]) } + args.push(files) + + Specs::Config.perform RSpec::Core::Runner.run(args.flatten, $stderr, $stdout).tap do |status| abort if status.nonzero? diff --git a/qa/spec/runtime/scenario_spec.rb b/qa/spec/runtime/scenario_spec.rb new file mode 100644 index 00000000000..7009192bcc0 --- /dev/null +++ b/qa/spec/runtime/scenario_spec.rb @@ -0,0 +1,27 @@ +describe QA::Runtime::Scenario do + subject do + Module.new.extend(described_class) + end + + it 'makes it possible to define global scenario attributes' do + subject.define(:my_attribute, 'some-value') + subject.define(:another_attribute, 'another-value') + + expect(subject.my_attribute).to eq 'some-value' + expect(subject.another_attribute).to eq 'another-value' + expect(subject.attributes) + .to eq(my_attribute: 'some-value', another_attribute: 'another-value') + end + + it 'raises error when attribute is not known' do + expect { subject.invalid_accessor } + .to raise_error ArgumentError, /invalid_accessor/ + end + + it 'raises error when attribute is empty' do + subject.define(:empty_attribute, '') + + expect { subject.empty_attribute } + .to raise_error ArgumentError, /empty_attribute/ + end +end diff --git a/qa/spec/scenario/bootable_spec.rb b/qa/spec/scenario/bootable_spec.rb new file mode 100644 index 00000000000..273aac7677e --- /dev/null +++ b/qa/spec/scenario/bootable_spec.rb @@ -0,0 +1,24 @@ +describe QA::Scenario::Bootable do + subject do + Class.new(QA::Scenario::Template) + .include(described_class) + end + + it 'makes it possible to define the scenario attribute' do + subject.class_eval do + attribute :something, '--something SOMETHING', 'Some attribute' + attribute :another, '--another ANOTHER', 'Some other attribute' + end + + expect(subject).to receive(:perform) + .with(something: 'test', another: 'other') + + subject.launch!(%w[--another other --something test]) + end + + it 'does not require attributes to be defined' do + expect(subject).to receive(:perform).with('some', 'argv') + + subject.launch!(%w[some argv]) + end +end diff --git a/qa/spec/scenario/entrypoint_spec.rb b/qa/spec/scenario/entrypoint_spec.rb index 3fd068b641c..aec79dcea04 100644 --- a/qa/spec/scenario/entrypoint_spec.rb +++ b/qa/spec/scenario/entrypoint_spec.rb @@ -6,31 +6,30 @@ describe QA::Scenario::Entrypoint do end context '#perform' do - let(:config) { spy('Specs::Config') } + let(:arguments) { spy('Runtime::Scenario') } let(:release) { spy('Runtime::Release') } let(:runner) { spy('Specs::Runner') } before do - allow(config).to receive(:perform) { |&block| block.call config } - allow(runner).to receive(:perform) { |&block| block.call runner } - - stub_const('QA::Specs::Config', config) stub_const('QA::Runtime::Release', release) + stub_const('QA::Runtime::Scenario', arguments) stub_const('QA::Specs::Runner', runner) + + allow(runner).to receive(:perform).and_yield(runner) end - it 'should set address' do + it 'sets an address of the subject' do subject.perform("hello") - expect(config).to have_received(:address=).with("hello") + expect(arguments).to have_received(:define) + .with(:gitlab_address, "hello") end context 'no paths' do it 'should call runner with default arguments' do subject.perform("test") - expect(runner).to have_received(:rspec) - .with(hash_including(files: 'qa/specs/features')) + expect(runner).to have_received(:files=).with('qa/specs/features') end end @@ -38,8 +37,7 @@ describe QA::Scenario::Entrypoint do it 'should call runner with paths' do subject.perform('test', 'path1', 'path2') - expect(runner).to have_received(:rspec) - .with(hash_including(files: %w(path1 path2))) + expect(runner).to have_received(:files=).with(%w[path1 path2]) end end end diff --git a/scripts/create_mysql_user.sh b/scripts/create_mysql_user.sh new file mode 100644 index 00000000000..28f6cfb50ae --- /dev/null +++ b/scripts/create_mysql_user.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +mysql --user=root --host=mysql <<EOF +CREATE DATABASE IF NOT EXISTS gitlabhq_test; +CREATE USER IF NOT EXISTS 'gitlab'@'%'; +GRANT ALL PRIVILEGES ON gitlabhq_test.* TO 'gitlab'@'%'; +FLUSH PRIVILEGES; +EOF diff --git a/scripts/create_postgres_user.sh b/scripts/create_postgres_user.sh new file mode 100644 index 00000000000..8a744df3226 --- /dev/null +++ b/scripts/create_postgres_user.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +psql -h postgres -U postgres postgres <<EOF +DROP DATABASE IF EXISTS gitlabhq_test; +CREATE DATABASE gitlabhq_test; +CREATE USER gitlab; +GRANT ALL PRIVILEGES ON DATABASE gitlabhq_test TO gitlab; +EOF diff --git a/scripts/prepare_build.sh b/scripts/prepare_build.sh index 7abadef5e89..36bcf087cd9 100644 --- a/scripts/prepare_build.sh +++ b/scripts/prepare_build.sh @@ -1,6 +1,7 @@ . scripts/utils.sh export SETUP_DB=${SETUP_DB:-true} +export CREATE_DB_USER=${CREATE_DB_USER:-$SETUP_DB} export USE_BUNDLE_INSTALL=${USE_BUNDLE_INSTALL:-true} export BUNDLE_INSTALL_FLAGS="--without production --jobs $(nproc) --path vendor --retry 3 --quiet" @@ -26,6 +27,9 @@ fi cp config/database.yml.$GITLAB_DATABASE config/database.yml +# Set user to a non-superuser to ensure we test permissions +sed -i 's/username: root/username: gitlab/g' config/database.yml + if [ "$GITLAB_DATABASE" = 'postgresql' ]; then sed -i 's/localhost/postgres/g' config/database.yml else # Assume it's mysql @@ -44,6 +48,16 @@ sed -i 's/localhost/redis/g' config/redis.queues.yml cp config/redis.shared_state.yml.example config/redis.shared_state.yml sed -i 's/localhost/redis/g' config/redis.shared_state.yml +# Some tasks (e.g. db:seed_fu) need to have a properly-configured database +# user but not necessarily a full schema loaded +if [ "$CREATE_DB_USER" != "false" ]; then + if [ "$GITLAB_DATABASE" = 'postgresql' ]; then + . scripts/create_postgres_user.sh + else + . scripts/create_mysql_user.sh + fi +fi + if [ "$SETUP_DB" != "false" ]; then bundle exec rake db:drop db:create db:schema:load db:migrate diff --git a/spec/controllers/dashboard/todos_controller_spec.rb b/spec/controllers/dashboard/todos_controller_spec.rb index d862e1447e3..f9faa4fa59a 100644 --- a/spec/controllers/dashboard/todos_controller_spec.rb +++ b/spec/controllers/dashboard/todos_controller_spec.rb @@ -44,11 +44,11 @@ describe Dashboard::TodosController do context 'when using pagination' do let(:last_page) { user.todos.page.total_pages } - let!(:issues) { create_list(:issue, 2, project: project, assignees: [user]) } + let!(:issues) { create_list(:issue, 3, project: project, assignees: [user]) } before do issues.each { |issue| todo_service.new_issue(issue, user) } - allow(Kaminari.config).to receive(:default_per_page).and_return(1) + allow(Kaminari.config).to receive(:default_per_page).and_return(2) end it 'redirects to last_page if page number is larger than number of pages' do diff --git a/spec/features/issues/issue_detail_spec.rb b/spec/features/issues/issue_detail_spec.rb index 6fbee0ebcb5..4224a8fe5d4 100644 --- a/spec/features/issues/issue_detail_spec.rb +++ b/spec/features/issues/issue_detail_spec.rb @@ -1,9 +1,9 @@ require 'rails_helper' feature 'Issue Detail', :js do - let(:user) { create(:user) } - let(:project) { create(:project, :public) } - let(:issue) { create(:issue, project: project, author: user) } + let(:user) { create(:user) } + let(:project) { create(:project, :public) } + let(:issue) { create(:issue, project: project, author: user) } context 'when user displays the issue' do before do @@ -27,6 +27,7 @@ feature 'Issue Detail', :js do click_link 'Edit' fill_in 'issuable-title', with: 'issue title' click_button 'Save' + wait_for_requests Users::DestroyService.new(user).execute(user) diff --git a/spec/features/merge_requests/create_new_mr_spec.rb b/spec/features/merge_requests/create_new_mr_spec.rb index 5402d61da54..db5ce2d11a8 100644 --- a/spec/features/merge_requests/create_new_mr_spec.rb +++ b/spec/features/merge_requests/create_new_mr_spec.rb @@ -67,6 +67,28 @@ feature 'Create New Merge Request', :js do expect(page).to have_content 'git checkout -b orphaned-branch origin/orphaned-branch' end + it 'allows filtering multiple dropdowns' do + visit project_new_merge_request_path(project) + + first('.js-source-branch').click + + input = find('.dropdown-source-branch .dropdown-input-field') + input.click + input.send_keys('orphaned-branch') + + find('.dropdown-source-branch .dropdown-content li', match: :first) + source_items = all('.dropdown-source-branch .dropdown-content li') + + expect(source_items.count).to eq(1) + + first('.js-target-branch').click + + find('.dropdown-target-branch .dropdown-content li', match: :first) + target_items = all('.dropdown-target-branch .dropdown-content li') + + expect(target_items.count).to be > 1 + end + context 'when target project cannot be viewed by the current user' do it 'does not leak the private project name & namespace' do private_project = create(:project, :private, :repository) diff --git a/spec/features/merge_requests/filter_by_labels_spec.rb b/spec/features/merge_requests/filter_by_labels_spec.rb index 9912e8165e6..7adae08e499 100644 --- a/spec/features/merge_requests/filter_by_labels_spec.rb +++ b/spec/features/merge_requests/filter_by_labels_spec.rb @@ -79,22 +79,6 @@ feature 'Merge Request filtering by Labels', :js do end end - context 'clear button' do - before do - input_filtered_search('label:~bug') - end - - it 'allows user to remove filtered labels' do - first('.clear-search').click - filtered_search.send_keys(:enter) - - expect(page).to have_issuable_counts(open: 3, closed: 0, all: 3) - expect(page).to have_content "Bugfix2" - expect(page).to have_content "Feature1" - expect(page).to have_content "Bugfix1" - end - end - context 'filter dropdown' do it 'filters by label name' do init_label_search diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb index 7a241b02d28..5c5d53877a6 100644 --- a/spec/helpers/application_helper_spec.rb +++ b/spec/helpers/application_helper_spec.rb @@ -4,8 +4,6 @@ require 'spec_helper' describe ApplicationHelper do include UploadHelpers - let(:gitlab_host) { "http://#{Gitlab.config.gitlab.host}" } - describe 'current_controller?' do it 'returns true when controller matches argument' do stub_controller_name('foo') @@ -57,30 +55,11 @@ describe ApplicationHelper do end describe 'project_icon' do - let(:asset_host) { 'http://assets' } - it 'returns an url for the avatar' do project = create(:project, :public, avatar: File.open(uploaded_image_temp_path)) - avatar_url = "/uploads/-/system/project/avatar/#{project.id}/banana_sample.gif" - - expect(helper.project_icon(project.full_path).to_s) - .to eq "<img data-src=\"#{avatar_url}\" class=\" lazy\" src=\"#{LazyImageTagHelper.placeholder_image}\" />" - - allow(ActionController::Base).to receive(:asset_host).and_return(asset_host) - avatar_url = "#{asset_host}/uploads/-/system/project/avatar/#{project.id}/banana_sample.gif" - - expect(helper.project_icon(project.full_path).to_s) - .to eq "<img data-src=\"#{avatar_url}\" class=\" lazy\" src=\"#{LazyImageTagHelper.placeholder_image}\" />" - end - - it 'gives uploaded icon when present' do - project = create(:project) - allow_any_instance_of(Project).to receive(:avatar_in_git).and_return(true) - - avatar_url = "#{gitlab_host}#{project_avatar_path(project)}" expect(helper.project_icon(project.full_path).to_s) - .to eq "<img data-src=\"#{avatar_url}\" class=\" lazy\" src=\"#{LazyImageTagHelper.placeholder_image}\" />" + .to eq "<img data-src=\"#{project.avatar.url}\" class=\" lazy\" src=\"#{LazyImageTagHelper.placeholder_image}\" />" end end @@ -91,40 +70,7 @@ describe ApplicationHelper do context 'when there is a matching user' do it 'returns a relative URL for the avatar' do expect(helper.avatar_icon(user.email).to_s) - .to eq("/uploads/-/system/user/avatar/#{user.id}/banana_sample.gif") - end - - context 'when an asset_host is set in the config' do - let(:asset_host) { 'http://assets' } - - before do - allow(ActionController::Base).to receive(:asset_host).and_return(asset_host) - end - - it 'returns an absolute URL on that asset host' do - expect(helper.avatar_icon(user.email, only_path: false).to_s) - .to eq("#{asset_host}/uploads/-/system/user/avatar/#{user.id}/banana_sample.gif") - end - end - - context 'when only_path is set to false' do - it 'returns an absolute URL for the avatar' do - expect(helper.avatar_icon(user.email, only_path: false).to_s) - .to eq("#{gitlab_host}/uploads/-/system/user/avatar/#{user.id}/banana_sample.gif") - end - end - - context 'when the GitLab instance is at a relative URL' do - before do - stub_config_setting(relative_url_root: '/gitlab') - # Must be stubbed after the stub above, and separately - stub_config_setting(url: Settings.send(:build_gitlab_url)) - end - - it 'returns a relative URL with the correct prefix' do - expect(helper.avatar_icon(user.email).to_s) - .to eq("/gitlab/uploads/-/system/user/avatar/#{user.id}/banana_sample.gif") - end + .to eq(user.avatar.url) end end @@ -138,18 +84,9 @@ describe ApplicationHelper do end describe 'using a user' do - context 'when only_path is true' do - it 'returns a relative URL for the avatar' do - expect(helper.avatar_icon(user, only_path: true).to_s) - .to eq("/uploads/-/system/user/avatar/#{user.id}/banana_sample.gif") - end - end - - context 'when only_path is false' do - it 'returns an absolute URL for the avatar' do - expect(helper.avatar_icon(user, only_path: false).to_s) - .to eq("#{gitlab_host}/uploads/-/system/user/avatar/#{user.id}/banana_sample.gif") - end + it 'returns a relative URL for the avatar' do + expect(helper.avatar_icon(user).to_s) + .to eq(user.avatar.url) end end end diff --git a/spec/helpers/groups_helper_spec.rb b/spec/helpers/groups_helper_spec.rb index 97f0ed4904e..32432ee1e81 100644 --- a/spec/helpers/groups_helper_spec.rb +++ b/spec/helpers/groups_helper_spec.rb @@ -3,8 +3,6 @@ require 'spec_helper' describe GroupsHelper do include ApplicationHelper - let(:asset_host) { 'http://assets' } - describe 'group_icon' do avatar_file_path = File.join(Rails.root, 'spec', 'fixtures', 'banana_sample.gif') @@ -13,16 +11,8 @@ describe GroupsHelper do group.avatar = fixture_file_upload(avatar_file_path) group.save! - avatar_url = "/uploads/-/system/group/avatar/#{group.id}/banana_sample.gif" - - expect(helper.group_icon(group).to_s) - .to eq "<img data-src=\"#{avatar_url}\" class=\" lazy\" src=\"#{LazyImageTagHelper.placeholder_image}\" />" - - allow(ActionController::Base).to receive(:asset_host).and_return(asset_host) - avatar_url = "#{asset_host}/uploads/-/system/group/avatar/#{group.id}/banana_sample.gif" - expect(helper.group_icon(group).to_s) - .to eq "<img data-src=\"#{avatar_url}\" class=\" lazy\" src=\"#{LazyImageTagHelper.placeholder_image}\" />" + .to eq "<img data-src=\"#{group.avatar.url}\" class=\" lazy\" src=\"#{LazyImageTagHelper.placeholder_image}\" />" end end @@ -34,25 +24,7 @@ describe GroupsHelper do group.avatar = fixture_file_upload(avatar_file_path) group.save! expect(group_icon_url(group.path).to_s) - .to match("/uploads/-/system/group/avatar/#{group.id}/banana_sample.gif") - end - - it 'returns an CDN url for the avatar' do - allow(ActionController::Base).to receive(:asset_host).and_return(asset_host) - group = create(:group) - group.avatar = fixture_file_upload(avatar_file_path) - group.save! - expect(group_icon_url(group.path).to_s) - .to match("#{asset_host}/uploads/-/system/group/avatar/#{group.id}/banana_sample.gif") - end - - it 'returns an based url for the avatar if private' do - allow(ActionController::Base).to receive(:asset_host).and_return(asset_host) - group = create(:group, :private) - group.avatar = fixture_file_upload(avatar_file_path) - group.save! - expect(group_icon_url(group.path).to_s) - .to match("/uploads/-/system/group/avatar/#{group.id}/banana_sample.gif") + .to match(group.avatar.url) end it 'gives default avatar_icon when no avatar is present' do diff --git a/spec/helpers/icons_helper_spec.rb b/spec/helpers/icons_helper_spec.rb index 3d79dac284f..2f23ed55d99 100644 --- a/spec/helpers/icons_helper_spec.rb +++ b/spec/helpers/icons_helper_spec.rb @@ -1,6 +1,8 @@ require 'spec_helper' describe IconsHelper do + let(:icons_path) { ActionController::Base.helpers.image_path("icons.svg") } + describe 'icon' do it 'returns aria-hidden by default' do star = icon('star') @@ -16,22 +18,42 @@ describe IconsHelper do end end + describe 'sprite_icon_path' do + it 'returns relative path' do + expect(sprite_icon_path) + .to eq icons_path + end + + context 'when an asset_host is set in the config it will return an absolute local URL' do + let(:asset_host) { 'http://assets' } + + before do + allow(ActionController::Base).to receive(:asset_host).and_return(asset_host) + end + + it 'returns an absolute URL on that asset host' do + expect(sprite_icon_path) + .to eq ActionController::Base.helpers.image_path("icons.svg", host: Gitlab.config.gitlab.url) + end + end + end + describe 'sprite_icon' do icon_name = 'clock' it 'returns svg icon html' do expect(sprite_icon(icon_name).to_s) - .to eq "<svg><use xlink:href=\"/images/icons.svg##{icon_name}\"></use></svg>" + .to eq "<svg><use xlink:href=\"#{icons_path}##{icon_name}\"></use></svg>" end it 'returns svg icon html + size classes' do expect(sprite_icon(icon_name, size: 72).to_s) - .to eq "<svg class=\"s72\"><use xlink:href=\"/images/icons.svg##{icon_name}\"></use></svg>" + .to eq "<svg class=\"s72\"><use xlink:href=\"#{icons_path}##{icon_name}\"></use></svg>" end it 'returns svg icon html + size classes + additional class' do expect(sprite_icon(icon_name, size: 72, css_class: 'icon-danger').to_s) - .to eq "<svg class=\"s72 icon-danger\"><use xlink:href=\"/images/icons.svg##{icon_name}\"></use></svg>" + .to eq "<svg class=\"s72 icon-danger\"><use xlink:href=\"#{icons_path}##{icon_name}\"></use></svg>" end end diff --git a/spec/javascripts/filtered_search/filtered_search_manager_spec.js b/spec/javascripts/filtered_search/filtered_search_manager_spec.js index f209328dee1..230c15e5de6 100644 --- a/spec/javascripts/filtered_search/filtered_search_manager_spec.js +++ b/spec/javascripts/filtered_search/filtered_search_manager_spec.js @@ -396,6 +396,25 @@ describe('Filtered Search Manager', () => { }); }); + describe('Clearing search', () => { + beforeEach(() => { + initializeManager(); + }); + + it('Clicking the "x" clear button, clears the input', () => { + const inputValue = 'label:~bug '; + manager.filteredSearchInput.value = inputValue; + manager.filteredSearchInput.dispatchEvent(new Event('input')); + + expect(gl.DropdownUtils.getSearchQuery()).toEqual(inputValue); + + manager.clearSearchButton.click(); + + expect(manager.filteredSearchInput.value).toEqual(''); + expect(gl.DropdownUtils.getSearchQuery()).toEqual(''); + }); + }); + describe('toggleInputContainerFocus', () => { beforeEach(() => { initializeManager(); diff --git a/spec/javascripts/lib/utils/text_markdown_spec.js b/spec/javascripts/lib/utils/text_markdown_spec.js new file mode 100644 index 00000000000..a95a7e2a5be --- /dev/null +++ b/spec/javascripts/lib/utils/text_markdown_spec.js @@ -0,0 +1,62 @@ +import textUtils from '~/lib/utils/text_markdown'; + +describe('init markdown', () => { + let textArea; + + beforeAll(() => { + textArea = document.createElement('textarea'); + document.querySelector('body').appendChild(textArea); + textArea.focus(); + }); + + afterAll(() => { + textArea.parentNode.removeChild(textArea); + }); + + describe('without selection', () => { + it('inserts the tag on an empty line', () => { + const initialValue = ''; + + textArea.value = initialValue; + textArea.selectionStart = 0; + textArea.selectionEnd = 0; + + textUtils.insertText(textArea, textArea.value, '*', null, '', false); + + expect(textArea.value).toEqual(`${initialValue}* `); + }); + + it('inserts the tag on a new line if the current one is not empty', () => { + const initialValue = 'some text'; + + textArea.value = initialValue; + textArea.setSelectionRange(initialValue.length, initialValue.length); + + textUtils.insertText(textArea, textArea.value, '*', null, '', false); + + expect(textArea.value).toEqual(`${initialValue}\n* `); + }); + + it('inserts the tag on the same line if the current line only contains spaces', () => { + const initialValue = ' '; + + textArea.value = initialValue; + textArea.setSelectionRange(initialValue.length, initialValue.length); + + textUtils.insertText(textArea, textArea.value, '*', null, '', false); + + expect(textArea.value).toEqual(`${initialValue}* `); + }); + + it('inserts the tag on the same line if the current line only contains tabs', () => { + const initialValue = '\t\t\t'; + + textArea.value = initialValue; + textArea.setSelectionRange(initialValue.length, initialValue.length); + + textUtils.insertText(textArea, textArea.value, '*', null, '', false); + + expect(textArea.value).toEqual(`${initialValue}* `); + }); + }); +}); diff --git a/spec/javascripts/lib/utils/text_utility_spec.js b/spec/javascripts/lib/utils/text_utility_spec.js index 829b3ef5735..b21bd958f90 100644 --- a/spec/javascripts/lib/utils/text_utility_spec.js +++ b/spec/javascripts/lib/utils/text_utility_spec.js @@ -1,109 +1,57 @@ -import { highCountTrim } from '~/lib/utils/text_utility'; +import * as textUtils from '~/lib/utils/text_utility'; describe('text_utility', () => { - describe('gl.text.getTextWidth', () => { - it('returns zero width when no text is passed', () => { - expect(gl.text.getTextWidth('')).toBe(0); + describe('addDelimiter', () => { + it('should add a delimiter to the given string', () => { + expect(textUtils.addDelimiter('1234')).toEqual('1,234'); + expect(textUtils.addDelimiter('222222')).toEqual('222,222'); }); - it('returns zero width when no text is passed and font is passed', () => { - expect(gl.text.getTextWidth('', '100px sans-serif')).toBe(0); - }); - - it('returns width when text is passed', () => { - expect(gl.text.getTextWidth('foo') > 0).toBe(true); - }); - - it('returns bigger width when font is larger', () => { - const largeFont = gl.text.getTextWidth('foo', '100px sans-serif'); - const regular = gl.text.getTextWidth('foo', '10px sans-serif'); - expect(largeFont > regular).toBe(true); - }); - }); - - describe('gl.text.pluralize', () => { - it('returns pluralized', () => { - expect(gl.text.pluralize('test', 2)).toBe('tests'); - }); - - it('returns pluralized when count is 0', () => { - expect(gl.text.pluralize('test', 0)).toBe('tests'); - }); - - it('does not return pluralized', () => { - expect(gl.text.pluralize('test', 1)).toBe('test'); + it('should not add a delimiter if string contains no numbers', () => { + expect(textUtils.addDelimiter('aaaa')).toEqual('aaaa'); }); }); describe('highCountTrim', () => { it('returns 99+ for count >= 100', () => { - expect(highCountTrim(105)).toBe('99+'); - expect(highCountTrim(100)).toBe('99+'); + expect(textUtils.highCountTrim(105)).toBe('99+'); + expect(textUtils.highCountTrim(100)).toBe('99+'); }); it('returns exact number for count < 100', () => { - expect(highCountTrim(45)).toBe(45); + expect(textUtils.highCountTrim(45)).toBe(45); }); }); - describe('gl.text.insertText', () => { - let textArea; - - beforeAll(() => { - textArea = document.createElement('textarea'); - document.querySelector('body').appendChild(textArea); - textArea.focus(); + describe('humanize', () => { + it('should remove underscores and uppercase the first letter', () => { + expect(textUtils.humanize('foo_bar')).toEqual('Foo bar'); }); + }); - afterAll(() => { - textArea.parentNode.removeChild(textArea); + describe('pluralize', () => { + it('should pluralize given string', () => { + expect(textUtils.pluralize('test', 2)).toBe('tests'); }); - describe('without selection', () => { - it('inserts the tag on an empty line', () => { - const initialValue = ''; - - textArea.value = initialValue; - textArea.selectionStart = 0; - textArea.selectionEnd = 0; - - gl.text.insertText(textArea, textArea.value, '*', null, '', false); - - expect(textArea.value).toEqual(`${initialValue}* `); - }); - - it('inserts the tag on a new line if the current one is not empty', () => { - const initialValue = 'some text'; - - textArea.value = initialValue; - textArea.setSelectionRange(initialValue.length, initialValue.length); - - gl.text.insertText(textArea, textArea.value, '*', null, '', false); - - expect(textArea.value).toEqual(`${initialValue}\n* `); - }); - - it('inserts the tag on the same line if the current line only contains spaces', () => { - const initialValue = ' '; - - textArea.value = initialValue; - textArea.setSelectionRange(initialValue.length, initialValue.length); - - gl.text.insertText(textArea, textArea.value, '*', null, '', false); - - expect(textArea.value).toEqual(`${initialValue}* `); - }); - - it('inserts the tag on the same line if the current line only contains tabs', () => { - const initialValue = '\t\t\t'; + it('should pluralize when count is 0', () => { + expect(textUtils.pluralize('test', 0)).toBe('tests'); + }); - textArea.value = initialValue; - textArea.setSelectionRange(initialValue.length, initialValue.length); + it('should not pluralize when count is 1', () => { + expect(textUtils.pluralize('test', 1)).toBe('test'); + }); + }); - gl.text.insertText(textArea, textArea.value, '*', null, '', false); + describe('dasherize', () => { + it('should replace underscores with dashes', () => { + expect(textUtils.dasherize('foo_bar_foo')).toEqual('foo-bar-foo'); + }); + }); - expect(textArea.value).toEqual(`${initialValue}* `); - }); + describe('slugify', () => { + it('should remove accents and convert to lower case', () => { + expect(textUtils.slugify('João')).toEqual('joão'); }); }); }); diff --git a/spec/javascripts/notes/components/issue_comment_form_spec.js b/spec/javascripts/notes/components/issue_comment_form_spec.js index a26fc8f63cc..db75262b562 100644 --- a/spec/javascripts/notes/components/issue_comment_form_spec.js +++ b/spec/javascripts/notes/components/issue_comment_form_spec.js @@ -55,6 +55,25 @@ describe('issue_comment_form component', () => { expect(vm.toggleIssueState).toHaveBeenCalled(); }); + + it('should disable action button whilst submitting', (done) => { + const saveNotePromise = Promise.resolve(); + vm.note = 'hello world'; + spyOn(vm, 'saveNote').and.returnValue(saveNotePromise); + spyOn(vm, 'stopPolling'); + + const actionButton = vm.$el.querySelector('.js-action-button'); + + vm.handleSave(); + + Vue.nextTick() + .then(() => expect(actionButton.disabled).toBeTruthy()) + .then(saveNotePromise) + .then(Vue.nextTick) + .then(() => expect(actionButton.disabled).toBeFalsy()) + .then(done) + .catch(done.fail); + }); }); describe('textarea', () => { diff --git a/spec/lib/gitlab/git/remote_repository_spec.rb b/spec/lib/gitlab/git/remote_repository_spec.rb new file mode 100644 index 00000000000..0506210887c --- /dev/null +++ b/spec/lib/gitlab/git/remote_repository_spec.rb @@ -0,0 +1,99 @@ +require 'spec_helper' + +describe Gitlab::Git::RemoteRepository, seed_helper: true do + let(:repository) { Gitlab::Git::Repository.new('default', TEST_REPO_PATH, '') } + subject { described_class.new(repository) } + + describe '#empty_repo?' do + using RSpec::Parameterized::TableSyntax + + where(:repository, :result) do + Gitlab::Git::Repository.new('default', TEST_REPO_PATH, '') | false + Gitlab::Git::Repository.new('default', 'does-not-exist.git', '') | true + end + + with_them do + it { expect(subject.empty_repo?).to eq(result) } + end + end + + describe '#commit_id' do + it 'returns an OID if the revision exists' do + expect(subject.commit_id('v1.0.0')).to eq('6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9') + end + + it 'is nil when the revision does not exist' do + expect(subject.commit_id('does-not-exist')).to be_nil + end + end + + describe '#branch_exists?' do + using RSpec::Parameterized::TableSyntax + + where(:branch, :result) do + 'master' | true + 'does-not-exist' | false + end + + with_them do + it { expect(subject.branch_exists?(branch)).to eq(result) } + end + end + + describe '#same_repository?' do + using RSpec::Parameterized::TableSyntax + + where(:other_repository, :result) do + repository | true + Gitlab::Git::Repository.new(repository.storage, repository.relative_path, '') | true + Gitlab::Git::Repository.new('broken', TEST_REPO_PATH, '') | false + Gitlab::Git::Repository.new(repository.storage, 'wrong/relative-path.git', '') | false + Gitlab::Git::Repository.new('broken', 'wrong/relative-path.git', '') | false + end + + with_them do + it { expect(subject.same_repository?(other_repository)).to eq(result) } + end + end + + describe '#fetch_env' do + let(:remote_repository) { described_class.new(repository) } + + let(:gitaly_client) { double(:gitaly_client) } + let(:address) { 'fake-address' } + let(:token) { 'fake-token' } + + subject { remote_repository.fetch_env } + + before do + allow(remote_repository).to receive(:gitaly_client).and_return(gitaly_client) + + expect(gitaly_client).to receive(:address).with(repository.storage).and_return(address) + expect(gitaly_client).to receive(:token).with(repository.storage).and_return(token) + end + + it { expect(subject).to be_a(Hash) } + it { expect(subject['GITALY_ADDRESS']).to eq(address) } + it { expect(subject['GITALY_TOKEN']).to eq(token) } + it { expect(subject['GITALY_WD']).to eq(Dir.pwd) } + + it 'creates a plausible GIT_SSH_COMMAND' do + git_ssh_command = subject['GIT_SSH_COMMAND'] + + expect(git_ssh_command).to start_with('/') + expect(git_ssh_command).to end_with('/gitaly-ssh upload-pack') + end + + it 'creates a plausible GITALY_PAYLOAD' do + req = Gitaly::SSHUploadPackRequest.decode_json(subject['GITALY_PAYLOAD']) + + expect(remote_repository.gitaly_repository).to eq(req.repository) + end + + context 'when the token is blank' do + let(:token) { '' } + + it { expect(subject.keys).not_to include('GITALY_TOKEN') } + end + end +end diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb index ee14b528ec2..5d990b42c24 100644 --- a/spec/lib/gitlab/git/repository_spec.rb +++ b/spec/lib/gitlab/git/repository_spec.rb @@ -449,7 +449,6 @@ describe Gitlab::Git::Repository, seed_helper: true do let(:repository) { Gitlab::Git::Repository.new('default', TEST_MUTABLE_REPO_PATH, '') } after do - FileUtils.rm_rf(TEST_MUTABLE_REPO_PATH) ensure_seeds end @@ -484,7 +483,6 @@ describe Gitlab::Git::Repository, seed_helper: true do let(:repository) { Gitlab::Git::Repository.new('default', TEST_MUTABLE_REPO_PATH, '') } after do - FileUtils.rm_rf(TEST_MUTABLE_REPO_PATH) ensure_seeds end @@ -544,7 +542,6 @@ describe Gitlab::Git::Repository, seed_helper: true do end after(:all) do - FileUtils.rm_rf(TEST_MUTABLE_REPO_PATH) ensure_seeds end end @@ -570,7 +567,6 @@ describe Gitlab::Git::Repository, seed_helper: true do end after(:all) do - FileUtils.rm_rf(TEST_MUTABLE_REPO_PATH) ensure_seeds end end @@ -588,7 +584,6 @@ describe Gitlab::Git::Repository, seed_helper: true do end after(:all) do - FileUtils.rm_rf(TEST_MUTABLE_REPO_PATH) ensure_seeds end end @@ -1122,7 +1117,6 @@ describe Gitlab::Git::Repository, seed_helper: true do end after do - FileUtils.rm_rf(TEST_MUTABLE_REPO_PATH) ensure_seeds end @@ -1169,7 +1163,6 @@ describe Gitlab::Git::Repository, seed_helper: true do end after do - FileUtils.rm_rf(TEST_MUTABLE_REPO_PATH) ensure_seeds end @@ -1419,7 +1412,6 @@ describe Gitlab::Git::Repository, seed_helper: true do end after(:all) do - FileUtils.rm_rf(TEST_MUTABLE_REPO_PATH) ensure_seeds end @@ -1537,35 +1529,60 @@ describe Gitlab::Git::Repository, seed_helper: true do end describe '#fetch_source_branch!' do - let(:local_ref) { 'refs/merge-requests/1/head' } + shared_examples '#fetch_source_branch!' do + let(:local_ref) { 'refs/merge-requests/1/head' } + let(:repository) { Gitlab::Git::Repository.new('default', TEST_REPO_PATH, '') } + let(:source_repository) { Gitlab::Git::Repository.new('default', TEST_MUTABLE_REPO_PATH, '') } - context 'when the branch exists' do - let(:source_branch) { 'master' } + after do + ensure_seeds + end - it 'writes the ref' do - expect(repository).to receive(:write_ref).with(local_ref, /\h{40}/) + context 'when the branch exists' do + context 'when the commit does not exist locally' do + let(:source_branch) { 'new-branch-for-fetch-source-branch' } + let(:source_rugged) { source_repository.rugged } + let(:new_oid) { new_commit_edit_old_file(source_rugged).oid } - repository.fetch_source_branch!(repository, source_branch, local_ref) - end + before do + source_rugged.branches.create(source_branch, new_oid) + end - it 'returns true' do - expect(repository.fetch_source_branch!(repository, source_branch, local_ref)).to eq(true) - end - end + it 'writes the ref' do + expect(repository.fetch_source_branch!(source_repository, source_branch, local_ref)).to eq(true) + expect(repository.commit(local_ref).sha).to eq(new_oid) + end + end - context 'when the branch does not exist' do - let(:source_branch) { 'definitely-not-master' } + context 'when the commit exists locally' do + let(:source_branch) { 'master' } + let(:expected_oid) { SeedRepo::LastCommit::ID } - it 'does not write the ref' do - expect(repository).not_to receive(:write_ref) + it 'writes the ref' do + # Sanity check: the commit should already exist + expect(repository.commit(expected_oid)).not_to be_nil - repository.fetch_source_branch!(repository, source_branch, local_ref) + expect(repository.fetch_source_branch!(source_repository, source_branch, local_ref)).to eq(true) + expect(repository.commit(local_ref).sha).to eq(expected_oid) + end + end end - it 'returns false' do - expect(repository.fetch_source_branch!(repository, source_branch, local_ref)).to eq(false) + context 'when the branch does not exist' do + let(:source_branch) { 'definitely-not-master' } + + it 'does not write the ref' do + expect(repository.fetch_source_branch!(source_repository, source_branch, local_ref)).to eq(false) + expect(repository.commit(local_ref)).to be_nil + end end end + + it_behaves_like '#fetch_source_branch!' + + context 'without gitaly', :skip_gitaly_mock do + it_behaves_like '#fetch_source_branch!' + end end describe '#rm_branch' do @@ -1641,7 +1658,6 @@ describe Gitlab::Git::Repository, seed_helper: true do end after do - FileUtils.rm_rf(TEST_MUTABLE_REPO_PATH) ensure_seeds end diff --git a/spec/lib/gitlab/github_import/client_spec.rb b/spec/lib/gitlab/github_import/client_spec.rb index 9cbd9bcc14e..5b2642d9473 100644 --- a/spec/lib/gitlab/github_import/client_spec.rb +++ b/spec/lib/gitlab/github_import/client_spec.rb @@ -185,6 +185,17 @@ describe Gitlab::GithubImport::Client do client.with_rate_limit { } end + + it 'ignores rate limiting when disabled' do + expect(client) + .to receive(:rate_limiting_enabled?) + .and_return(false) + + expect(client) + .not_to receive(:requests_remaining?) + + expect(client.with_rate_limit { 10 }).to eq(10) + end end describe '#requests_remaining?' do @@ -362,4 +373,20 @@ describe Gitlab::GithubImport::Client do end end end + + describe '#rate_limiting_enabled?' do + let(:client) { described_class.new('foo') } + + it 'returns true when using GitHub.com' do + expect(client.rate_limiting_enabled?).to eq(true) + end + + it 'returns false for GitHub enterprise installations' do + expect(client) + .to receive(:api_endpoint) + .and_return('https://github.kittens.com/') + + expect(client.rate_limiting_enabled?).to eq(false) + end + end end diff --git a/spec/lib/gitlab/hook_data/issue_builder_spec.rb b/spec/lib/gitlab/hook_data/issue_builder_spec.rb index 6c529cdd051..aeacd577d18 100644 --- a/spec/lib/gitlab/hook_data/issue_builder_spec.rb +++ b/spec/lib/gitlab/hook_data/issue_builder_spec.rb @@ -11,7 +11,6 @@ describe Gitlab::HookData::IssueBuilder do %w[ assignee_id author_id - branch_name closed_at confidential created_at diff --git a/spec/lib/gitlab/metrics/sidekiq_middleware_spec.rb b/spec/lib/gitlab/metrics/sidekiq_middleware_spec.rb index 6d69b5305d2..ae1d8b47fe9 100644 --- a/spec/lib/gitlab/metrics/sidekiq_middleware_spec.rb +++ b/spec/lib/gitlab/metrics/sidekiq_middleware_spec.rb @@ -4,32 +4,40 @@ describe Gitlab::Metrics::SidekiqMiddleware do let(:middleware) { described_class.new } let(:message) { { 'args' => ['test'], 'enqueued_at' => Time.new(2016, 6, 23, 6, 59).to_f } } - def run(worker, message) - expect(Gitlab::Metrics::BackgroundTransaction).to receive(:new) - .with(worker.class) - .and_call_original - - expect_any_instance_of(Gitlab::Metrics::Transaction).to receive(:set) - .with(:sidekiq_queue_duration, instance_of(Float)) + describe '#call' do + it 'tracks the transaction' do + worker = double(:worker, class: double(:class, name: 'TestWorker')) - expect_any_instance_of(Gitlab::Metrics::Transaction).to receive(:finish) + expect(Gitlab::Metrics::BackgroundTransaction).to receive(:new) + .with(worker.class) + .and_call_original - middleware.call(worker, message, :test) { nil } - end + expect_any_instance_of(Gitlab::Metrics::Transaction).to receive(:set) + .with(:sidekiq_queue_duration, instance_of(Float)) - describe '#call' do - let(:test_worker_class) { double(:class, name: 'TestWorker') } - let(:worker) { double(:worker, class: test_worker_class) } + expect_any_instance_of(Gitlab::Metrics::Transaction).to receive(:finish) - it 'tracks the transaction' do - run(worker, message) + middleware.call(worker, message, :test) { nil } end it 'tracks the transaction (for messages without `enqueued_at`)' do - run(worker, {}) + worker = double(:worker, class: double(:class, name: 'TestWorker')) + + expect(Gitlab::Metrics::BackgroundTransaction).to receive(:new) + .with(worker.class) + .and_call_original + + expect_any_instance_of(Gitlab::Metrics::Transaction).to receive(:set) + .with(:sidekiq_queue_duration, instance_of(Float)) + + expect_any_instance_of(Gitlab::Metrics::Transaction).to receive(:finish) + + middleware.call(worker, {}, :test) { nil } end it 'tracks any raised exceptions' do + worker = double(:worker, class: double(:class, name: 'TestWorker')) + expect_any_instance_of(Gitlab::Metrics::Transaction) .to receive(:run).and_raise(RuntimeError) diff --git a/spec/models/concerns/avatarable_spec.rb b/spec/models/concerns/avatarable_spec.rb new file mode 100644 index 00000000000..cbdc438be0b --- /dev/null +++ b/spec/models/concerns/avatarable_spec.rb @@ -0,0 +1,44 @@ +require 'spec_helper' + +describe Avatarable do + subject { create(:project, avatar: fixture_file_upload(File.join(Rails.root, 'spec/fixtures/dk.png'))) } + + let(:gitlab_host) { "https://gitlab.example.com" } + let(:relative_url_root) { "/gitlab" } + let(:asset_host) { "https://gitlab-assets.example.com" } + + before do + stub_config_setting(base_url: gitlab_host) + stub_config_setting(relative_url_root: relative_url_root) + end + + describe '#avatar_path' do + using RSpec::Parameterized::TableSyntax + + where(:has_asset_host, :visibility_level, :only_path, :avatar_path) do + true | Project::PRIVATE | true | [gitlab_host, relative_url_root, subject.avatar.url] + true | Project::PRIVATE | false | [gitlab_host, relative_url_root, subject.avatar.url] + true | Project::INTERNAL | true | [gitlab_host, relative_url_root, subject.avatar.url] + true | Project::INTERNAL | false | [gitlab_host, relative_url_root, subject.avatar.url] + true | Project::PUBLIC | true | [subject.avatar.url] + true | Project::PUBLIC | false | [asset_host, subject.avatar.url] + false | Project::PRIVATE | true | [relative_url_root, subject.avatar.url] + false | Project::PRIVATE | false | [gitlab_host, relative_url_root, subject.avatar.url] + false | Project::INTERNAL | true | [relative_url_root, subject.avatar.url] + false | Project::INTERNAL | false | [gitlab_host, relative_url_root, subject.avatar.url] + false | Project::PUBLIC | true | [relative_url_root, subject.avatar.url] + false | Project::PUBLIC | false | [gitlab_host, relative_url_root, subject.avatar.url] + end + + with_them do + before do + allow(ActionController::Base).to receive(:asset_host).and_return(has_asset_host ? asset_host : nil) + subject.visibility_level = visibility_level + end + + it 'returns the expected avatar path' do + expect(subject.avatar_path(only_path: only_path)).to eq(avatar_path.join) + end + end + end +end diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb index d4052a64570..5e82a2988ce 100644 --- a/spec/models/group_spec.rb +++ b/spec/models/group_spec.rb @@ -247,8 +247,6 @@ describe Group do describe '#avatar_url' do let!(:group) { create(:group, :access_requestable, :with_avatar) } let(:user) { create(:user) } - let(:gitlab_host) { "http://#{Gitlab.config.gitlab.host}" } - let(:avatar_path) { "/uploads/-/system/group/avatar/#{group.id}/dk.png" } context 'when avatar file is uploaded' do before do @@ -256,12 +254,8 @@ describe Group do end it 'shows correct avatar url' do - expect(group.avatar_url).to eq(avatar_path) - expect(group.avatar_url(only_path: false)).to eq([gitlab_host, avatar_path].join) - - allow(ActionController::Base).to receive(:asset_host).and_return(gitlab_host) - - expect(group.avatar_url).to eq([gitlab_host, avatar_path].join) + expect(group.avatar_url).to eq(group.avatar.url) + expect(group.avatar_url(only_path: false)).to eq([Gitlab.config.gitlab.url, group.avatar.url].join) end end end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index e684389af5d..4db417c8793 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -883,20 +883,14 @@ describe Project do context 'when avatar file is uploaded' do let(:project) { create(:project, :public, :with_avatar) } - let(:avatar_path) { "/uploads/-/system/project/avatar/#{project.id}/dk.png" } - let(:gitlab_host) { "http://#{Gitlab.config.gitlab.host}" } it 'shows correct url' do - expect(project.avatar_url).to eq(avatar_path) - expect(project.avatar_url(only_path: false)).to eq([gitlab_host, avatar_path].join) - - allow(ActionController::Base).to receive(:asset_host).and_return(gitlab_host) - - expect(project.avatar_url).to eq([gitlab_host, avatar_path].join) + expect(project.avatar_url).to eq(project.avatar.url) + expect(project.avatar_url(only_path: false)).to eq([Gitlab.config.gitlab.url, project.avatar.url].join) end end - context 'When avatar file in git' do + context 'when avatar file in git' do before do allow(project).to receive(:avatar_in_git) { true } end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index a3ebf649aa8..65dccf9638d 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -1149,16 +1149,9 @@ describe User do let(:user) { create(:user, :with_avatar) } context 'when avatar file is uploaded' do - let(:gitlab_host) { "http://#{Gitlab.config.gitlab.host}" } - let(:avatar_path) { "/uploads/-/system/user/avatar/#{user.id}/dk.png" } - it 'shows correct avatar url' do - expect(user.avatar_url).to eq(avatar_path) - expect(user.avatar_url(only_path: false)).to eq([gitlab_host, avatar_path].join) - - allow(ActionController::Base).to receive(:asset_host).and_return(gitlab_host) - - expect(user.avatar_url).to eq([gitlab_host, avatar_path].join) + expect(user.avatar_url).to eq(user.avatar.url) + expect(user.avatar_url(only_path: false)).to eq([Gitlab.config.gitlab.url, user.avatar.url].join) end end end diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb index 780dbce6488..04a658cd6c3 100644 --- a/spec/requests/api/groups_spec.rb +++ b/spec/requests/api/groups_spec.rb @@ -427,6 +427,142 @@ describe API::Groups do end end + describe 'GET /groups/:id/subgroups', :nested_groups do + let!(:subgroup1) { create(:group, parent: group1) } + let!(:subgroup2) { create(:group, :private, parent: group1) } + let!(:subgroup3) { create(:group, :private, parent: group2) } + + context 'when unauthenticated' do + it 'returns only public subgroups' do + get api("/groups/#{group1.id}/subgroups") + + expect(response).to have_gitlab_http_status(200) + expect(response).to include_pagination_headers + expect(json_response).to be_an Array + expect(json_response.length).to eq(1) + expect(json_response.first['id']).to eq(subgroup1.id) + expect(json_response.first['parent_id']).to eq(group1.id) + end + + it 'returns 404 for a private group' do + get api("/groups/#{group2.id}/subgroups") + + expect(response).to have_gitlab_http_status(404) + end + end + + context 'when authenticated as user' do + context 'when user is not member of a public group' do + it 'returns no subgroups for the public group' do + get api("/groups/#{group1.id}/subgroups", user2) + + expect(response).to have_gitlab_http_status(200) + expect(json_response).to be_an Array + expect(json_response.length).to eq(0) + end + + context 'when using all_available in request' do + it 'returns public subgroups' do + get api("/groups/#{group1.id}/subgroups", user2), all_available: true + + expect(response).to have_gitlab_http_status(200) + expect(json_response).to be_an Array + expect(json_response.length).to eq(1) + expect(json_response[0]['id']).to eq(subgroup1.id) + expect(json_response[0]['parent_id']).to eq(group1.id) + end + end + end + + context 'when user is not member of a private group' do + it 'returns 404 for the private group' do + get api("/groups/#{group2.id}/subgroups", user1) + + expect(response).to have_gitlab_http_status(404) + end + end + + context 'when user is member of public group' do + before do + group1.add_guest(user2) + end + + it 'returns private subgroups' do + get api("/groups/#{group1.id}/subgroups", user2) + + expect(response).to have_gitlab_http_status(200) + expect(response).to include_pagination_headers + expect(json_response).to be_an Array + expect(json_response.length).to eq(2) + private_subgroups = json_response.select { |group| group['visibility'] == 'private' } + expect(private_subgroups.length).to eq(1) + expect(private_subgroups.first['id']).to eq(subgroup2.id) + expect(private_subgroups.first['parent_id']).to eq(group1.id) + end + + context 'when using statistics in request' do + it 'does not include statistics' do + get api("/groups/#{group1.id}/subgroups", user2), statistics: true + + expect(response).to have_gitlab_http_status(200) + expect(json_response).to be_an Array + expect(json_response.first).not_to include 'statistics' + end + end + end + + context 'when user is member of private group' do + before do + group2.add_guest(user1) + end + + it 'returns subgroups' do + get api("/groups/#{group2.id}/subgroups", user1) + + expect(response).to have_gitlab_http_status(200) + expect(json_response).to be_an Array + expect(json_response.length).to eq(1) + expect(json_response.first['id']).to eq(subgroup3.id) + expect(json_response.first['parent_id']).to eq(group2.id) + end + end + end + + context 'when authenticated as admin' do + it 'returns private subgroups of a public group' do + get api("/groups/#{group1.id}/subgroups", admin) + + expect(response).to have_gitlab_http_status(200) + expect(json_response).to be_an Array + expect(json_response.length).to eq(2) + end + + it 'returns subgroups of a private group' do + get api("/groups/#{group2.id}/subgroups", admin) + + expect(response).to have_gitlab_http_status(200) + expect(json_response).to be_an Array + expect(json_response.length).to eq(1) + end + + it 'does not include statistics by default' do + get api("/groups/#{group1.id}/subgroups", admin) + + expect(response).to have_gitlab_http_status(200) + expect(json_response).to be_an Array + expect(json_response.first).not_to include('statistics') + end + + it 'includes statistics if requested' do + get api("/groups/#{group1.id}/subgroups", admin), statistics: true + + expect(response).to have_gitlab_http_status(200) + expect(json_response).to be_an Array + expect(json_response.first).to include('statistics') + end + end + end + describe "POST /groups" do context "when authenticated as user without group permissions" do it "does not create group" do diff --git a/spec/requests/api/services_spec.rb b/spec/requests/api/services_spec.rb index dfe48e45d49..ba697e2b305 100644 --- a/spec/requests/api/services_spec.rb +++ b/spec/requests/api/services_spec.rb @@ -175,4 +175,25 @@ describe API::Services do end end end + + describe 'Mattermost service' do + let(:service_name) { 'mattermost' } + let(:params) do + { webhook: 'https://hook.example.com', username: 'username' } + end + + before do + project.create_mattermost_service( + active: true, + properties: params + ) + end + + it 'accepts a username for update' do + put api("/projects/#{project.id}/services/mattermost", user), params.merge(username: 'new_username') + + expect(response).to have_gitlab_http_status(200) + expect(json_response['properties']['username']).to eq('new_username') + end + end end diff --git a/spec/services/merge_requests/merge_service_spec.rb b/spec/services/merge_requests/merge_service_spec.rb index ac196e92601..f86f1ac2443 100644 --- a/spec/services/merge_requests/merge_service_spec.rb +++ b/spec/services/merge_requests/merge_service_spec.rb @@ -248,6 +248,28 @@ describe MergeRequests::MergeService do expect(merge_request.merge_error).to include(error_message) expect(Rails.logger).to have_received(:error).with(a_string_matching(error_message)) end + + context "when fast-forward merge is not allowed" do + before do + allow_any_instance_of(Repository).to receive(:ancestor?).and_return(nil) + end + + %w(semi-linear ff).each do |merge_method| + it "logs and saves error if merge is #{merge_method} only" do + merge_method = 'rebase_merge' if merge_method == 'semi-linear' + merge_request.project.update(merge_method: merge_method) + error_message = 'Only fast-forward merge is allowed for your project. Please update your source branch' + allow(service).to receive(:execute_hooks) + + service.execute(merge_request) + + expect(merge_request).to be_open + expect(merge_request.merge_commit_sha).to be_nil + expect(merge_request.merge_error).to include(error_message) + expect(Rails.logger).to have_received(:error).with(a_string_matching(error_message)) + end + end + end end end end diff --git a/spec/services/milestones/destroy_service_spec.rb b/spec/services/milestones/destroy_service_spec.rb index 5739386dd0d..16e288b3148 100644 --- a/spec/services/milestones/destroy_service_spec.rb +++ b/spec/services/milestones/destroy_service_spec.rb @@ -4,7 +4,7 @@ describe Milestones::DestroyService do let(:user) { create(:user) } let(:project) { create(:project) } let(:milestone) { create(:milestone, title: 'Milestone v1.0', project: project) } - let(:issue) { create(:issue, project: project, milestone: milestone) } + let!(:issue) { create(:issue, project: project, milestone: milestone) } let(:merge_request) { create(:merge_request, source_project: project, milestone: milestone) } before do diff --git a/tsconfig.json b/tsconfig.json deleted file mode 100644 index 3a569cf7c19..00000000000 --- a/tsconfig.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "compilerOptions": { - "target": "es5", - "strict": true, - "module": "es2015", - "moduleResolution": "node" - } -}
\ No newline at end of file diff --git a/vendor/assets/javascripts/latinise.js b/vendor/assets/javascripts/latinise.js deleted file mode 100644 index da37966b28a..00000000000 --- a/vendor/assets/javascripts/latinise.js +++ /dev/null @@ -1,11 +0,0 @@ -// Converting text to basic latin (aka removing accents) -// -// Based on: http://semplicewebsites.com/removing-accents-javascript -// -var Latinise = { - map: {"Á":"A","Ă":"A","Ắ":"A","Ặ":"A","Ằ":"A","Ẳ":"A","Ẵ":"A","Ǎ":"A","Â":"A","Ấ":"A","Ậ":"A","Ầ":"A","Ẩ":"A","Ẫ":"A","Ä":"A","Ǟ":"A","Ȧ":"A","Ǡ":"A","Ạ":"A","Ȁ":"A","À":"A","Ả":"A","Ȃ":"A","Ā":"A","Ą":"A","Å":"A","Ǻ":"A","Ḁ":"A","Ⱥ":"A","Ã":"A","Ꜳ":"AA","Æ":"AE","Ǽ":"AE","Ǣ":"AE","Ꜵ":"AO","Ꜷ":"AU","Ꜹ":"AV","Ꜻ":"AV","Ꜽ":"AY","Ḃ":"B","Ḅ":"B","Ɓ":"B","Ḇ":"B","Ƀ":"B","Ƃ":"B","Ć":"C","Č":"C","Ç":"C","Ḉ":"C","Ĉ":"C","Ċ":"C","Ƈ":"C","Ȼ":"C","Ď":"D","Ḑ":"D","Ḓ":"D","Ḋ":"D","Ḍ":"D","Ɗ":"D","Ḏ":"D","Dz":"D","Dž":"D","Đ":"D","Ƌ":"D","DZ":"DZ","DŽ":"DZ","É":"E","Ĕ":"E","Ě":"E","Ȩ":"E","Ḝ":"E","Ê":"E","Ế":"E","Ệ":"E","Ề":"E","Ể":"E","Ễ":"E","Ḙ":"E","Ë":"E","Ė":"E","Ẹ":"E","Ȅ":"E","È":"E","Ẻ":"E","Ȇ":"E","Ē":"E","Ḗ":"E","Ḕ":"E","Ę":"E","Ɇ":"E","Ẽ":"E","Ḛ":"E","Ꝫ":"ET","Ḟ":"F","Ƒ":"F","Ǵ":"G","Ğ":"G","Ǧ":"G","Ģ":"G","Ĝ":"G","Ġ":"G","Ɠ":"G","Ḡ":"G","Ǥ":"G","Ḫ":"H","Ȟ":"H","Ḩ":"H","Ĥ":"H","Ⱨ":"H","Ḧ":"H","Ḣ":"H","Ḥ":"H","Ħ":"H","Í":"I","Ĭ":"I","Ǐ":"I","Î":"I","Ï":"I","Ḯ":"I","İ":"I","Ị":"I","Ȉ":"I","Ì":"I","Ỉ":"I","Ȋ":"I","Ī":"I","Į":"I","Ɨ":"I","Ĩ":"I","Ḭ":"I","Ꝺ":"D","Ꝼ":"F","Ᵹ":"G","Ꞃ":"R","Ꞅ":"S","Ꞇ":"T","Ꝭ":"IS","Ĵ":"J","Ɉ":"J","Ḱ":"K","Ǩ":"K","Ķ":"K","Ⱪ":"K","Ꝃ":"K","Ḳ":"K","Ƙ":"K","Ḵ":"K","Ꝁ":"K","Ꝅ":"K","Ĺ":"L","Ƚ":"L","Ľ":"L","Ļ":"L","Ḽ":"L","Ḷ":"L","Ḹ":"L","Ⱡ":"L","Ꝉ":"L","Ḻ":"L","Ŀ":"L","Ɫ":"L","Lj":"L","Ł":"L","LJ":"LJ","Ḿ":"M","Ṁ":"M","Ṃ":"M","Ɱ":"M","Ń":"N","Ň":"N","Ņ":"N","Ṋ":"N","Ṅ":"N","Ṇ":"N","Ǹ":"N","Ɲ":"N","Ṉ":"N","Ƞ":"N","Nj":"N","Ñ":"N","NJ":"NJ","Ó":"O","Ŏ":"O","Ǒ":"O","Ô":"O","Ố":"O","Ộ":"O","Ồ":"O","Ổ":"O","Ỗ":"O","Ö":"O","Ȫ":"O","Ȯ":"O","Ȱ":"O","Ọ":"O","Ő":"O","Ȍ":"O","Ò":"O","Ỏ":"O","Ơ":"O","Ớ":"O","Ợ":"O","Ờ":"O","Ở":"O","Ỡ":"O","Ȏ":"O","Ꝋ":"O","Ꝍ":"O","Ō":"O","Ṓ":"O","Ṑ":"O","Ɵ":"O","Ǫ":"O","Ǭ":"O","Ø":"O","Ǿ":"O","Õ":"O","Ṍ":"O","Ṏ":"O","Ȭ":"O","Ƣ":"OI","Ꝏ":"OO","Ɛ":"E","Ɔ":"O","Ȣ":"OU","Ṕ":"P","Ṗ":"P","Ꝓ":"P","Ƥ":"P","Ꝕ":"P","Ᵽ":"P","Ꝑ":"P","Ꝙ":"Q","Ꝗ":"Q","Ŕ":"R","Ř":"R","Ŗ":"R","Ṙ":"R","Ṛ":"R","Ṝ":"R","Ȑ":"R","Ȓ":"R","Ṟ":"R","Ɍ":"R","Ɽ":"R","Ꜿ":"C","Ǝ":"E","Ś":"S","Ṥ":"S","Š":"S","Ṧ":"S","Ş":"S","Ŝ":"S","Ș":"S","Ṡ":"S","Ṣ":"S","Ṩ":"S","ẞ":"SS","Ť":"T","Ţ":"T","Ṱ":"T","Ț":"T","Ⱦ":"T","Ṫ":"T","Ṭ":"T","Ƭ":"T","Ṯ":"T","Ʈ":"T","Ŧ":"T","Ɐ":"A","Ꞁ":"L","Ɯ":"M","Ʌ":"V","Ꜩ":"TZ","Ú":"U","Ŭ":"U","Ǔ":"U","Û":"U","Ṷ":"U","Ü":"U","Ǘ":"U","Ǚ":"U","Ǜ":"U","Ǖ":"U","Ṳ":"U","Ụ":"U","Ű":"U","Ȕ":"U","Ù":"U","Ủ":"U","Ư":"U","Ứ":"U","Ự":"U","Ừ":"U","Ử":"U","Ữ":"U","Ȗ":"U","Ū":"U","Ṻ":"U","Ų":"U","Ů":"U","Ũ":"U","Ṹ":"U","Ṵ":"U","Ꝟ":"V","Ṿ":"V","Ʋ":"V","Ṽ":"V","Ꝡ":"VY","Ẃ":"W","Ŵ":"W","Ẅ":"W","Ẇ":"W","Ẉ":"W","Ẁ":"W","Ⱳ":"W","Ẍ":"X","Ẋ":"X","Ý":"Y","Ŷ":"Y","Ÿ":"Y","Ẏ":"Y","Ỵ":"Y","Ỳ":"Y","Ƴ":"Y","Ỷ":"Y","Ỿ":"Y","Ȳ":"Y","Ɏ":"Y","Ỹ":"Y","Ź":"Z","Ž":"Z","Ẑ":"Z","Ⱬ":"Z","Ż":"Z","Ẓ":"Z","Ȥ":"Z","Ẕ":"Z","Ƶ":"Z","IJ":"IJ","Œ":"OE","ᴀ":"A","ᴁ":"AE","ʙ":"B","ᴃ":"B","ᴄ":"C","ᴅ":"D","ᴇ":"E","ꜰ":"F","ɢ":"G","ʛ":"G","ʜ":"H","ɪ":"I","ʁ":"R","ᴊ":"J","ᴋ":"K","ʟ":"L","ᴌ":"L","ᴍ":"M","ɴ":"N","ᴏ":"O","ɶ":"OE","ᴐ":"O","ᴕ":"OU","ᴘ":"P","ʀ":"R","ᴎ":"N","ᴙ":"R","ꜱ":"S","ᴛ":"T","ⱻ":"E","ᴚ":"R","ᴜ":"U","ᴠ":"V","ᴡ":"W","ʏ":"Y","ᴢ":"Z","á":"a","ă":"a","ắ":"a","ặ":"a","ằ":"a","ẳ":"a","ẵ":"a","ǎ":"a","â":"a","ấ":"a","ậ":"a","ầ":"a","ẩ":"a","ẫ":"a","ä":"a","ǟ":"a","ȧ":"a","ǡ":"a","ạ":"a","ȁ":"a","à":"a","ả":"a","ȃ":"a","ā":"a","ą":"a","ᶏ":"a","ẚ":"a","å":"a","ǻ":"a","ḁ":"a","ⱥ":"a","ã":"a","ꜳ":"aa","æ":"ae","ǽ":"ae","ǣ":"ae","ꜵ":"ao","ꜷ":"au","ꜹ":"av","ꜻ":"av","ꜽ":"ay","ḃ":"b","ḅ":"b","ɓ":"b","ḇ":"b","ᵬ":"b","ᶀ":"b","ƀ":"b","ƃ":"b","ɵ":"o","ć":"c","č":"c","ç":"c","ḉ":"c","ĉ":"c","ɕ":"c","ċ":"c","ƈ":"c","ȼ":"c","ď":"d","ḑ":"d","ḓ":"d","ȡ":"d","ḋ":"d","ḍ":"d","ɗ":"d","ᶑ":"d","ḏ":"d","ᵭ":"d","ᶁ":"d","đ":"d","ɖ":"d","ƌ":"d","ı":"i","ȷ":"j","ɟ":"j","ʄ":"j","dz":"dz","dž":"dz","é":"e","ĕ":"e","ě":"e","ȩ":"e","ḝ":"e","ê":"e","ế":"e","ệ":"e","ề":"e","ể":"e","ễ":"e","ḙ":"e","ë":"e","ė":"e","ẹ":"e","ȅ":"e","è":"e","ẻ":"e","ȇ":"e","ē":"e","ḗ":"e","ḕ":"e","ⱸ":"e","ę":"e","ᶒ":"e","ɇ":"e","ẽ":"e","ḛ":"e","ꝫ":"et","ḟ":"f","ƒ":"f","ᵮ":"f","ᶂ":"f","ǵ":"g","ğ":"g","ǧ":"g","ģ":"g","ĝ":"g","ġ":"g","ɠ":"g","ḡ":"g","ᶃ":"g","ǥ":"g","ḫ":"h","ȟ":"h","ḩ":"h","ĥ":"h","ⱨ":"h","ḧ":"h","ḣ":"h","ḥ":"h","ɦ":"h","ẖ":"h","ħ":"h","ƕ":"hv","í":"i","ĭ":"i","ǐ":"i","î":"i","ï":"i","ḯ":"i","ị":"i","ȉ":"i","ì":"i","ỉ":"i","ȋ":"i","ī":"i","į":"i","ᶖ":"i","ɨ":"i","ĩ":"i","ḭ":"i","ꝺ":"d","ꝼ":"f","ᵹ":"g","ꞃ":"r","ꞅ":"s","ꞇ":"t","ꝭ":"is","ǰ":"j","ĵ":"j","ʝ":"j","ɉ":"j","ḱ":"k","ǩ":"k","ķ":"k","ⱪ":"k","ꝃ":"k","ḳ":"k","ƙ":"k","ḵ":"k","ᶄ":"k","ꝁ":"k","ꝅ":"k","ĺ":"l","ƚ":"l","ɬ":"l","ľ":"l","ļ":"l","ḽ":"l","ȴ":"l","ḷ":"l","ḹ":"l","ⱡ":"l","ꝉ":"l","ḻ":"l","ŀ":"l","ɫ":"l","ᶅ":"l","ɭ":"l","ł":"l","lj":"lj","ſ":"s","ẜ":"s","ẛ":"s","ẝ":"s","ḿ":"m","ṁ":"m","ṃ":"m","ɱ":"m","ᵯ":"m","ᶆ":"m","ń":"n","ň":"n","ņ":"n","ṋ":"n","ȵ":"n","ṅ":"n","ṇ":"n","ǹ":"n","ɲ":"n","ṉ":"n","ƞ":"n","ᵰ":"n","ᶇ":"n","ɳ":"n","ñ":"n","nj":"nj","ó":"o","ŏ":"o","ǒ":"o","ô":"o","ố":"o","ộ":"o","ồ":"o","ổ":"o","ỗ":"o","ö":"o","ȫ":"o","ȯ":"o","ȱ":"o","ọ":"o","ő":"o","ȍ":"o","ò":"o","ỏ":"o","ơ":"o","ớ":"o","ợ":"o","ờ":"o","ở":"o","ỡ":"o","ȏ":"o","ꝋ":"o","ꝍ":"o","ⱺ":"o","ō":"o","ṓ":"o","ṑ":"o","ǫ":"o","ǭ":"o","ø":"o","ǿ":"o","õ":"o","ṍ":"o","ṏ":"o","ȭ":"o","ƣ":"oi","ꝏ":"oo","ɛ":"e","ᶓ":"e","ɔ":"o","ᶗ":"o","ȣ":"ou","ṕ":"p","ṗ":"p","ꝓ":"p","ƥ":"p","ᵱ":"p","ᶈ":"p","ꝕ":"p","ᵽ":"p","ꝑ":"p","ꝙ":"q","ʠ":"q","ɋ":"q","ꝗ":"q","ŕ":"r","ř":"r","ŗ":"r","ṙ":"r","ṛ":"r","ṝ":"r","ȑ":"r","ɾ":"r","ᵳ":"r","ȓ":"r","ṟ":"r","ɼ":"r","ᵲ":"r","ᶉ":"r","ɍ":"r","ɽ":"r","ↄ":"c","ꜿ":"c","ɘ":"e","ɿ":"r","ś":"s","ṥ":"s","š":"s","ṧ":"s","ş":"s","ŝ":"s","ș":"s","ṡ":"s","ṣ":"s","ṩ":"s","ʂ":"s","ᵴ":"s","ᶊ":"s","ȿ":"s","ɡ":"g","ß":"ss","ᴑ":"o","ᴓ":"o","ᴝ":"u","ť":"t","ţ":"t","ṱ":"t","ț":"t","ȶ":"t","ẗ":"t","ⱦ":"t","ṫ":"t","ṭ":"t","ƭ":"t","ṯ":"t","ᵵ":"t","ƫ":"t","ʈ":"t","ŧ":"t","ᵺ":"th","ɐ":"a","ᴂ":"ae","ǝ":"e","ᵷ":"g","ɥ":"h","ʮ":"h","ʯ":"h","ᴉ":"i","ʞ":"k","ꞁ":"l","ɯ":"m","ɰ":"m","ᴔ":"oe","ɹ":"r","ɻ":"r","ɺ":"r","ⱹ":"r","ʇ":"t","ʌ":"v","ʍ":"w","ʎ":"y","ꜩ":"tz","ú":"u","ŭ":"u","ǔ":"u","û":"u","ṷ":"u","ü":"u","ǘ":"u","ǚ":"u","ǜ":"u","ǖ":"u","ṳ":"u","ụ":"u","ű":"u","ȕ":"u","ù":"u","ủ":"u","ư":"u","ứ":"u","ự":"u","ừ":"u","ử":"u","ữ":"u","ȗ":"u","ū":"u","ṻ":"u","ų":"u","ᶙ":"u","ů":"u","ũ":"u","ṹ":"u","ṵ":"u","ᵫ":"ue","ꝸ":"um","ⱴ":"v","ꝟ":"v","ṿ":"v","ʋ":"v","ᶌ":"v","ⱱ":"v","ṽ":"v","ꝡ":"vy","ẃ":"w","ŵ":"w","ẅ":"w","ẇ":"w","ẉ":"w","ẁ":"w","ⱳ":"w","ẘ":"w","ẍ":"x","ẋ":"x","ᶍ":"x","ý":"y","ŷ":"y","ÿ":"y","ẏ":"y","ỵ":"y","ỳ":"y","ƴ":"y","ỷ":"y","ỿ":"y","ȳ":"y","ẙ":"y","ɏ":"y","ỹ":"y","ź":"z","ž":"z","ẑ":"z","ʑ":"z","ⱬ":"z","ż":"z","ẓ":"z","ȥ":"z","ẕ":"z","ᵶ":"z","ᶎ":"z","ʐ":"z","ƶ":"z","ɀ":"z","ff":"ff","ffi":"ffi","ffl":"ffl","fi":"fi","fl":"fl","ij":"ij","œ":"oe","st":"st","ₐ":"a","ₑ":"e","ᵢ":"i","ⱼ":"j","ₒ":"o","ᵣ":"r","ᵤ":"u","ᵥ":"v","ₓ":"x"} -}; - -String.prototype.latinise = function() { - return this.replace(/[^A-Za-z0-9]/g, function(x) { return Latinise.map[x] || x; }); -}; diff --git a/vendor/gitignore/Android.gitignore b/vendor/gitignore/Android.gitignore index c79ba5080a3..addf405e4f5 100644 --- a/vendor/gitignore/Android.gitignore +++ b/vendor/gitignore/Android.gitignore @@ -32,7 +32,7 @@ proguard/ # Android Studio captures folder captures/ -# Intellij +# IntelliJ *.iml .idea/workspace.xml .idea/tasks.xml diff --git a/vendor/gitignore/Perl.gitignore b/vendor/gitignore/Perl.gitignore index 9bf1537f6ae..ecf66f84291 100644 --- a/vendor/gitignore/Perl.gitignore +++ b/vendor/gitignore/Perl.gitignore @@ -24,7 +24,7 @@ Build.bat # Module::Install inc/ -# ExtUitls::MakeMaker +# ExtUtils::MakeMaker /blib/ /_eumm/ /*.gz diff --git a/vendor/gitlab-ci-yml/Crystal.gitlab-ci.yml b/vendor/gitlab-ci-yml/Crystal.gitlab-ci.yml index 02cfab3a5b2..36386a19fdc 100644 --- a/vendor/gitlab-ci-yml/Crystal.gitlab-ci.yml +++ b/vendor/gitlab-ci-yml/Crystal.gitlab-ci.yml @@ -16,7 +16,7 @@ image: "crystallang/crystal:latest" # Cache shards in between builds cache: paths: - - libs + - lib # This is a basic example for a shard or script which doesn't use # services such as redis or postgres diff --git a/vendor/licenses.csv b/vendor/licenses.csv index 9f78059986d..6f6ca5f8b32 100644 --- a/vendor/licenses.csv +++ b/vendor/licenses.csv @@ -1,7 +1,11 @@ +"","","MIT,ISC,Apache 2.0,New BSD,Simplified BSD" RedCloth,4.3.2,MIT abbrev,1.0.9,ISC +abbrev,1.1.0,ISC accepts,1.3.3,MIT ace-rails-ap,4.1.2,MIT +acorn,3.3.0,MIT +acorn,4.0.13,MIT acorn,5.1.1,MIT acorn-dynamic-import,2.0.2,MIT acorn-jsx,3.0.1,MIT @@ -15,7 +19,9 @@ activesupport,4.2.8,MIT acts-as-taggable-on,4.0.0,MIT addressable,2.5.2,Apache 2.0 after,0.8.2,MIT +ajv,4.11.8,MIT ajv,5.2.2,MIT +ajv-keywords,1.5.1,MIT ajv-keywords,2.1.0,MIT akismet,2.0.0,MIT align-text,0.1.4,MIT @@ -24,10 +30,14 @@ alphanum-sort,1.0.2,MIT amdefine,1.0.1,BSD-3-Clause OR MIT ansi-escapes,1.4.0,MIT ansi-html,0.0.5,"Apache, Version 2.0" +ansi-html,0.0.7,Apache 2.0 ansi-regex,2.1.1,MIT ansi-styles,2.2.1,MIT +ansi-styles,3.2.0,MIT anymatch,1.3.2,ISC append-transform,0.4.0,MIT +aproba,1.1.1,ISC +are-we-there-yet,1.1.4,ISC arel,6.0.4,MIT argparse,1.0.9,MIT arr-diff,2.0.0,MIT @@ -35,6 +45,7 @@ arr-flatten,1.0.1,MIT array-find,1.0.0,MIT array-find-index,1.0.2,MIT array-flatten,1.1.1,MIT +array-flatten,2.1.1,MIT array-slice,0.2.3,MIT array-union,1.0.2,MIT array-uniq,1.0.3,MIT @@ -44,15 +55,24 @@ arrify,1.0.1,MIT asana,0.6.0,MIT asciidoctor,1.5.3,MIT asciidoctor-plantuml,0.0.7,MIT +asn1,0.2.3,MIT asn1.js,4.9.1,MIT assert,1.4.1,MIT +assert-plus,0.2.0,MIT +assert-plus,1.0.0,MIT +async,0.9.2,MIT +async,1.5.2,MIT async,2.4.1,MIT async-each,1.0.1,MIT +asynckit,0.4.0,MIT atomic,1.1.99,Apache 2.0 attr_encrypted,3.0.3,MIT attr_required,1.0.0,MIT autoprefixer,6.7.7,MIT autoprefixer-rails,6.2.3,MIT +autosize,4.0.0,MIT +aws-sign2,0.6.0,Apache 2.0 +aws4,1.6.0,MIT axiom-types,0.1.1,MIT axios,0.16.2,MIT babel-code-frame,6.22.0,MIT @@ -130,6 +150,7 @@ babel-types,6.23.0,MIT babosa,1.0.2,MIT babylon,6.16.1,MIT backo2,1.0.2,MIT +balanced-match,0.4.2,MIT balanced-match,1.0.0,MIT base32,0.3.2,MIT base64-arraybuffer,0.1.5,MIT @@ -137,19 +158,25 @@ base64-js,1.2.0,MIT base64id,1.0.0,MIT batch,0.6.1,MIT bcrypt,3.1.11,MIT +bcrypt-pbkdf,1.0.1,New BSD bcrypt_pbkdf,1.0.0,MIT better-assert,1.0.2,MIT big.js,3.1.3,MIT binary-extensions,1.10.0,MIT bindata,2.4.1,ruby blob,0.0.4,unknown +block-stream,0.0.9,ISC bluebird,2.11.0,MIT +bluebird,3.5.0,MIT bn.js,4.11.6,MIT body-parser,1.17.2,MIT bonjour,3.5.0,MIT +boom,2.10.1,New BSD bootstrap-sass,3.3.6,MIT bootstrap_form,2.7.0,MIT +brace-expansion,1.1.7,MIT brace-expansion,1.1.8,MIT +braces,0.1.5,MIT braces,1.8.5,MIT brorand,1.0.7,MIT browser,2.2.0,MIT @@ -168,17 +195,23 @@ builder,3.2.3,MIT builtin-modules,1.1.1,MIT builtin-status-codes,3.0.0,MIT bytes,2.4.0,MIT +bytes,2.5.0,MIT caller-path,0.1.0,MIT callsite,1.0.0,unknown callsites,0.2.0,MIT +camelcase,1.2.1,MIT +camelcase,2.1.1,MIT +camelcase,3.0.0,MIT camelcase,4.1.0,MIT camelcase-keys,2.1.0,MIT caniuse-api,1.6.1,MIT caniuse-db,1.0.30000649,CC-BY-4.0 -carrierwave,1.1.0,MIT +carrierwave,1.2.1,MIT +caseless,0.12.0,Apache 2.0 cause,0.1,MIT center-align,0.1.3,MIT chalk,1.1.3,MIT +chalk,2.3.0,MIT charlock_holmes,0.7.5,MIT chokidar,1.7.0,MIT chronic,0.10.2,MIT @@ -191,6 +224,7 @@ clap,1.1.3,MIT cli-cursor,1.0.2,MIT cli-width,2.1.0,ISC clipboard,1.6.1,MIT +cliui,2.1.0,ISC cliui,3.2.0,ISC clone,1.0.2,MIT co,4.6.0,MIT @@ -204,9 +238,11 @@ color-string,0.3.0,MIT colormin,1.1.2,MIT colors,1.1.2,MIT combine-lists,1.0.1,MIT +combined-stream,1.0.5,MIT commander,2.9.0,MIT commondir,1.0.1,MIT component-bind,1.0.0,unknown +component-emitter,1.1.2,unknown component-emitter,1.2.1,MIT component-inherit,0.0.3,unknown compressible,2.0.11,MIT @@ -220,7 +256,8 @@ configstore,1.4.0,Simplified BSD connect,3.6.3,MIT connect-history-api-fallback,1.3.0,MIT connection_pool,2.2.1,MIT -console-browserify,1.1.0,[Circular] +console-browserify,1.1.0,MIT +console-control-strings,1.1.0,ISC consolidate,0.14.5,MIT constants-browserify,1.0.0,MIT contains-path,0.1.0,MIT @@ -230,6 +267,7 @@ convert-source-map,1.3.0,MIT cookie,0.3.1,MIT cookie-signature,1.0.6,MIT copy-webpack-plugin,4.0.1,MIT +core-js,2.3.0,MIT core-js,2.4.1,MIT core-util-is,1.0.2,MIT cosmiconfig,2.1.1,MIT @@ -240,9 +278,11 @@ create-hmac,1.1.4,MIT creole,0.5.0,ruby cropper,2.3.0,MIT cross-spawn,5.1.0,MIT +cryptiles,2.0.5,New BSD crypto-browserify,3.11.0,MIT css-color-names,0.0.4,MIT css-loader,0.28.0,MIT +css-selector-tokenizer,0.6.0,MIT css-selector-tokenizer,0.7.0,MIT css_parser,1.5.0,MIT cssesc,0.1.0,MIT @@ -250,11 +290,16 @@ cssnano,3.10.0,MIT csso,2.3.2,MIT currently-unhandled,0.4.1,MIT custom-event,1.0.1,MIT +d,0.1.1,MIT d,1.0.0,MIT d3,3.5.11,New BSD d3_rails,3.5.11,MIT +dashdash,1.14.1,MIT date-now,0.1.4,MIT de-indent,1.0.2,MIT +debug,2.2.0,MIT +debug,2.3.3,MIT +debug,2.6.7,MIT debug,2.6.8,MIT debugger-ruby_core_source,1.3.8,MIT decamelize,1.2.0,MIT @@ -269,7 +314,11 @@ default-require-extensions,1.0.0,MIT default_value_for,3.0.2,MIT defined,1.0.0,MIT del,2.2.2,MIT +del,3.0.0,MIT +delayed-stream,1.0.0,MIT delegate,3.1.2,MIT +delegates,1.0.0,MIT +depd,1.1.0,MIT depd,1.1.1,MIT des.js,1.0.0,MIT descendants_tracker,0.0.4,MIT @@ -285,12 +334,14 @@ diffy,3.1.0,MIT dns-equal,1.0.0,MIT dns-packet,1.2.2,MIT dns-txt,2.0.2,MIT +doctrine,1.5.0,BSD doctrine,2.0.0,Apache 2.0 document-register-element,1.3.0,MIT dom-serialize,2.2.1,MIT dom-serializer,0.1.0,MIT domain-browser,1.1.7,MIT domain_name,0.5.20161021,"Simplified BSD,New BSD,Mozilla Public License 2.0" +domelementtype,1.1.3,unknown domelementtype,1.3.0,unknown domhandler,2.3.0,unknown domutils,1.5.1,unknown @@ -298,9 +349,10 @@ doorkeeper,4.2.6,MIT doorkeeper-openid_connect,1.2.0,MIT dropzone,4.2.0,MIT dropzonejs-rails,0.7.2,MIT -duplexer,0.1.1,[Circular] +duplexer,0.1.1,MIT duplexer3,0.1.4,New BSD duplexify,3.5.1,MIT +ecc-jsbn,0.1.1,MIT editorconfig,0.13.2,MIT ee-first,1.1.1,MIT ejs,2.5.6,Apache 2.0 @@ -315,6 +367,7 @@ end-of-stream,1.4.0,MIT engine.io,1.8.3,MIT engine.io-client,1.8.3,MIT engine.io-parser,1.3.2,MIT +enhanced-resolve,0.9.1,MIT enhanced-resolve,3.4.1,MIT ent,2.2.0,MIT entities,1.1.1,BSD-like @@ -346,9 +399,12 @@ eslint-plugin-jasmine,2.2.0,MIT eslint-plugin-promise,3.5.0,ISC espree,3.5.0,Simplified BSD esprima,2.7.3,Simplified BSD +esprima,4.0.0,Simplified BSD esquery,1.0.0,BSD esrecurse,4.1.0,Simplified BSD +estraverse,1.9.3,BSD estraverse,4.1.1,Simplified BSD +estraverse,4.2.0,Simplified BSD esutils,2.0.2,BSD et-orbi,1.0.3,MIT etag,1.8.0,MIT @@ -365,12 +421,14 @@ execjs,2.6.0,MIT exit-hook,1.1.1,MIT expand-braces,0.1.2,MIT expand-brackets,0.1.5,MIT +expand-range,0.1.1,MIT expand-range,1.8.2,MIT exports-loader,0.6.4,MIT express,4.15.4,MIT expression_parser,0.9.0,MIT extend,3.0.1,MIT extglob,0.3.2,MIT +extsprintf,1.0.2,MIT faraday,0.12.2,MIT faraday_middleware,0.11.0.1,MIT faraday_middleware-multi_json,0.0.6,MIT @@ -378,6 +436,8 @@ fast-deep-equal,1.0.0,MIT fast-levenshtein,2.0.6,MIT fast_gettext,1.4.0,"MIT,ruby" fastparse,1.1.1,MIT +faye-websocket,0.10.0,MIT +faye-websocket,0.11.1,MIT faye-websocket,0.7.3,MIT ffi,1.9.18,New BSD figures,1.7.0,MIT @@ -386,17 +446,19 @@ file-loader,0.11.1,MIT filename-regex,2.0.0,MIT fileset,2.0.3,MIT filesize,3.3.0,New BSD +filesize,3.5.10,New BSD fill-range,2.2.3,MIT finalhandler,1.0.4,MIT find-cache-dir,1.0.0,MIT find-root,0.1.2,MIT +find-up,1.1.2,MIT find-up,2.1.0,MIT flat-cache,1.2.2,MIT flatten,1.0.2,MIT flipper,0.10.2,MIT flipper-active_record,0.10.2,MIT flowdock,0.7.1,MIT -fog-aliyun,0.1.0,MIT +fog-aliyun,0.2.0,MIT fog-aws,1.4.0,MIT fog-core,1.44.3,MIT fog-google,0.5.3,MIT @@ -409,6 +471,8 @@ follow-redirects,1.2.3,MIT font-awesome-rails,4.7.0.1,"MIT,SIL Open Font License" for-in,0.1.6,MIT for-own,0.1.4,MIT +forever-agent,0.6.1,Apache 2.0 +form-data,2.1.4,MIT formatador,0.2.5,MIT forwarded,0.1.0,MIT fresh,0.5.0,MIT @@ -416,8 +480,12 @@ from,0.1.7,MIT fs-access,1.0.1,MIT fs-extra,0.26.7,MIT fs.realpath,1.0.0,ISC -fsevents,,unknown +fsevents,1.1.2,MIT +fstream,1.0.11,ISC +fstream-ignore,1.0.5,ISC function-bind,1.1.0,MIT +fuzzaldrin-plus,0.5.0,MIT +gauge,2.7.4,ISC gemnasium-gitlab-service,0.2.6,MIT gemojione,3.3.0,MIT generate-function,2.0.0,MIT @@ -426,30 +494,37 @@ get-caller-file,1.0.2,ISC get-stdin,4.0.1,MIT get-stream,3.0.0,MIT get_process_mem,0.2.0,MIT +getpass,0.1.7,MIT gettext_i18n_rails,1.8.0,MIT gettext_i18n_rails_js,1.2.0,MIT -gitaly-proto,0.41.0,MIT +gitaly-proto,0.51.0,MIT github-linguist,4.7.6,MIT github-markup,1.6.1,MIT gitlab-flowdock-git-hook,1.0.1,MIT gitlab-grit,2.8.2,MIT -gitlab-markup,1.6.2,MIT +gitlab-markup,1.6.3,MIT gitlab-svgs,1.0.4,unknown gitlab_omniauth-ldap,2.0.4,MIT +glob,5.0.15,ISC glob,6.0.4,ISC +glob,7.1.1,ISC +glob,7.1.2,ISC glob-base,0.3.0,MIT glob-parent,2.0.0,ISC globalid,0.3.7,MIT globals,9.18.0,MIT globby,5.0.0,MIT +globby,6.1.0,MIT gollum-grit_adapter,1.0.1,MIT gollum-lib,4.2.7,MIT gollum-rugged_adapter,0.4.4,MIT gon,6.1.0,MIT good-listener,1.2.2,MIT google-api-client,0.13.6,Apache 2.0 -google-protobuf,3.4.0.2,New BSD +google-protobuf,3.4.1.1,New BSD +googleapis-common-protos-types,1.0.0,Apache 2.0 googleauth,0.5.3,Apache 2.0 +got,3.3.1,MIT got,7.1.0,MIT gpgme,2.0.13,LGPL-2.1+ graceful-fs,4.1.11,ISC @@ -458,25 +533,31 @@ grape,1.0.0,MIT grape-entity,0.6.0,MIT grape-route-helpers,2.1.0,MIT grape_logging,1.7.0,MIT -grpc,1.6.0,Apache 2.0 +grpc,1.6.6,Apache 2.0 gzip-size,3.0.0,MIT hamlit,2.6.1,MIT handle-thing,1.2.5,MIT handlebars,4.0.6,MIT +har-schema,1.0.5,ISC +har-validator,4.2.1,ISC has,1.0.1,MIT has-ansi,2.0.0,MIT has-binary,0.1.7,MIT has-cors,1.1.0,MIT +has-flag,1.0.0,MIT has-flag,2.0.0,MIT has-symbol-support-x,1.3.0,MIT has-to-string-tag-x,1.3.0,MIT +has-unicode,2.0.1,ISC hash-sum,1.0.2,MIT hash.js,1.0.3,MIT hashie,3.5.6,MIT hashie-forbidden_attributes,0.1.1,MIT +hawk,3.1.3,New BSD he,1.1.1,MIT health_check,2.6.0,MIT hipchat,1.5.2,MIT +hoek,2.16.3,New BSD home-or-tmp,2.0.0,MIT hosted-git-info,2.2.0,ISC hpack.js,2.1.6,MIT @@ -489,10 +570,12 @@ htmlparser2,3.9.2,MIT http,0.9.8,MIT http-cookie,1.0.3,MIT http-deceiver,1.2.7,MIT +http-errors,1.6.1,MIT http-errors,1.6.2,MIT http-form_data,1.0.1,MIT http-proxy,1.16.2,MIT http-proxy-middleware,0.17.4,MIT +http-signature,1.1.1,MIT http_parser.rb,0.6.0,MIT httparty,0.13.7,MIT httpclient,2.8.2,ruby @@ -513,6 +596,7 @@ indexof,0.0.1,unknown infinity-agent,2.0.3,MIT inflight,1.0.6,ISC influxdb,0.2.3,MIT +inherits,2.0.1,ISC inherits,2.0.3,ISC ini,1.3.4,ISC inquirer,0.12.0,MIT @@ -532,12 +616,16 @@ is-builtin-module,1.0.0,MIT is-dotfile,1.0.2,MIT is-equal-shallow,0.1.3,MIT is-extendable,0.1.1,MIT +is-extglob,1.0.0,MIT is-extglob,2.1.1,MIT is-finite,1.0.2,MIT +is-fullwidth-code-point,1.0.0,MIT is-fullwidth-code-point,2.0.0,MIT +is-glob,2.0.1,MIT is-glob,3.1.0,MIT is-my-json-valid,2.16.0,MIT is-npm,1.0.0,MIT +is-number,0.1.1,MIT is-number,2.1.0,MIT is-object,1.0.1,MIT is-path-cwd,1.0.0,MIT @@ -553,13 +641,16 @@ is-resolvable,1.0.0,MIT is-retry-allowed,1.1.0,MIT is-stream,1.1.0,MIT is-svg,2.1.0,MIT +is-typedarray,1.0.0,MIT is-unc-path,0.1.2,MIT is-utf8,0.2.1,MIT is-windows,0.2.0,MIT +isarray,0.0.1,MIT isarray,1.0.0,MIT isbinaryfile,3.0.2,MIT -isexe,2.0.0,ISC +isexe,1.1.2,ISC isobject,2.1.0,MIT +isstream,0.1.2,MIT istanbul,0.4.5,New BSD istanbul-api,1.1.1,New BSD istanbul-lib-coverage,1.0.1,New BSD @@ -573,6 +664,7 @@ jasmine-core,2.6.3,MIT jasmine-jquery,2.1.1,MIT jed,1.1.1,MIT jira-ruby,1.4.1,MIT +jodid25519,1.0.2,MIT jquery,2.2.1,MIT jquery-atwho-rails,1.3.2,MIT jquery-rails,4.1.1,MIT @@ -582,18 +674,23 @@ js-beautify,1.6.12,MIT js-cookie,2.1.3,MIT js-tokens,3.0.1,MIT js-yaml,3.7.0,MIT +js-yaml,3.9.1,MIT +jsbn,0.1.1,MIT +jsesc,0.5.0,MIT jsesc,1.3.0,MIT json,1.8.6,ruby json-jwt,1.7.2,MIT json-loader,0.5.7,MIT +json-schema,0.2.3,"AFLv2.1,BSD" json-schema-traverse,0.3.1,MIT json-stable-stringify,1.0.1,MIT json-stringify-safe,5.0.1,ISC -json3,3.3.2,[Circular] +json3,3.3.2,MIT json5,0.5.1,MIT jsonfile,2.4.0,MIT jsonify,0.0.0,Public Domain jsonpointer,4.0.1,MIT +jsprim,1.4.0,MIT jszip,3.1.3,(MIT OR GPL-3.0) jszip-utils,0.0.2,MIT or GPLv3 jwt,1.5.6,MIT @@ -619,11 +716,14 @@ levn,0.3.0,MIT licensee,8.7.0,MIT lie,3.1.1,MIT little-plugger,1.1.4,MIT +load-json-file,1.1.0,MIT load-json-file,2.0.0,MIT loader-runner,2.3.0,MIT +loader-utils,0.2.16,MIT loader-utils,1.1.0,MIT locale,2.1.2,"ruby,LGPLv3+" locate-path,2.0.0,MIT +lodash,3.10.1,MIT lodash,4.17.4,MIT lodash._baseassign,3.2.0,MIT lodash._basecopy,3.0.1,MIT @@ -634,11 +734,13 @@ lodash._getnative,3.9.1,MIT lodash._isiterateecall,3.0.9,MIT lodash._topath,3.8.1,MIT lodash.assign,3.2.0,MIT +lodash.camelcase,4.1.1,MIT lodash.camelcase,4.3.0,MIT lodash.capitalize,4.2.1,MIT lodash.cond,4.5.2,MIT lodash.deburr,4.1.0,MIT lodash.defaults,3.1.2,MIT +lodash.get,3.7.0,MIT lodash.get,4.4.2,MIT lodash.isarguments,3.1.0,MIT lodash.isarray,3.0.4,MIT @@ -658,7 +760,9 @@ loofah,2.0.3,MIT loose-envify,1.3.1,MIT loud-rejection,1.6.0,MIT lowercase-keys,1.0.0,MIT +lru-cache,2.2.4,MIT lru-cache,3.2.0,ISC +lru-cache,4.0.2,ISC macaddress,0.2.8,MIT mail,2.6.6,MIT mail_room,0.9.1,MIT @@ -670,6 +774,7 @@ math-expression-evaluator,1.2.16,MIT media-typer,0.3.0,MIT mem,1.1.0,MIT memoist,0.16.0,MIT +memory-fs,0.2.0,MIT memory-fs,0.4.1,MIT meow,3.7.0,MIT merge-descriptors,1.0.1,MIT @@ -677,8 +782,10 @@ method_source,0.8.2,MIT methods,1.1.2,MIT micromatch,2.3.11,MIT miller-rabin,4.0.0,MIT -mime,1.3.4,[Circular] +mime,1.3.4,MIT +mime-db,1.27.0,MIT mime-db,1.29.0,MIT +mime-types,2.1.15,MIT mime-types,3.1,MIT mime-types-data,3.2016.0521,MIT mimemagic,0.3.0,MIT @@ -687,13 +794,17 @@ mimic-response,1.0.0,MIT mini_portile2,2.3.0,MIT minimalistic-assert,1.0.0,ISC minimatch,3.0.3,ISC +minimatch,3.0.4,ISC minimist,0.0.8,MIT +minimist,1.2.0,MIT mkdirp,0.5.1,MIT mmap2,2.2.7,ruby moment,2.17.1,MIT -monaco-editor,0.8.3,MIT +monaco-editor,0.10.0,MIT mousetrap,1.4.6,Apache 2.0 mousetrap-rails,1.4.6,"MIT,Apache" +ms,0.7.1,MIT +ms,0.7.2,MIT ms,2.0.0,MIT multi_json,1.12.2,MIT multi_xml,0.6.0,MIT @@ -703,7 +814,9 @@ multipart-post,2.0.0,MIT mustermann,1.0.0,MIT mustermann-grape,1.0.0,MIT mute-stream,0.0.5,ISC +mysql2,0.4.5,MIT name-all-modules-plugin,1.0.1,MIT +nan,2.6.2,MIT natural-compare,1.4.0,MIT negotiator,0.6.1,MIT nested-error-stacks,1.0.2,MIT @@ -712,21 +825,30 @@ net-ssh,4.1.0,MIT netrc,0.11.0,MIT node-dir,0.1.17,MIT node-forge,0.6.33,BSD +node-libs-browser,1.1.1,MIT node-libs-browser,2.0.0,MIT +node-pre-gyp,0.6.36,New BSD +node-pre-gyp,0.6.37,New BSD nodemon,1.11.0,MIT nokogiri,1.8.1,MIT +nopt,1.0.10,MIT nopt,3.0.6,ISC -normalize-package-data,2.3.5,Simplified BSD +nopt,4.0.1,ISC +normalize-package-data,2.4.0,Simplified BSD normalize-path,2.1.1,MIT normalize-range,0.1.2,MIT normalize-url,1.9.1,MIT npm-run-path,2.0.2,MIT +npmlog,4.1.0,ISC null-check,1.0.0,MIT num2fraction,1.2.2,MIT number-is-nan,1.0.1,MIT numerizer,0.1.1,MIT oauth,0.5.1,MIT +oauth-sign,0.8.2,Apache 2.0 oauth2,1.4.0,MIT +object-assign,3.0.0,MIT +object-assign,4.1.0,MIT object-assign,4.1.1,MIT object-component,0.0.3,unknown object.omit,2.0.1,MIT @@ -766,6 +888,7 @@ orm_adapter,0.5.0,MIT os,0.9.6,MIT os-browserify,0.2.1,MIT os-homedir,1.0.2,MIT +os-locale,1.4.0,MIT os-locale,2.1.0,MIT os-tmpdir,1.0.2,MIT osenv,0.1.4,ISC @@ -776,6 +899,7 @@ p-locate,2.0.0,MIT p-map,1.1.1,MIT p-timeout,1.2.0,MIT package-json,1.2.0,MIT +pako,0.2.9,MIT pako,1.0.5,(MIT AND Zlib) paranoia,2.3.1,MIT parse-asn1,5.0.0,ISC @@ -786,28 +910,34 @@ parseqs,0.0.5,MIT parseuri,0.0.5,MIT parseurl,1.3.1,MIT path-browserify,0.0.0,MIT +path-exists,2.1.0,MIT path-exists,3.0.0,MIT path-is-absolute,1.0.1,MIT path-is-inside,1.0.2,(WTFPL OR MIT) path-key,2.0.1,MIT path-parse,1.0.5,MIT path-to-regexp,0.1.7,MIT +path-type,1.1.0,MIT path-type,2.0.0,MIT pause-stream,0.0.11,"MIT,Apache2" pbkdf2,3.0.9,MIT peek,1.0.1,MIT peek-gc,0.0.2,MIT peek-host,1.0.0,MIT +peek-mysql2,1.1.0,MIT peek-performance_bar,1.3.0,MIT peek-pg,1.3.0,MIT peek-rblineprof,0.2.0,MIT peek-redis,1.2.0,MIT peek-sidekiq,1.0.3,MIT +performance-now,0.2.0,MIT pg,0.18.4,"BSD,ruby,GPL" pify,2.3.0,MIT -pikaday,1.5.1,"BSD,MIT" +pify,3.0.0,MIT +pikaday,1.6.1,MIT pinkie,2.0.4,MIT pinkie-promise,2.0.1,MIT +pkg-dir,1.0.0,MIT pkg-dir,2.0.0,MIT pkg-up,1.0.0,MIT pluralize,1.2.1,MIT @@ -860,7 +990,7 @@ private,0.1.7,MIT process,0.11.9,MIT process-nextick-args,1.0.7,MIT progress,1.1.8,MIT -prometheus-client-mmap,0.7.0.beta14,Apache 2.0 +prometheus-client-mmap,0.7.0.beta18,Apache 2.0 proto-list,1.2.4,ISC proxy-addr,1.1.5,MIT prr,0.0.0,MIT @@ -868,15 +998,18 @@ ps-tree,1.1.0,MIT pseudomap,1.0.2,ISC public-encrypt,4.0.0,MIT public_suffix,3.0.0,MIT +punycode,1.3.2,MIT punycode,1.4.1,MIT pyu-ruby-sasl,0.0.3.3,MIT q,1.5.0,MIT qjobs,1.1.5,MIT +qs,6.4.0,New BSD qs,6.5.0,New BSD query-string,4.3.2,MIT querystring,0.2.0,MIT -querystring-es3,0.2.1,[Circular] +querystring-es3,0.2.1,MIT querystringify,0.0.4,MIT +querystringify,1.0.0,MIT rack,1.6.8,MIT rack-accept,0.4.5,MIT rack-attack,4.4.1,MIT @@ -908,9 +1041,14 @@ rdoc,4.2.2,ruby re2,1.1.1,New BSD react-dev-utils,0.5.2,New BSD read-all-stream,3.1.0,MIT +read-pkg,1.1.0,MIT read-pkg,2.0.0,MIT +read-pkg-up,1.0.1,MIT read-pkg-up,2.0.0,MIT +readable-stream,1.0.34,MIT readable-stream,2.0.6,MIT +readable-stream,2.2.9,MIT +readable-stream,2.3.3,MIT readdirp,2.1.0,MIT readline2,1.0.1,MIT recaptcha,3.0.0,MIT @@ -932,21 +1070,26 @@ regenerate,1.3.2,MIT regenerator-runtime,0.10.1,MIT regenerator-transform,0.9.8,BSD regex-cache,0.4.3,MIT +regexpu-core,1.0.0,MIT regexpu-core,2.0.0,MIT registry-url,3.1.0,MIT regjsgen,0.2.0,MIT regjsparser,0.1.5,BSD remove-trailing-separator,1.1.0,ISC repeat-element,1.1.2,MIT +repeat-string,0.2.2,MIT repeat-string,1.6.1,MIT +repeating,1.1.3,MIT repeating,2.0.1,MIT representable,3.0.4,MIT +request,2.81.0,Apache 2.0 request_store,1.3.1,MIT require-directory,2.1.1,MIT require-from-string,1.2.1,MIT require-main-filename,1.0.1,ISC require-uncached,1.0.3,MIT requires-port,1.0.0,MIT +resolve,1.1.7,MIT resolve,1.2.0,MIT resolve-from,1.0.1,MIT responders,2.3.0,MIT @@ -972,6 +1115,7 @@ rugged,0.26.0,MIT run-async,0.1.0,MIT rx-lite,3.1.2,Apache 2.0 safe-buffer,5.0.1,MIT +safe-buffer,5.1.1,MIT safe_yaml,1.0.4,MIT sanitize,2.1.0,MIT sass,3.4.22,MIT @@ -985,6 +1129,7 @@ select-hose,2.0.0,MIT select2,3.5.2-browserify,unknown select2-rails,3.5.9.3,MIT selfsigned,1.10.1,MIT +semver,4.3.6,ISC semver,5.3.0,ISC semver-diff,2.1.0,MIT send,0.15.4,MIT @@ -1011,14 +1156,20 @@ slack-notifier,1.5.1,MIT slash,1.0.0,MIT slice-ansi,0.0.4,MIT slide,1.1.6,ISC +sntp,1.0.9,BSD socket.io,1.7.3,MIT socket.io-adapter,0.5.0,MIT socket.io-client,1.7.3,MIT socket.io-parser,2.3.1,MIT sockjs,0.3.18,MIT sockjs-client,1.0.1,MIT +sockjs-client,1.1.4,MIT sort-keys,1.1.2,MIT +source-list-map,0.1.8,MIT source-list-map,2.0.0,MIT +source-map,0.1.43,BSD +source-map,0.2.0,BSD +source-map,0.4.4,New BSD source-map,0.5.6,New BSD source-map-support,0.4.11,MIT spdx-correct,1.0.2,Apache 2.0 @@ -1031,6 +1182,7 @@ sprintf-js,1.0.3,New BSD sprockets,3.7.1,MIT sprockets-rails,3.2.0,MIT sql.js,0.4.0,MIT +sshpk,1.13.0,MIT state_machines,0.4.0,MIT state_machines-activemodel,0.4.0,MIT state_machines-activerecord,0.4.0,MIT @@ -1042,19 +1194,29 @@ stream-shift,1.0.0,MIT strict-uri-encode,1.1.0,MIT string-length,1.0.1,MIT string-width,1.0.2,MIT +string-width,2.0.0,MIT string_decoder,0.10.31,MIT +string_decoder,1.0.1,MIT +string_decoder,1.0.3,MIT stringex,2.7.1,MIT +stringstream,0.0.5,MIT strip-ansi,3.0.1,MIT +strip-bom,2.0.0,MIT strip-bom,3.0.0,MIT strip-eof,1.0.0,MIT strip-indent,1.0.1,MIT strip-json-comments,2.0.1,MIT +supports-color,2.0.0,MIT supports-color,3.2.3,MIT +supports-color,4.2.1,MIT svg4everybody,2.1.9,CC0-1.0 svgo,0.7.2,MIT sys-filesystem,1.1.6,Artistic 2.0 table,3.8.3,New BSD +tapable,0.1.10,MIT tapable,0.2.8,MIT +tar,2.2.1,ISC +tar-pack,3.4.0,Simplified BSD temple,0.7.7,MIT test-exclude,4.0.0,ISC text,1.3.1,MIT @@ -1067,9 +1229,10 @@ three-stl-loader,1.0.4,MIT through,2.3.8,MIT thunky,0.1.0,unknown tilt,2.0.6,MIT -time-stamp,2.0.0,MIT timeago.js,2.0.5,MIT +timed-out,2.0.0,MIT timed-out,4.0.1,MIT +timers-browserify,1.4.2,MIT timers-browserify,2.0.4,MIT timfel-krb5-auth,0.8.3,LGPL tiny-emitter,1.1.0,MIT @@ -1079,15 +1242,20 @@ to-arraybuffer,1.0.1,MIT to-fast-properties,1.0.2,MIT toml-rb,0.3.15,MIT touch,1.0.0,ISC +tough-cookie,2.3.2,New BSD traverse,0.6.6,MIT trim-newlines,1.0.0,MIT trim-right,1.0.1,MIT truncato,0.7.10,MIT tryit,1.0.3,MIT +ts-loader,3.1.1,MIT tty-browserify,0.0.0,MIT +tunnel-agent,0.6.0,Apache 2.0 +tweetnacl,0.14.5,Unlicense type-check,0.3.2,MIT type-is,1.6.15,MIT typedarray,0.0.6,MIT +typescript,2.6.1,Apache 2.0 tzinfo,1.2.3,MIT u2f,0.2.1,MIT uber,0.1.0,MIT @@ -1095,6 +1263,8 @@ uglifier,2.7.2,MIT uglify-js,2.8.29,Simplified BSD uglify-to-browserify,1.0.2,MIT uglifyjs-webpack-plugin,0.4.6,MIT +uid-number,0.0.6,ISC +ultron,1.0.2,MIT ultron,1.1.0,MIT unc-path-regex,0.1.2,MIT undefsafe,0.0.3,MIT / http://rem.mit-license.org @@ -1111,6 +1281,8 @@ update-notifier,0.5.0,Simplified BSD url,0.11.0,MIT url-loader,0.5.8,MIT url-parse,1.0.5,MIT +url-parse,1.1.7,MIT +url-parse,1.1.9,MIT url-parse-lax,1.0.0,MIT url-to-options,1.0.1,MIT url_safe_base64,0.2.2,MIT @@ -1118,26 +1290,28 @@ user-home,2.0.0,MIT useragent,2.2.1,MIT util,0.10.3,MIT util-deprecate,1.0.2,MIT -utils-merge,1.0.0,[Circular] +utils-merge,1.0.0,MIT uuid,2.0.3,MIT +uuid,3.0.1,MIT validate-npm-package-license,3.0.1,Apache 2.0 validates_hostname,1.0.6,MIT vary,1.1.1,MIT vendors,1.0.1,MIT +verror,1.3.6,MIT version_sorter,2.1.0,MIT virtus,1.0.5,MIT visibilityjs,1.2.4,MIT vm-browserify,0.0.4,MIT vmstat,2.3.0,MIT void-elements,2.0.1,MIT -vue,2.2.6,MIT +vue,2.5.2,MIT vue-hot-reload-api,2.0.11,MIT vue-loader,11.3.4,MIT vue-resource,1.3.4,MIT vue-style-loader,2.0.5,MIT -vue-template-compiler,2.2.6,MIT +vue-template-compiler,2.5.2,MIT vue-template-es2015-compiler,1.5.1,MIT -vuex,2.3.1,MIT +vuex,3.0.0,MIT warden,1.2.6,MIT watchpack,1.4.0,MIT wbuf,1.7.2,MIT @@ -1151,15 +1325,20 @@ webpack-stats-plugin,0.1.5,MIT websocket-driver,0.6.5,MIT websocket-extensions,0.1.1,MIT whet.extend,0.9.9,MIT -which,1.3.0,ISC +which,1.2.12,ISC +which-module,1.0.0,ISC which-module,2.0.0,ISC +wide-align,1.1.2,ISC wikicloth,0.8.1,MIT window-size,0.1.0,MIT +wordwrap,0.0.2,MIT/X11 +wordwrap,0.0.3,MIT wordwrap,1.0.0,MIT wrap-ansi,2.1.0,MIT wrappy,1.0.2,ISC write,0.2.1,MIT write-file-atomic,1.3.4,ISC +ws,1.1.2,MIT ws,2.3.1,MIT wtf-8,1.0.0,MIT xdg-basedir,2.0.0,MIT @@ -1168,6 +1347,9 @@ xmlhttprequest-ssl,1.5.3,MIT xtend,4.0.1,MIT y18n,3.2.1,ISC yallist,2.1.2,ISC +yargs,3.10.0,MIT +yargs,6.6.0,MIT yargs,8.0.2,MIT +yargs-parser,4.2.1,ISC yargs-parser,7.0.0,ISC yeast,0.1.2,MIT diff --git a/yarn.lock b/yarn.lock index efae3892c31..bf92370d44f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -101,12 +101,6 @@ ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" -ansi-styles@^3.1.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.0.tgz#c159b8d5be0f9e5a6f346dab94f16ce022161b88" - dependencies: - color-convert "^1.9.0" - anymatch@^1.3.0: version "1.3.2" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a" @@ -223,12 +217,18 @@ async@1.x, async@^1.4.0, async@^1.4.2, async@^1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" -async@2.4.1, async@^2.1.2, async@^2.1.4: +async@2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/async/-/async-2.4.1.tgz#62a56b279c98a11d0987096a01cc3eeb8eb7bbd7" dependencies: lodash "^4.14.0" +async@^2.1.2, async@^2.1.4: + version "2.5.0" + resolved "https://registry.yarnpkg.com/async/-/async-2.5.0.tgz#843190fd6b7357a0b9e1c956edddd5ec8462b54d" + dependencies: + lodash "^4.14.0" + async@~0.9.0: version "0.9.2" resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" @@ -267,7 +267,7 @@ axios@^0.16.2: follow-redirects "^1.2.3" is-buffer "^1.1.5" -babel-code-frame@^6.11.0, babel-code-frame@^6.16.0, babel-code-frame@^6.22.0: +babel-code-frame@^6.11.0, babel-code-frame@^6.22.0: version "6.22.0" resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.22.0.tgz#027620bee567a88c32561574e7fd0801d33118e4" dependencies: @@ -275,6 +275,14 @@ babel-code-frame@^6.11.0, babel-code-frame@^6.16.0, babel-code-frame@^6.22.0: esutils "^2.0.2" js-tokens "^3.0.0" +babel-code-frame@^6.16.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" + dependencies: + chalk "^1.1.3" + esutils "^2.0.2" + js-tokens "^3.0.2" + babel-core@^6.22.1, babel-core@^6.23.0: version "6.23.1" resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.23.1.tgz#c143cb621bb2f621710c220c5d579d15b8a442df" @@ -924,7 +932,11 @@ bluebird@^2.10.2: version "2.11.0" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-2.11.0.tgz#534b9033c022c9579c56ba3b3e5a5caafbb650e1" -bluebird@^3.0.5, bluebird@^3.1.1, bluebird@^3.3.0: +bluebird@^3.0.5, bluebird@^3.1.1: + version "3.4.7" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.4.7.tgz#f72d760be09b7f76d08ed8fae98b289a8d05fab3" + +bluebird@^3.3.0: version "3.5.0" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.0.tgz#791420d7f551eea2897453a8a77653f96606d67c" @@ -1055,6 +1067,10 @@ buffer-indexof@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/buffer-indexof/-/buffer-indexof-1.1.0.tgz#f54f647c4f4e25228baa656a2e57e43d5f270982" +buffer-shims@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/buffer-shims/-/buffer-shims-1.0.0.tgz#9978ce317388c649ad8793028c3477ef044a8b51" + buffer-xor@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" @@ -1154,14 +1170,6 @@ chalk@1.1.3, chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3: strip-ansi "^3.0.0" supports-color "^2.0.0" -chalk@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.0.tgz#b5ea48efc9c1793dccc9b4767c93914d3f2d52ba" - dependencies: - ansi-styles "^3.1.0" - escape-string-regexp "^1.0.5" - supports-color "^4.0.0" - chokidar@^1.4.1, chokidar@^1.4.3, chokidar@^1.6.0, chokidar@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" @@ -1245,7 +1253,7 @@ code-point-at@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" -color-convert@^1.3.0, color-convert@^1.9.0: +color-convert@^1.3.0: version "1.9.0" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.0.tgz#1accf97dd739b983bf994d56fec8f95853641b7a" dependencies: @@ -1446,7 +1454,11 @@ copy-webpack-plugin@^4.0.1: minimatch "^3.0.0" node-dir "^0.1.10" -core-js@^2.2.0, core-js@^2.4.0, core-js@^2.4.1: +core-js@^2.2.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.0.tgz#569c050918be6486b3837552028ae0466b717086" + +core-js@^2.4.0, core-js@^2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e" @@ -1985,7 +1997,7 @@ engine.io@1.8.3: engine.io-parser "1.3.2" ws "1.1.2" -enhanced-resolve@^3.0.0, enhanced-resolve@^3.4.0: +enhanced-resolve@^3.4.0: version "3.4.1" resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-3.4.1.tgz#0421e339fd71419b3da13d129b3979040230476e" dependencies: @@ -2066,7 +2078,11 @@ es6-map@^0.1.3: es6-symbol "~3.1.1" event-emitter "~0.3.5" -es6-promise@^3.0.2, es6-promise@~3.0.2: +es6-promise@^3.0.2: + version "3.3.1" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.3.1.tgz#a08cdde84ccdbf34d027a1451bc91d4bcd28a613" + +es6-promise@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.0.2.tgz#010d5858423a5f118979665f46486a95c6ee2bb6" @@ -2247,6 +2263,10 @@ esprima@2.7.x, esprima@^2.6.0, esprima@^2.7.1: version "2.7.3" resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" +esprima@^3.1.1: + version "3.1.3" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" + esprima@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804" @@ -2647,11 +2667,11 @@ fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2: mkdirp ">=0.5 0" rimraf "2" -function-bind@^1.0.2, function-bind@~1.1.0: +function-bind@^1.0.2: version "1.1.0" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.0.tgz#16176714c801798e4e8f2cf7f7529467bb4a5771" -function-bind@^1.1.1: +function-bind@^1.1.1, function-bind@~1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" @@ -2737,25 +2757,25 @@ glob@^6.0.4: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" +glob@^7.0.0, glob@^7.1.1, glob@~7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" inherits "2" - minimatch "^3.0.2" + minimatch "^3.0.4" once "^1.3.0" path-is-absolute "^1.0.0" -glob@~7.1.2: - version "7.1.2" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" +glob@^7.0.3, glob@^7.0.5: + version "7.1.1" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" inherits "2" - minimatch "^3.0.4" + minimatch "^3.0.2" once "^1.3.0" path-is-absolute "^1.0.0" @@ -2958,10 +2978,14 @@ html-comment-regex@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.1.tgz#668b93776eaae55ebde8f3ad464b307a4963625e" -html-entities@1.2.0, html-entities@^1.2.0: +html-entities@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.0.tgz#41948caf85ce82fed36e4e6a0ed371a6664379e2" +html-entities@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.1.tgz#0df29351f0721163515dfb9e5543e5f6eed5162f" + htmlparser2@^3.8.2: version "3.9.2" resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.9.2.tgz#1bdf87acca0f3f9e53fa4fcceb0f4b4cbb00b338" @@ -3367,6 +3391,10 @@ isexe@^1.1.1: version "1.1.2" resolved "https://registry.yarnpkg.com/isexe/-/isexe-1.1.2.tgz#36f3e22e60750920f5e7241a476a8c6a42275ad0" +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + isobject@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" @@ -3510,7 +3538,18 @@ js-tokens@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.1.tgz#08e9f132484a2c45a30907e9dc4d5567b7f114d7" -js-yaml@3.x, js-yaml@^3.4.3, js-yaml@^3.5.1, js-yaml@^3.7.0: +js-tokens@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" + +js-yaml@3.x, js-yaml@^3.4.3, js-yaml@^3.7.0: + version "3.8.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.8.1.tgz#782ba50200be7b9e5a8537001b7804db3ad02628" + dependencies: + argparse "^1.0.7" + esprima "^3.1.1" + +js-yaml@^3.5.1: version "3.9.1" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.9.1.tgz#08775cebdfdd359209f0d2acd383c8f86a6904a0" dependencies: @@ -4051,7 +4090,7 @@ miller-rabin@^4.0.0: bn.js "^4.0.0" brorand "^1.0.1" -"mime-db@>= 1.29.0 < 2": +"mime-db@>= 1.29.0 < 2", mime-db@~1.29.0: version "1.29.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.29.0.tgz#48d26d235589651704ac5916ca06001914266878" @@ -4059,7 +4098,13 @@ mime-db@~1.27.0: version "1.27.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.27.0.tgz#820f572296bbd20ec25ed55e5b5de869e5436eb1" -mime-types@^2.1.12, mime-types@~2.1.11, mime-types@~2.1.15, mime-types@~2.1.7: +mime-types@^2.1.12, mime-types@~2.1.7: + version "2.1.16" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.16.tgz#2b858a52e5ecd516db897ac2be87487830698e23" + dependencies: + mime-db "~1.29.0" + +mime-types@~2.1.11, mime-types@~2.1.15: version "2.1.15" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.15.tgz#a4ebf5064094569237b8cf70046776d09fc92aed" dependencies: @@ -4283,7 +4328,16 @@ nopt@~1.0.10: dependencies: abbrev "1" -normalize-package-data@^2.3.2, normalize-package-data@^2.3.4: +normalize-package-data@^2.3.2: + version "2.3.5" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.3.5.tgz#8d924f142960e1777e7ffe170543631cc7cb02df" + dependencies: + hosted-git-info "^2.1.4" + is-builtin-module "^1.0.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + +normalize-package-data@^2.3.4: version "2.4.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" dependencies: @@ -4458,7 +4512,7 @@ os-locale@^2.0.0: lcid "^1.0.0" mem "^1.1.0" -os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.1: +os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.1, os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" @@ -5154,7 +5208,7 @@ read-pkg@^2.0.0: normalize-package-data "^2.3.2" path-type "^2.0.0" -readable-stream@^2.0.0, readable-stream@^2.0.6, readable-stream@^2.1.0, readable-stream@^2.1.4, readable-stream@^2.2.2, readable-stream@^2.2.9: +readable-stream@^2.0.0, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.2.2, readable-stream@^2.2.9: version "2.3.3" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c" dependencies: @@ -5177,6 +5231,18 @@ readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable string_decoder "~0.10.x" util-deprecate "~1.0.1" +readable-stream@^2.1.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.2.tgz#a9e6fec3c7dda85f8bb1b3ba7028604556fc825e" + dependencies: + buffer-shims "^1.0.0" + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "~1.0.0" + process-nextick-args "~1.0.6" + string_decoder "~0.10.x" + util-deprecate "~1.0.1" + readable-stream@~1.0.2: version "1.0.34" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" @@ -5462,10 +5528,14 @@ semver-diff@^2.0.0: dependencies: semver "^5.0.3" -"semver@2 || 3 || 4 || 5", semver@^5.0.1, semver@^5.0.3, semver@^5.3.0: +"semver@2 || 3 || 4 || 5", semver@^5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" +semver@^5.0.3: + version "5.4.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" + semver@~4.3.3: version "4.3.6" resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da" @@ -5873,7 +5943,7 @@ supports-color@^3.1.0, supports-color@^3.1.1, supports-color@^3.1.2, supports-co dependencies: has-flag "^1.0.0" -supports-color@^4.0.0, supports-color@^4.2.1: +supports-color@^4.2.1: version "4.2.1" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.2.1.tgz#65a4bb2631e90e02420dba5554c375a4754bb836" dependencies: @@ -5987,6 +6057,10 @@ thunky@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/thunky/-/thunky-0.1.0.tgz#bf30146824e2b6e67b0f2d7a4ac8beb26908684e" +time-stamp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/time-stamp/-/time-stamp-2.0.0.tgz#95c6a44530e15ba8d6f4a3ecb8c3a3fac46da357" + timeago.js@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/timeago.js/-/timeago.js-2.0.5.tgz#730c74fbdb0b0917a553675a4460e3a7f80db86c" @@ -6015,12 +6089,18 @@ tiny-emitter@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-1.1.0.tgz#ab405a21ffed814a76c19739648093d70654fecb" -tmp@0.0.31, tmp@0.0.x: +tmp@0.0.31: version "0.0.31" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.31.tgz#8f38ab9438e17315e5dbd8b3657e8bfb277ae4a7" dependencies: os-tmpdir "~1.0.1" +tmp@0.0.x: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + dependencies: + os-tmpdir "~1.0.2" + to-array@0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890" @@ -6061,15 +6141,6 @@ tryit@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/tryit/-/tryit-1.0.3.tgz#393be730a9446fd1ead6da59a014308f36c289cb" -ts-loader@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-3.1.1.tgz#602d93c12029eaf8fa1ee478a90785d40c5f6658" - dependencies: - chalk "^2.3.0" - enhanced-resolve "^3.0.0" - loader-utils "^1.0.2" - semver "^5.0.1" - tty-browserify@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" @@ -6101,10 +6172,6 @@ typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" -typescript@^2.6.1: - version "2.6.1" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.6.1.tgz#ef39cdea27abac0b500242d6726ab90e0c846631" - uglify-js@^2.6, uglify-js@^2.8.29: version "2.8.29" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd" @@ -6380,7 +6447,7 @@ webpack-bundle-analyzer@^2.8.2: opener "^1.4.3" ws "^2.3.1" -webpack-dev-middleware@^1.0.11, webpack-dev-middleware@^1.11.0: +webpack-dev-middleware@^1.0.11: version "1.11.0" resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-1.11.0.tgz#09691d0973a30ad1f82ac73a12e2087f0a4754f9" dependencies: @@ -6389,6 +6456,16 @@ webpack-dev-middleware@^1.0.11, webpack-dev-middleware@^1.11.0: path-is-absolute "^1.0.0" range-parser "^1.0.3" +webpack-dev-middleware@^1.11.0: + version "1.12.0" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-1.12.0.tgz#d34efefb2edda7e1d3b5dbe07289513219651709" + dependencies: + memory-fs "~0.4.1" + mime "^1.3.4" + path-is-absolute "^1.0.0" + range-parser "^1.0.3" + time-stamp "^2.0.0" + webpack-dev-server@^2.6.1: version "2.7.1" resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-2.7.1.tgz#21580f5a08cd065c71144cf6f61c345bca59a8b8" @@ -6477,12 +6554,18 @@ which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" -which@^1.1.1, which@^1.2.1, which@^1.2.9: +which@^1.1.1, which@^1.2.1: version "1.2.12" resolved "https://registry.yarnpkg.com/which/-/which-1.2.12.tgz#de67b5e450269f194909ef23ece4ebe416fa1192" dependencies: isexe "^1.1.1" +which@^1.2.9: + version "1.3.0" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a" + dependencies: + isexe "^2.0.0" + wide-align@^1.1.0: version "1.1.2" resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710" |