diff options
270 files changed, 2926 insertions, 2584 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1b4134282c9..c0b622f5abd 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,4 +1,4 @@ -image: "dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.4.4-golang-1.9-git-2.18-chrome-67.0-node-8.x-yarn-1.2-postgresql-9.6-graphicsmagick-1.3.29" +image: "dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.4.4-golang-1.9-git-2.18-chrome-69.0-node-8.x-yarn-1.2-postgresql-9.6-graphicsmagick-1.3.29" .dedicated-runner: &dedicated-runner retry: 1 @@ -708,7 +708,6 @@ gitlab:assets:compile: SETUP_DB: "false" SKIP_STORAGE_VALIDATION: "true" WEBPACK_REPORT: "true" - NO_COMPRESSION: "true" # we override the max_old_space_size to prevent OOM errors NODE_OPTIONS: --max_old_space_size=3584 script: @@ -722,6 +721,7 @@ gitlab:assets:compile: expire_in: 31d paths: - webpack-report/ + - public/assets/ karma: <<: *dedicated-no-docs-and-no-qa-pull-cache-job diff --git a/Dangerfile b/Dangerfile index 9217610da8b..46e53edcac4 100644 --- a/Dangerfile +++ b/Dangerfile @@ -4,4 +4,6 @@ danger.import_dangerfile(path: 'danger/changelog') danger.import_dangerfile(path: 'danger/specs') danger.import_dangerfile(path: 'danger/gemfile') danger.import_dangerfile(path: 'danger/database') +danger.import_dangerfile(path: 'danger/documentation') danger.import_dangerfile(path: 'danger/frozen_string') +danger.import_dangerfile(path: 'danger/commit_messages') diff --git a/GITLAB_SHELL_VERSION b/GITLAB_SHELL_VERSION index 2b0aa21219d..56b6be4ebb2 100644 --- a/GITLAB_SHELL_VERSION +++ b/GITLAB_SHELL_VERSION @@ -1 +1 @@ -8.2.1 +8.3.1 @@ -170,7 +170,7 @@ gem 'state_machines-activerecord', '~> 0.5.1' gem 'acts-as-taggable-on', '~> 5.0' # Background jobs -gem 'sidekiq', '~> 5.1' +gem 'sidekiq', '~> 5.2.1' gem 'sidekiq-cron', '~> 0.6.0' gem 'redis-namespace', '~> 1.6.0' gem 'sidekiq-limit_fetch', '~> 3.4', require: false diff --git a/Gemfile.lock b/Gemfile.lock index 3dce80deb87..8c545b7257c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -133,7 +133,7 @@ GEM concurrent-ruby (1.0.5) concurrent-ruby-ext (1.0.5) concurrent-ruby (= 1.0.5) - connection_pool (2.2.1) + connection_pool (2.2.2) crack (0.4.3) safe_yaml (~> 1.0.0) crass (1.0.4) @@ -649,7 +649,7 @@ GEM httpclient (>= 2.4) multi_json (>= 1.3.6) rack (>= 1.1) - rack-protection (2.0.1) + rack-protection (2.0.3) rack rack-proxy (0.6.0) rack @@ -843,9 +843,8 @@ GEM rack shoulda-matchers (3.1.2) activesupport (>= 4.0.0) - sidekiq (5.1.3) - concurrent-ruby (~> 1.0) - connection_pool (~> 2.2, >= 2.2.0) + sidekiq (5.2.1) + connection_pool (~> 2.2, >= 2.2.2) rack-protection (>= 1.5.0) redis (>= 3.3.5, < 5) sidekiq-cron (0.6.0) @@ -1166,7 +1165,7 @@ DEPENDENCIES settingslogic (~> 2.0.9) sham_rack (~> 1.3.6) shoulda-matchers (~> 3.1.2) - sidekiq (~> 5.1) + sidekiq (~> 5.2.1) sidekiq-cron (~> 0.6.0) sidekiq-limit_fetch (~> 3.4) simple_po_parser (~> 1.1.2) diff --git a/Gemfile.rails5.lock b/Gemfile.rails5.lock index e1295e1ff9b..b384592d035 100644 --- a/Gemfile.rails5.lock +++ b/Gemfile.rails5.lock @@ -136,7 +136,7 @@ GEM concurrent-ruby (1.0.5) concurrent-ruby-ext (1.0.5) concurrent-ruby (= 1.0.5) - connection_pool (2.2.1) + connection_pool (2.2.2) crack (0.4.3) safe_yaml (~> 1.0.0) crass (1.0.4) @@ -653,7 +653,7 @@ GEM httpclient (>= 2.4) multi_json (>= 1.3.6) rack (>= 1.1) - rack-protection (2.0.1) + rack-protection (2.0.3) rack rack-proxy (0.6.0) rack @@ -851,9 +851,8 @@ GEM rack shoulda-matchers (3.1.2) activesupport (>= 4.0.0) - sidekiq (5.1.3) - concurrent-ruby (~> 1.0) - connection_pool (~> 2.2, >= 2.2.0) + sidekiq (5.2.1) + connection_pool (~> 2.2, >= 2.2.2) rack-protection (>= 1.5.0) redis (>= 3.3.5, < 5) sidekiq-cron (0.6.0) @@ -1176,7 +1175,7 @@ DEPENDENCIES settingslogic (~> 2.0.9) sham_rack (~> 1.3.6) shoulda-matchers (~> 3.1.2) - sidekiq (~> 5.1) + sidekiq (~> 5.2.1) sidekiq-cron (~> 0.6.0) sidekiq-limit_fetch (~> 3.4) simple_po_parser (~> 1.1.2) diff --git a/app/assets/javascripts/commons/gitlab_ui.js b/app/assets/javascripts/commons/gitlab_ui.js index 923c036f5a4..14c2db24205 100644 --- a/app/assets/javascripts/commons/gitlab_ui.js +++ b/app/assets/javascripts/commons/gitlab_ui.js @@ -1,4 +1,12 @@ import Vue from 'vue'; -import progressBar from '@gitlab-org/gitlab-ui/dist/base/progress_bar'; +import progressBar from '@gitlab-org/gitlab-ui/dist/components/base/progress_bar'; +import modal from '@gitlab-org/gitlab-ui/dist/components/base/modal'; + +import dModal from '@gitlab-org/gitlab-ui/dist/directives/modal'; +import dTooltip from '@gitlab-org/gitlab-ui/dist/directives/tooltip'; Vue.component('gl-progress-bar', progressBar); +Vue.component('gl-ui-modal', modal); + +Vue.directive('gl-modal', dModal); +Vue.directive('gl-tooltip', dTooltip); diff --git a/app/assets/javascripts/diff_notes/components/resolve_discussion_btn.js b/app/assets/javascripts/diff_notes/components/resolve_discussion_btn.js index 5ed13488788..6fcad187b35 100644 --- a/app/assets/javascripts/diff_notes/components/resolve_discussion_btn.js +++ b/app/assets/javascripts/diff_notes/components/resolve_discussion_btn.js @@ -1,4 +1,4 @@ -/* eslint-disable object-shorthand, func-names, comma-dangle, no-else-return, quotes */ +/* eslint-disable object-shorthand, func-names, no-else-return */ /* global CommentsStore */ /* global ResolveService */ @@ -25,44 +25,44 @@ const ResolveDiscussionBtn = Vue.extend({ }; }, computed: { - showButton: function () { + showButton: function() { if (this.discussion) { return this.discussion.isResolvable(); } else { return false; } }, - isDiscussionResolved: function () { + isDiscussionResolved: function() { if (this.discussion) { return this.discussion.isResolved(); } else { return false; } }, - buttonText: function () { + buttonText: function() { if (this.isDiscussionResolved) { - return "Unresolve discussion"; + return 'Unresolve discussion'; } else { - return "Resolve discussion"; + return 'Resolve discussion'; } }, - loading: function () { + loading: function() { if (this.discussion) { return this.discussion.loading; } else { return false; } - } + }, }, - created: function () { + created: function() { CommentsStore.createDiscussion(this.discussionId, this.canResolve); this.discussion = CommentsStore.state[this.discussionId]; }, methods: { - resolve: function () { + resolve: function() { ResolveService.toggleResolveForDiscussion(this.mergeRequestId, this.discussionId); - } + }, }, }); diff --git a/app/assets/javascripts/diff_notes/services/resolve.js b/app/assets/javascripts/diff_notes/services/resolve.js index 0b3568e432d..e69eaad4423 100644 --- a/app/assets/javascripts/diff_notes/services/resolve.js +++ b/app/assets/javascripts/diff_notes/services/resolve.js @@ -8,9 +8,7 @@ window.gl = window.gl || {}; class ResolveServiceClass { constructor(root) { - this.noteResource = Vue.resource( - `${root}/notes{/noteId}/resolve?html=true`, - ); + this.noteResource = Vue.resource(`${root}/notes{/noteId}/resolve?html=true`); this.discussionResource = Vue.resource( `${root}/merge_requests{/mergeRequestId}/discussions{/discussionId}/resolve?html=true`, ); @@ -51,10 +49,7 @@ class ResolveServiceClass { discussion.updateHeadline(data); }) .catch( - () => - new Flash( - 'An error occurred when trying to resolve a discussion. Please try again.', - ), + () => new Flash('An error occurred when trying to resolve a discussion. Please try again.'), ); } diff --git a/app/assets/javascripts/diffs/components/app.vue b/app/assets/javascripts/diffs/components/app.vue index b5b05df4d34..4261a99c52b 100644 --- a/app/assets/javascripts/diffs/components/app.vue +++ b/app/assets/javascripts/diffs/components/app.vue @@ -59,7 +59,7 @@ export default { emailPatchPath: state => state.diffs.emailPatchPath, }), ...mapGetters('diffs', ['isParallelView']), - ...mapGetters(['isNotesFetched']), + ...mapGetters(['isNotesFetched', 'discussionsStructuredByLineCode']), targetBranch() { return { branchName: this.targetBranchName, @@ -112,13 +112,26 @@ export default { }, created() { this.adjustView(); + eventHub.$once('fetchedNotesData', this.setDiscussions); }, methods: { - ...mapActions('diffs', ['setBaseConfig', 'fetchDiffFiles', 'startRenderDiffsQueue']), + ...mapActions('diffs', [ + 'setBaseConfig', + 'fetchDiffFiles', + 'startRenderDiffsQueue', + 'assignDiscussionsToDiff', + ]), + fetchData() { this.fetchDiffFiles() .then(() => { - requestIdleCallback(this.startRenderDiffsQueue, { timeout: 1000 }); + requestIdleCallback( + () => { + this.setDiscussions(); + this.startRenderDiffsQueue(); + }, + { timeout: 1000 }, + ); }) .catch(() => { createFlash(__('Something went wrong on our end. Please try again!')); @@ -128,6 +141,16 @@ export default { eventHub.$emit('fetchNotesData'); } }, + setDiscussions() { + if (this.isNotesFetched) { + requestIdleCallback( + () => { + this.assignDiscussionsToDiff(this.discussionsStructuredByLineCode); + }, + { timeout: 1000 }, + ); + } + }, adjustView() { if (this.shouldShow && this.isParallelView) { window.mrTabs.expandViewContainer(); diff --git a/app/assets/javascripts/diffs/components/diff_discussions.vue b/app/assets/javascripts/diffs/components/diff_discussions.vue index e64d5511d78..cddbe554fbd 100644 --- a/app/assets/javascripts/diffs/components/diff_discussions.vue +++ b/app/assets/javascripts/diffs/components/diff_discussions.vue @@ -1,4 +1,5 @@ <script> +import { mapActions } from 'vuex'; import noteableDiscussion from '../../notes/components/noteable_discussion.vue'; export default { @@ -11,6 +12,14 @@ export default { required: true, }, }, + methods: { + ...mapActions('diffs', ['removeDiscussionsFromDiff']), + deleteNoteHandler(discussion) { + if (discussion.notes.length <= 1) { + this.removeDiscussionsFromDiff(discussion); + } + }, + }, }; </script> @@ -31,6 +40,7 @@ export default { :render-diff-file="false" :always-expanded="true" :discussions-by-diff-order="true" + @noteDeleted="deleteNoteHandler" /> </ul> </div> diff --git a/app/assets/javascripts/diffs/components/diff_file.vue b/app/assets/javascripts/diffs/components/diff_file.vue index 59e9ba08b8b..67e85c4eee3 100644 --- a/app/assets/javascripts/diffs/components/diff_file.vue +++ b/app/assets/javascripts/diffs/components/diff_file.vue @@ -1,5 +1,5 @@ <script> -import { mapActions } from 'vuex'; +import { mapActions, mapGetters } from 'vuex'; import _ from 'underscore'; import { __, sprintf } from '~/locale'; import createFlash from '~/flash'; @@ -30,6 +30,7 @@ export default { }; }, computed: { + ...mapGetters(['isNotesFetched', 'discussionsStructuredByLineCode']), isCollapsed() { return this.file.collapsed || false; }, @@ -44,23 +45,23 @@ export default { ); }, showExpandMessage() { - return this.isCollapsed && !this.isLoadingCollapsedDiff && !this.file.tooLarge; + return ( + !this.isCollapsed && + !this.file.highlightedDiffLines && + !this.isLoadingCollapsedDiff && + !this.file.tooLarge && + this.file.text + ); }, showLoadingIcon() { return this.isLoadingCollapsedDiff || (!this.file.renderIt && !this.isCollapsed); }, }, methods: { - ...mapActions('diffs', ['loadCollapsedDiff']), + ...mapActions('diffs', ['loadCollapsedDiff', 'assignDiscussionsToDiff']), handleToggle() { - const { collapsed, highlightedDiffLines, parallelDiffLines } = this.file; - - if ( - collapsed && - !highlightedDiffLines && - parallelDiffLines !== undefined && - !parallelDiffLines.length - ) { + const { highlightedDiffLines, parallelDiffLines } = this.file; + if (!highlightedDiffLines && parallelDiffLines !== undefined && !parallelDiffLines.length) { this.handleLoadCollapsedDiff(); } else { this.file.collapsed = !this.file.collapsed; @@ -76,6 +77,14 @@ export default { this.file.collapsed = false; this.file.renderIt = true; }) + .then(() => { + requestIdleCallback( + () => { + this.assignDiscussionsToDiff(this.discussionsStructuredByLineCode); + }, + { timeout: 1000 }, + ); + }) .catch(() => { this.isLoadingCollapsedDiff = false; createFlash(__('Something went wrong on our end. Please try again!')); @@ -136,11 +145,11 @@ export default { :diff-file="file" /> <loading-icon - v-else-if="showLoadingIcon" + v-if="showLoadingIcon" class="diff-content loading" /> <div - v-if="showExpandMessage" + v-else-if="showExpandMessage" class="nothing-here-block diff-collapsed" > {{ __('This diff is collapsed.') }} diff --git a/app/assets/javascripts/diffs/components/diff_gutter_avatars.vue b/app/assets/javascripts/diffs/components/diff_gutter_avatars.vue index 7e50a0aed84..a02c41f39ab 100644 --- a/app/assets/javascripts/diffs/components/diff_gutter_avatars.vue +++ b/app/assets/javascripts/diffs/components/diff_gutter_avatars.vue @@ -1,15 +1,11 @@ <script> import { mapActions } from 'vuex'; import Icon from '~/vue_shared/components/icon.vue'; -import tooltip from '~/vue_shared/directives/tooltip'; import { pluralize, truncate } from '~/lib/utils/text_utility'; import UserAvatarImage from '~/vue_shared/components/user_avatar/user_avatar_image.vue'; import { COUNT_OF_AVATARS_IN_GUTTER, LENGTH_OF_AVATAR_TOOLTIP } from '../constants'; export default { - directives: { - tooltip, - }, components: { Icon, UserAvatarImage, @@ -91,10 +87,10 @@ export default { @click.native="toggleDiscussions" /> <span - v-tooltip + v-gl-tooltip v-if="moreText" :title="moreText" - class="diff-comments-more-count has-tooltip js-diff-comment-avatar js-diff-comment-plus" + class="diff-comments-more-count js-diff-comment-avatar js-diff-comment-plus" data-container="body" data-placement="top" role="button" diff --git a/app/assets/javascripts/diffs/components/diff_line_gutter_content.vue b/app/assets/javascripts/diffs/components/diff_line_gutter_content.vue index 8ad1ea34245..6eff3013dcd 100644 --- a/app/assets/javascripts/diffs/components/diff_line_gutter_content.vue +++ b/app/assets/javascripts/diffs/components/diff_line_gutter_content.vue @@ -13,6 +13,10 @@ export default { Icon, }, props: { + line: { + type: Object, + required: true, + }, fileHash: { type: String, required: true, @@ -21,31 +25,16 @@ export default { type: String, required: true, }, - lineType: { - type: String, - required: false, - default: '', - }, lineNumber: { type: Number, required: false, default: 0, }, - lineCode: { - type: String, - required: false, - default: '', - }, linePosition: { type: String, required: false, default: '', }, - metaData: { - type: Object, - required: false, - default: () => ({}), - }, showCommentButton: { type: Boolean, required: false, @@ -76,11 +65,6 @@ export default { required: false, default: false, }, - discussions: { - type: Array, - required: false, - default: () => [], - }, }, computed: { ...mapState({ @@ -89,7 +73,7 @@ export default { }), ...mapGetters(['isLoggedIn']), lineHref() { - return this.lineCode ? `#${this.lineCode}` : '#'; + return `#${this.line.lineCode || ''}`; }, shouldShowCommentButton() { return ( @@ -103,20 +87,19 @@ export default { ); }, hasDiscussions() { - return this.discussions.length > 0; + return this.line.discussions && this.line.discussions.length > 0; }, shouldShowAvatarsOnGutter() { - if (!this.lineType && this.linePosition === LINE_POSITION_RIGHT) { + if (!this.line.type && this.linePosition === LINE_POSITION_RIGHT) { return false; } - return this.showCommentButton && this.hasDiscussions; }, }, methods: { ...mapActions('diffs', ['loadMoreLines', 'showCommentForm']), handleCommentButton() { - this.showCommentForm({ lineCode: this.lineCode }); + this.showCommentForm({ lineCode: this.line.lineCode }); }, handleLoadMoreLines() { if (this.isRequesting) { @@ -125,8 +108,8 @@ export default { this.isRequesting = true; const endpoint = this.contextLinesPath; - const oldLineNumber = this.metaData.oldPos || 0; - const newLineNumber = this.metaData.newPos || 0; + const oldLineNumber = this.line.metaData.oldPos || 0; + const newLineNumber = this.line.metaData.newPos || 0; const offset = newLineNumber - oldLineNumber; const bottom = this.isBottom; const { fileHash } = this; @@ -201,7 +184,7 @@ export default { </a> <diff-gutter-avatars v-if="shouldShowAvatarsOnGutter" - :discussions="discussions" + :discussions="line.discussions" /> </template> </div> diff --git a/app/assets/javascripts/diffs/components/diff_line_note_form.vue b/app/assets/javascripts/diffs/components/diff_line_note_form.vue index cbe4551d06b..a0dc381ccc7 100644 --- a/app/assets/javascripts/diffs/components/diff_line_note_form.vue +++ b/app/assets/javascripts/diffs/components/diff_line_note_form.vue @@ -6,6 +6,7 @@ import noteForm from '../../notes/components/note_form.vue'; import { getNoteFormData } from '../store/utils'; import autosave from '../../notes/mixins/autosave'; import { DIFF_NOTE_TYPE } from '../constants'; +import { reduceDiscussionsToLineCodes } from '../../notes/stores/utils'; export default { components: { @@ -52,7 +53,7 @@ export default { } }, methods: { - ...mapActions('diffs', ['cancelCommentForm']), + ...mapActions('diffs', ['cancelCommentForm', 'assignDiscussionsToDiff']), ...mapActions(['saveNote', 'refetchDiscussionById']), handleCancelCommentForm(shouldConfirm, isDirty) { if (shouldConfirm && isDirty) { @@ -88,7 +89,10 @@ export default { const endpoint = this.getNotesDataByProp('discussionsPath'); this.refetchDiscussionById({ path: endpoint, discussionId: result.discussion_id }) - .then(() => { + .then(selectedDiscussion => { + const lineCodeDiscussions = reduceDiscussionsToLineCodes([selectedDiscussion]); + this.assignDiscussionsToDiff(lineCodeDiscussions); + this.handleCancelCommentForm(); }) .catch(() => { diff --git a/app/assets/javascripts/diffs/components/diff_table_cell.vue b/app/assets/javascripts/diffs/components/diff_table_cell.vue index 33bc8d9971e..5d9a0b123fe 100644 --- a/app/assets/javascripts/diffs/components/diff_table_cell.vue +++ b/app/assets/javascripts/diffs/components/diff_table_cell.vue @@ -11,8 +11,6 @@ import { LINE_HOVER_CLASS_NAME, LINE_UNFOLD_CLASS_NAME, INLINE_DIFF_VIEW_TYPE, - LINE_POSITION_LEFT, - LINE_POSITION_RIGHT, } from '../constants'; export default { @@ -67,42 +65,24 @@ export default { required: false, default: false, }, - discussions: { - type: Array, - required: false, - default: () => [], - }, }, computed: { ...mapGetters(['isLoggedIn']), - normalizedLine() { - let normalizedLine; - - if (this.diffViewType === INLINE_DIFF_VIEW_TYPE) { - normalizedLine = this.line; - } else if (this.linePosition === LINE_POSITION_LEFT) { - normalizedLine = this.line.left; - } else if (this.linePosition === LINE_POSITION_RIGHT) { - normalizedLine = this.line.right; - } - - return normalizedLine; - }, isMatchLine() { - return this.normalizedLine.type === MATCH_LINE_TYPE; + return this.line.type === MATCH_LINE_TYPE; }, isContextLine() { - return this.normalizedLine.type === CONTEXT_LINE_TYPE; + return this.line.type === CONTEXT_LINE_TYPE; }, isMetaLine() { - const { type } = this.normalizedLine; + const { type } = this.line; return ( type === OLD_NO_NEW_LINE_TYPE || type === NEW_NO_NEW_LINE_TYPE || type === EMPTY_CELL_TYPE ); }, classNameMap() { - const { type } = this.normalizedLine; + const { type } = this.line; return { [type]: type, @@ -116,9 +96,9 @@ export default { }; }, lineNumber() { - const { lineType, normalizedLine } = this; + const { lineType } = this; - return lineType === OLD_LINE_TYPE ? normalizedLine.oldLine : normalizedLine.newLine; + return lineType === OLD_LINE_TYPE ? this.line.oldLine : this.line.newLine; }, }, }; @@ -129,20 +109,17 @@ export default { :class="classNameMap" > <diff-line-gutter-content + :line="line" :file-hash="fileHash" :context-lines-path="contextLinesPath" - :line-type="normalizedLine.type" - :line-code="normalizedLine.lineCode" :line-position="linePosition" :line-number="lineNumber" - :meta-data="normalizedLine.metaData" :show-comment-button="showCommentButton" :is-hover="isHover" :is-bottom="isBottom" :is-match-line="isMatchLine" :is-context-line="isContentLine" :is-meta-line="isMetaLine" - :discussions="discussions" /> </td> </template> diff --git a/app/assets/javascripts/diffs/components/inline_diff_comment_row.vue b/app/assets/javascripts/diffs/components/inline_diff_comment_row.vue index 6348f32d36d..46a51859da5 100644 --- a/app/assets/javascripts/diffs/components/inline_diff_comment_row.vue +++ b/app/assets/javascripts/diffs/components/inline_diff_comment_row.vue @@ -21,18 +21,13 @@ export default { type: Number, required: true, }, - discussions: { - type: Array, - required: false, - default: () => [], - }, }, computed: { ...mapState({ diffLineCommentForms: state => state.diffs.diffLineCommentForms, }), className() { - return this.discussions.length ? '' : 'js-temp-notes-holder'; + return this.line.discussions.length ? '' : 'js-temp-notes-holder'; }, }, }; @@ -49,8 +44,8 @@ export default { > <div class="content"> <diff-discussions - v-if="discussions.length" - :discussions="discussions" + v-if="line.discussions.length" + :discussions="line.discussions" /> <diff-line-note-form v-if="diffLineCommentForms[line.lineCode]" diff --git a/app/assets/javascripts/diffs/components/inline_diff_table_row.vue b/app/assets/javascripts/diffs/components/inline_diff_table_row.vue index 32d65ff994f..0e306f39a9f 100644 --- a/app/assets/javascripts/diffs/components/inline_diff_table_row.vue +++ b/app/assets/javascripts/diffs/components/inline_diff_table_row.vue @@ -33,11 +33,6 @@ export default { required: false, default: false, }, - discussions: { - type: Array, - required: false, - default: () => [], - }, }, data() { return { @@ -94,7 +89,6 @@ export default { :is-bottom="isBottom" :is-hover="isHover" :show-comment-button="true" - :discussions="discussions" class="diff-line-num old_line" /> <diff-table-cell @@ -104,7 +98,6 @@ export default { :line-type="newLineType" :is-bottom="isBottom" :is-hover="isHover" - :discussions="discussions" class="diff-line-num new_line" /> <td diff --git a/app/assets/javascripts/diffs/components/inline_diff_view.vue b/app/assets/javascripts/diffs/components/inline_diff_view.vue index e7d789734c3..947e7c98fae 100644 --- a/app/assets/javascripts/diffs/components/inline_diff_view.vue +++ b/app/assets/javascripts/diffs/components/inline_diff_view.vue @@ -2,7 +2,6 @@ import { mapGetters, mapState } from 'vuex'; import inlineDiffTableRow from './inline_diff_table_row.vue'; import inlineDiffCommentRow from './inline_diff_comment_row.vue'; -import { trimFirstCharOfLineContent } from '../store/utils'; export default { components: { @@ -20,29 +19,17 @@ export default { }, }, computed: { - ...mapGetters('diffs', [ - 'commitId', - 'shouldRenderInlineCommentRow', - 'singleDiscussionByLineCode', - ]), + ...mapGetters('diffs', ['commitId', 'shouldRenderInlineCommentRow']), ...mapState({ diffLineCommentForms: state => state.diffs.diffLineCommentForms, }), - normalizedDiffLines() { - return this.diffLines.map(line => (line.richText ? trimFirstCharOfLineContent(line) : line)); - }, diffLinesLength() { - return this.normalizedDiffLines.length; + return this.diffLines.length; }, userColorScheme() { return window.gon.user_color_scheme; }, }, - methods: { - discussionsList(line) { - return line.lineCode !== undefined ? this.singleDiscussionByLineCode(line.lineCode) : []; - }, - }, }; </script> @@ -53,7 +40,7 @@ export default { class="code diff-wrap-lines js-syntax-highlight text-file js-diff-inline-view"> <tbody> <template - v-for="(line, index) in normalizedDiffLines" + v-for="(line, index) in diffLines" > <inline-diff-table-row :file-hash="diffFile.fileHash" @@ -61,7 +48,6 @@ export default { :line="line" :is-bottom="index + 1 === diffLinesLength" :key="line.lineCode" - :discussions="discussionsList(line)" /> <inline-diff-comment-row v-if="shouldRenderInlineCommentRow(line)" @@ -69,7 +55,6 @@ export default { :line="line" :line-index="index" :key="index" - :discussions="discussionsList(line)" /> </template> </tbody> diff --git a/app/assets/javascripts/diffs/components/parallel_diff_comment_row.vue b/app/assets/javascripts/diffs/components/parallel_diff_comment_row.vue index 48b8feeb0b4..26417c350cb 100644 --- a/app/assets/javascripts/diffs/components/parallel_diff_comment_row.vue +++ b/app/assets/javascripts/diffs/components/parallel_diff_comment_row.vue @@ -21,51 +21,49 @@ export default { type: Number, required: true, }, - leftDiscussions: { - type: Array, - required: false, - default: () => [], - }, - rightDiscussions: { - type: Array, - required: false, - default: () => [], - }, }, computed: { ...mapState({ diffLineCommentForms: state => state.diffs.diffLineCommentForms, }), leftLineCode() { - return this.line.left.lineCode; + return this.line.left && this.line.left.lineCode; }, rightLineCode() { - return this.line.right.lineCode; + return this.line.right && this.line.right.lineCode; }, hasExpandedDiscussionOnLeft() { - const discussions = this.leftDiscussions; - - return discussions ? discussions.every(discussion => discussion.expanded) : false; + return this.line.left && this.line.left.discussions + ? this.line.left.discussions.every(discussion => discussion.expanded) + : false; }, hasExpandedDiscussionOnRight() { - const discussions = this.rightDiscussions; - - return discussions ? discussions.every(discussion => discussion.expanded) : false; + return this.line.right && this.line.right.discussions + ? this.line.right.discussions.every(discussion => discussion.expanded) + : false; }, hasAnyExpandedDiscussion() { return this.hasExpandedDiscussionOnLeft || this.hasExpandedDiscussionOnRight; }, shouldRenderDiscussionsOnLeft() { - return this.leftDiscussions && this.hasExpandedDiscussionOnLeft; + return this.line.left && this.line.left.discussions && this.hasExpandedDiscussionOnLeft; }, shouldRenderDiscussionsOnRight() { - return this.rightDiscussions && this.hasExpandedDiscussionOnRight && this.line.right.type; + return ( + this.line.right && + this.line.right.discussions && + this.hasExpandedDiscussionOnRight && + this.line.right.type + ); }, showRightSideCommentForm() { - return this.line.right.type && this.diffLineCommentForms[this.rightLineCode]; + return ( + this.line.right && this.line.right.type && this.diffLineCommentForms[this.rightLineCode] + ); }, className() { - return this.leftDiscussions.length > 0 || this.rightDiscussions.length > 0 + return (this.left && this.line.left.discussions.length > 0) || + (this.right && this.line.right.discussions.length > 0) ? '' : 'js-temp-notes-holder'; }, @@ -85,8 +83,8 @@ export default { class="content" > <diff-discussions - v-if="leftDiscussions.length" - :discussions="leftDiscussions" + v-if="line.left.discussions.length" + :discussions="line.left.discussions" /> </div> <diff-line-note-form @@ -104,8 +102,8 @@ export default { class="content" > <diff-discussions - v-if="rightDiscussions.length" - :discussions="rightDiscussions" + v-if="line.right.discussions.length" + :discussions="line.right.discussions" /> </div> <diff-line-note-form diff --git a/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue b/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue index d4e54c2bd00..fb68d191091 100644 --- a/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue +++ b/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue @@ -1,6 +1,5 @@ <script> import $ from 'jquery'; -import { mapGetters } from 'vuex'; import DiffTableCell from './diff_table_cell.vue'; import { NEW_LINE_TYPE, @@ -10,8 +9,7 @@ import { OLD_NO_NEW_LINE_TYPE, PARALLEL_DIFF_VIEW_TYPE, NEW_NO_NEW_LINE_TYPE, - LINE_POSITION_LEFT, - LINE_POSITION_RIGHT, + EMPTY_CELL_TYPE, } from '../constants'; export default { @@ -36,16 +34,6 @@ export default { required: false, default: false, }, - leftDiscussions: { - type: Array, - required: false, - default: () => [], - }, - rightDiscussions: { - type: Array, - required: false, - default: () => [], - }, }, data() { return { @@ -54,29 +42,26 @@ export default { }; }, computed: { - ...mapGetters('diffs', ['isParallelView']), isContextLine() { - return this.line.left.type === CONTEXT_LINE_TYPE; + return this.line.left && this.line.left.type === CONTEXT_LINE_TYPE; }, classNameMap() { return { [CONTEXT_LINE_CLASS_NAME]: this.isContextLine, - [PARALLEL_DIFF_VIEW_TYPE]: this.isParallelView, + [PARALLEL_DIFF_VIEW_TYPE]: true, }; }, parallelViewLeftLineType() { - if (this.line.right.type === NEW_NO_NEW_LINE_TYPE) { + if (this.line.right && this.line.right.type === NEW_NO_NEW_LINE_TYPE) { return OLD_NO_NEW_LINE_TYPE; } - return this.line.left.type; + return this.line.left ? this.line.left.type : EMPTY_CELL_TYPE; }, }, created() { this.newLineType = NEW_LINE_TYPE; this.oldLineType = OLD_LINE_TYPE; - this.linePositionLeft = LINE_POSITION_LEFT; - this.linePositionRight = LINE_POSITION_RIGHT; this.parallelDiffViewType = PARALLEL_DIFF_VIEW_TYPE; }, methods: { @@ -116,47 +101,57 @@ export default { @mouseover="handleMouseMove" @mouseout="handleMouseMove" > - <diff-table-cell - :file-hash="fileHash" - :context-lines-path="contextLinesPath" - :line="line" - :line-type="oldLineType" - :line-position="linePositionLeft" - :is-bottom="isBottom" - :is-hover="isLeftHover" - :show-comment-button="true" - :diff-view-type="parallelDiffViewType" - :discussions="leftDiscussions" - class="diff-line-num old_line" - /> - <td - :id="line.left.lineCode" - :class="parallelViewLeftLineType" - class="line_content parallel left-side" - @mousedown.native="handleParallelLineMouseDown" - v-html="line.left.richText" - > - </td> - <diff-table-cell - :file-hash="fileHash" - :context-lines-path="contextLinesPath" - :line="line" - :line-type="newLineType" - :line-position="linePositionRight" - :is-bottom="isBottom" - :is-hover="isRightHover" - :show-comment-button="true" - :diff-view-type="parallelDiffViewType" - :discussions="rightDiscussions" - class="diff-line-num new_line" - /> - <td - :id="line.right.lineCode" - :class="line.right.type" - class="line_content parallel right-side" - @mousedown.native="handleParallelLineMouseDown" - v-html="line.right.richText" - > - </td> + <template v-if="line.left"> + <diff-table-cell + :file-hash="fileHash" + :context-lines-path="contextLinesPath" + :line="line.left" + :line-type="oldLineType" + :is-bottom="isBottom" + :is-hover="isLeftHover" + :show-comment-button="true" + :diff-view-type="parallelDiffViewType" + line-position="left" + class="diff-line-num old_line" + /> + <td + :id="line.left.lineCode" + :class="parallelViewLeftLineType" + class="line_content parallel left-side" + @mousedown.native="handleParallelLineMouseDown" + v-html="line.left.richText" + > + </td> + </template> + <template v-else> + <td class="diff-line-num old_line empty-cell"></td> + <td class="line_content parallel left-side empty-cell"></td> + </template> + <template v-if="line.right"> + <diff-table-cell + :file-hash="fileHash" + :context-lines-path="contextLinesPath" + :line="line.right" + :line-type="newLineType" + :is-bottom="isBottom" + :is-hover="isRightHover" + :show-comment-button="true" + :diff-view-type="parallelDiffViewType" + line-position="right" + class="diff-line-num new_line" + /> + <td + :id="line.right.lineCode" + :class="line.right.type" + class="line_content parallel right-side" + @mousedown.native="handleParallelLineMouseDown" + v-html="line.right.richText" + > + </td> + </template> + <template v-else> + <td class="diff-line-num old_line empty-cell"></td> + <td class="line_content parallel right-side empty-cell"></td> + </template> </tr> </template> diff --git a/app/assets/javascripts/diffs/components/parallel_diff_view.vue b/app/assets/javascripts/diffs/components/parallel_diff_view.vue index 24ceb52a04a..501bd4450d8 100644 --- a/app/assets/javascripts/diffs/components/parallel_diff_view.vue +++ b/app/assets/javascripts/diffs/components/parallel_diff_view.vue @@ -2,8 +2,6 @@ import { mapState, mapGetters } from 'vuex'; import parallelDiffTableRow from './parallel_diff_table_row.vue'; import parallelDiffCommentRow from './parallel_diff_comment_row.vue'; -import { EMPTY_CELL_TYPE } from '../constants'; -import { trimFirstCharOfLineContent } from '../store/utils'; export default { components: { @@ -21,46 +19,17 @@ export default { }, }, computed: { - ...mapGetters('diffs', [ - 'commitId', - 'singleDiscussionByLineCode', - 'shouldRenderParallelCommentRow', - ]), + ...mapGetters('diffs', ['commitId', 'shouldRenderParallelCommentRow']), ...mapState({ diffLineCommentForms: state => state.diffs.diffLineCommentForms, }), - parallelDiffLines() { - return this.diffLines.map(line => { - const parallelLine = Object.assign({}, line); - - if (line.left) { - parallelLine.left = trimFirstCharOfLineContent(line.left); - } else { - parallelLine.left = { type: EMPTY_CELL_TYPE }; - } - - if (line.right) { - parallelLine.right = trimFirstCharOfLineContent(line.right); - } else { - parallelLine.right = { type: EMPTY_CELL_TYPE }; - } - - return parallelLine; - }); - }, diffLinesLength() { - return this.parallelDiffLines.length; + return this.diffLines.length; }, userColorScheme() { return window.gon.user_color_scheme; }, }, - methods: { - discussionsByLine(line, leftOrRight) { - return line[leftOrRight] && line[leftOrRight].lineCode !== undefined ? - this.singleDiscussionByLineCode(line[leftOrRight].lineCode) : []; - }, - }, }; </script> @@ -73,7 +42,7 @@ export default { <table> <tbody> <template - v-for="(line, index) in parallelDiffLines" + v-for="(line, index) in diffLines" > <parallel-diff-table-row :file-hash="diffFile.fileHash" @@ -81,8 +50,6 @@ export default { :line="line" :is-bottom="index + 1 === diffLinesLength" :key="index" - :left-discussions="discussionsByLine(line, 'left')" - :right-discussions="discussionsByLine(line, 'right')" /> <parallel-diff-comment-row v-if="shouldRenderParallelCommentRow(line)" @@ -90,8 +57,6 @@ export default { :line="line" :diff-file-hash="diffFile.fileHash" :line-index="index" - :left-discussions="discussionsByLine(line, 'left')" - :right-discussions="discussionsByLine(line, 'right')" /> </template> </tbody> diff --git a/app/assets/javascripts/diffs/store/actions.js b/app/assets/javascripts/diffs/store/actions.js index 4ab6ceb249a..027df2ec841 100644 --- a/app/assets/javascripts/diffs/store/actions.js +++ b/app/assets/javascripts/diffs/store/actions.js @@ -3,6 +3,7 @@ import axios from '~/lib/utils/axios_utils'; import Cookies from 'js-cookie'; import { handleLocationHash, historyPushState } from '~/lib/utils/common_utils'; import { mergeUrlParams } from '~/lib/utils/url_utility'; +import { getDiffPositionByLineCode } from './utils'; import * as types from './mutation_types'; import { PARALLEL_DIFF_VIEW_TYPE, @@ -29,25 +30,53 @@ export const fetchDiffFiles = ({ state, commit }) => { .then(handleLocationHash); }; -export const startRenderDiffsQueue = ({ state, commit }) => { - const checkItem = () => { - const nextFile = state.diffFiles.find( - file => !file.renderIt && (!file.collapsed || !file.text), - ); - if (nextFile) { - requestAnimationFrame(() => { - commit(types.RENDER_FILE, nextFile); +// This is adding line discussions to the actual lines in the diff tree +// once for parallel and once for inline mode +export const assignDiscussionsToDiff = ({ state, commit }, allLineDiscussions) => { + const diffPositionByLineCode = getDiffPositionByLineCode(state.diffFiles); + + Object.values(allLineDiscussions).forEach(discussions => { + if (discussions.length > 0) { + const { fileHash } = discussions[0]; + commit(types.SET_LINE_DISCUSSIONS_FOR_FILE, { + fileHash, + discussions, + diffPositionByLineCode, }); - requestIdleCallback( - () => { - checkItem(); - }, - { timeout: 1000 }, - ); } - }; + }); +}; + +export const removeDiscussionsFromDiff = ({ commit }, removeDiscussion) => { + const { fileHash, line_code } = removeDiscussion; + commit(types.REMOVE_LINE_DISCUSSIONS_FOR_FILE, { fileHash, lineCode: line_code }); +}; + +export const startRenderDiffsQueue = ({ state, commit }) => { + const checkItem = () => + new Promise(resolve => { + const nextFile = state.diffFiles.find( + file => !file.renderIt && (!file.collapsed || !file.text), + ); + + if (nextFile) { + requestAnimationFrame(() => { + commit(types.RENDER_FILE, nextFile); + }); + requestIdleCallback( + () => { + checkItem() + .then(resolve) + .catch(() => {}); + }, + { timeout: 1000 }, + ); + } else { + resolve(); + } + }); - checkItem(); + return checkItem(); }; export const setInlineDiffViewType = ({ commit }) => { diff --git a/app/assets/javascripts/diffs/store/getters.js b/app/assets/javascripts/diffs/store/getters.js index 4a47646d7fa..968ba3c5e13 100644 --- a/app/assets/javascripts/diffs/store/getters.js +++ b/app/assets/javascripts/diffs/store/getters.js @@ -17,7 +17,10 @@ export const commitId = state => (state.commit && state.commit.id ? state.commit export const diffHasAllExpandedDiscussions = (state, getters) => diff => { const discussions = getters.getDiffFileDiscussions(diff); - return (discussions.length && discussions.every(discussion => discussion.expanded)) || false; + return ( + (discussions && discussions.length && discussions.every(discussion => discussion.expanded)) || + false + ); }; /** @@ -28,7 +31,10 @@ export const diffHasAllExpandedDiscussions = (state, getters) => diff => { export const diffHasAllCollpasedDiscussions = (state, getters) => diff => { const discussions = getters.getDiffFileDiscussions(diff); - return (discussions.length && discussions.every(discussion => !discussion.expanded)) || false; + return ( + (discussions && discussions.length && discussions.every(discussion => !discussion.expanded)) || + false + ); }; /** @@ -40,7 +46,9 @@ export const diffHasExpandedDiscussions = (state, getters) => diff => { const discussions = getters.getDiffFileDiscussions(diff); return ( - (discussions.length && discussions.find(discussion => discussion.expanded) !== undefined) || + (discussions && + discussions.length && + discussions.find(discussion => discussion.expanded) !== undefined) || false ); }; @@ -64,45 +72,38 @@ export const getDiffFileDiscussions = (state, getters, rootState, rootGetters) = discussion.diff_discussion && _.isEqual(discussion.diff_file.file_hash, diff.fileHash), ) || []; -export const singleDiscussionByLineCode = (state, getters, rootState, rootGetters) => lineCode => { - if (!lineCode || lineCode === undefined) return []; - const discussions = rootGetters.discussionsByLineCode; - return discussions[lineCode] || []; -}; - -export const shouldRenderParallelCommentRow = (state, getters) => line => { - const leftLineCode = line.left.lineCode; - const rightLineCode = line.right.lineCode; - const leftDiscussions = getters.singleDiscussionByLineCode(leftLineCode); - const rightDiscussions = getters.singleDiscussionByLineCode(rightLineCode); - const hasDiscussion = leftDiscussions.length || rightDiscussions.length; +export const shouldRenderParallelCommentRow = state => line => { + const hasDiscussion = + (line.left && line.left.discussions && line.left.discussions.length) || + (line.right && line.right.discussions && line.right.discussions.length); - const hasExpandedDiscussionOnLeft = leftDiscussions.length - ? leftDiscussions.every(discussion => discussion.expanded) - : false; - const hasExpandedDiscussionOnRight = rightDiscussions.length - ? rightDiscussions.every(discussion => discussion.expanded) - : false; + const hasExpandedDiscussionOnLeft = + line.left && line.left.discussions && line.left.discussions.length + ? line.left.discussions.every(discussion => discussion.expanded) + : false; + const hasExpandedDiscussionOnRight = + line.right && line.right.discussions && line.right.discussions.length + ? line.right.discussions.every(discussion => discussion.expanded) + : false; if (hasDiscussion && (hasExpandedDiscussionOnLeft || hasExpandedDiscussionOnRight)) { return true; } - const hasCommentFormOnLeft = state.diffLineCommentForms[leftLineCode]; - const hasCommentFormOnRight = state.diffLineCommentForms[rightLineCode]; + const hasCommentFormOnLeft = line.left && state.diffLineCommentForms[line.left.lineCode]; + const hasCommentFormOnRight = line.right && state.diffLineCommentForms[line.right.lineCode]; return hasCommentFormOnLeft || hasCommentFormOnRight; }; -export const shouldRenderInlineCommentRow = (state, getters) => line => { +export const shouldRenderInlineCommentRow = state => line => { if (state.diffLineCommentForms[line.lineCode]) return true; - const lineDiscussions = getters.singleDiscussionByLineCode(line.lineCode); - if (lineDiscussions.length === 0) { + if (!line.discussions || line.discussions.length === 0) { return false; } - return lineDiscussions.every(discussion => discussion.expanded); + return line.discussions.every(discussion => discussion.expanded); }; // prevent babel-plugin-rewire from generating an invalid default during karma∂ tests diff --git a/app/assets/javascripts/diffs/store/mutation_types.js b/app/assets/javascripts/diffs/store/mutation_types.js index c999d637d50..f61efbe6e1e 100644 --- a/app/assets/javascripts/diffs/store/mutation_types.js +++ b/app/assets/javascripts/diffs/store/mutation_types.js @@ -9,3 +9,5 @@ export const ADD_CONTEXT_LINES = 'ADD_CONTEXT_LINES'; export const ADD_COLLAPSED_DIFFS = 'ADD_COLLAPSED_DIFFS'; export const EXPAND_ALL_FILES = 'EXPAND_ALL_FILES'; export const RENDER_FILE = 'RENDER_FILE'; +export const SET_LINE_DISCUSSIONS_FOR_FILE = 'SET_LINE_DISCUSSIONS_FOR_FILE'; +export const REMOVE_LINE_DISCUSSIONS_FOR_FILE = 'REMOVE_LINE_DISCUSSIONS_FOR_FILE'; diff --git a/app/assets/javascripts/diffs/store/mutations.js b/app/assets/javascripts/diffs/store/mutations.js index bc69ae30777..6dc5bf16c65 100644 --- a/app/assets/javascripts/diffs/store/mutations.js +++ b/app/assets/javascripts/diffs/store/mutations.js @@ -1,8 +1,13 @@ import Vue from 'vue'; -import _ from 'underscore'; import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; -import { findDiffFile, addLineReferences, removeMatchLine, addContextLines } from './utils'; -import { LINES_TO_BE_RENDERED_DIRECTLY, MAX_LINES_TO_BE_RENDERED } from '../constants'; +import { + findDiffFile, + addLineReferences, + removeMatchLine, + addContextLines, + prepareDiffData, + isDiscussionApplicableToLine, +} from './utils'; import * as types from './mutation_types'; export default { @@ -17,38 +22,7 @@ export default { [types.SET_DIFF_DATA](state, data) { const diffData = convertObjectPropsToCamelCase(data, { deep: true }); - let showingLines = 0; - const filesLength = diffData.diffFiles.length; - let i; - for (i = 0; i < filesLength; i += 1) { - const file = diffData.diffFiles[i]; - if (file.parallelDiffLines) { - const linesLength = file.parallelDiffLines.length; - let u = 0; - for (u = 0; u < linesLength; u += 1) { - const line = file.parallelDiffLines[u]; - if (line.left) delete line.left.text; - if (line.right) delete line.right.text; - } - } - - if (file.highlightedDiffLines) { - const linesLength = file.highlightedDiffLines.length; - let u; - for (u = 0; u < linesLength; u += 1) { - const line = file.highlightedDiffLines[u]; - delete line.text; - } - } - - if (file.highlightedDiffLines) { - showingLines += file.parallelDiffLines.length; - } - Object.assign(file, { - renderIt: showingLines < LINES_TO_BE_RENDERED_DIRECTLY, - collapsed: file.text && showingLines > MAX_LINES_TO_BE_RENDERED, - }); - } + prepareDiffData(diffData); Object.assign(state, { ...diffData, @@ -98,12 +72,10 @@ export default { [types.ADD_COLLAPSED_DIFFS](state, { file, data }) { const normalizedData = convertObjectPropsToCamelCase(data, { deep: true }); + prepareDiffData(normalizedData); const [newFileData] = normalizedData.diffFiles.filter(f => f.fileHash === file.fileHash); - - if (newFileData) { - const index = _.findIndex(state.diffFiles, f => f.fileHash === file.fileHash); - state.diffFiles.splice(index, 1, newFileData); - } + const selectedFile = state.diffFiles.find(f => f.fileHash === file.fileHash); + Object.assign(selectedFile, { ...newFileData }); }, [types.EXPAND_ALL_FILES](state) { @@ -112,4 +84,81 @@ export default { collapsed: false, })); }, + + [types.SET_LINE_DISCUSSIONS_FOR_FILE](state, { fileHash, discussions, diffPositionByLineCode }) { + const selectedFile = state.diffFiles.find(f => f.fileHash === fileHash); + const firstDiscussion = discussions[0]; + const isDiffDiscussion = firstDiscussion.diff_discussion; + const hasLineCode = firstDiscussion.line_code; + const isResolvable = firstDiscussion.resolvable; + const diffPosition = diffPositionByLineCode[firstDiscussion.line_code]; + + if ( + selectedFile && + isDiffDiscussion && + hasLineCode && + isResolvable && + diffPosition && + isDiscussionApplicableToLine(firstDiscussion, diffPosition) + ) { + const targetLine = selectedFile.parallelDiffLines.find( + line => + (line.left && line.left.lineCode === firstDiscussion.line_code) || + (line.right && line.right.lineCode === firstDiscussion.line_code), + ); + if (targetLine) { + if (targetLine.left && targetLine.left.lineCode === firstDiscussion.line_code) { + Object.assign(targetLine.left, { + discussions, + }); + } else { + Object.assign(targetLine.right, { + discussions, + }); + } + } + + if (selectedFile.highlightedDiffLines) { + const targetInlineLine = selectedFile.highlightedDiffLines.find( + line => line.lineCode === firstDiscussion.line_code, + ); + + if (targetInlineLine) { + Object.assign(targetInlineLine, { + discussions, + }); + } + } + } + }, + + [types.REMOVE_LINE_DISCUSSIONS_FOR_FILE](state, { fileHash, lineCode }) { + const selectedFile = state.diffFiles.find(f => f.fileHash === fileHash); + if (selectedFile) { + const targetLine = selectedFile.parallelDiffLines.find( + line => + (line.left && line.left.lineCode === lineCode) || + (line.right && line.right.lineCode === lineCode), + ); + if (targetLine) { + const side = targetLine.left && targetLine.left.lineCode === lineCode ? 'left' : 'right'; + + Object.assign(targetLine[side], { + discussions: [], + }); + } + + if (selectedFile.highlightedDiffLines) { + const targetInlineLine = selectedFile.highlightedDiffLines.find( + line => line.lineCode === lineCode, + ); + + if (targetInlineLine) { + Object.assign(targetInlineLine, { + discussions: [], + }); + } + } + } + }, }; diff --git a/app/assets/javascripts/diffs/store/utils.js b/app/assets/javascripts/diffs/store/utils.js index 82082ac508a..b7e52a8f37f 100644 --- a/app/assets/javascripts/diffs/store/utils.js +++ b/app/assets/javascripts/diffs/store/utils.js @@ -8,6 +8,8 @@ import { NEW_LINE_TYPE, OLD_LINE_TYPE, MATCH_LINE_TYPE, + LINES_TO_BE_RENDERED_DIRECTLY, + MAX_LINES_TO_BE_RENDERED, } from '../constants'; export function findDiffFile(files, hash) { @@ -161,6 +163,11 @@ export function addContextLines(options) { * @returns {Object} */ export function trimFirstCharOfLineContent(line = {}) { + // eslint-disable-next-line no-param-reassign + delete line.text; + // eslint-disable-next-line no-param-reassign + line.discussions = []; + const parsedLine = Object.assign({}, line); if (line.richText) { @@ -174,7 +181,44 @@ export function trimFirstCharOfLineContent(line = {}) { return parsedLine; } -export function getDiffRefsByLineCode(diffFiles) { +// This prepares and optimizes the incoming diff data from the server +// by setting up incremental rendering and removing unneeded data +export function prepareDiffData(diffData) { + const filesLength = diffData.diffFiles.length; + let showingLines = 0; + for (let i = 0; i < filesLength; i += 1) { + const file = diffData.diffFiles[i]; + + if (file.parallelDiffLines) { + const linesLength = file.parallelDiffLines.length; + for (let u = 0; u < linesLength; u += 1) { + const line = file.parallelDiffLines[u]; + if (line.left) { + line.left = trimFirstCharOfLineContent(line.left); + } + if (line.right) { + line.right = trimFirstCharOfLineContent(line.right); + } + } + } + + if (file.highlightedDiffLines) { + const linesLength = file.highlightedDiffLines.length; + for (let u = 0; u < linesLength; u += 1) { + const line = file.highlightedDiffLines[u]; + Object.assign(line, { ...trimFirstCharOfLineContent(line) }); + } + showingLines += file.parallelDiffLines.length; + } + + Object.assign(file, { + renderIt: showingLines < LINES_TO_BE_RENDERED_DIRECTLY, + collapsed: file.text && showingLines > MAX_LINES_TO_BE_RENDERED, + }); + } +} + +export function getDiffPositionByLineCode(diffFiles) { return diffFiles.reduce((acc, diffFile) => { const { baseSha, headSha, startSha } = diffFile.diffRefs; const { newPath, oldPath } = diffFile; @@ -194,3 +238,12 @@ export function getDiffRefsByLineCode(diffFiles) { return acc; }, {}); } + +// This method will check whether the discussion is still applicable +// to the diff line in question regarding different versions of the MR +export function isDiscussionApplicableToLine(discussion, diffPosition) { + const originalRefs = convertObjectPropsToCamelCase(discussion.original_position.formatter); + const refs = convertObjectPropsToCamelCase(discussion.position.formatter); + + return _.isEqual(refs, diffPosition) || _.isEqual(originalRefs, diffPosition); +} diff --git a/app/assets/javascripts/lib/utils/text_utility.js b/app/assets/javascripts/lib/utils/text_utility.js index 2be3c97bd95..879f94a26ec 100644 --- a/app/assets/javascripts/lib/utils/text_utility.js +++ b/app/assets/javascripts/lib/utils/text_utility.js @@ -49,6 +49,16 @@ export const dasherize = str => str.replace(/[_\s]+/g, '-'); export const slugify = str => str.trim().toLowerCase(); /** + * Replaces whitespaces with hyphens and converts to lower case + * @param {String} str + * @returns {String} + */ +export const slugifyWithHyphens = str => { + const regex = new RegExp(/\s+/, 'g'); + return str.toLowerCase().replace(regex, '-'); +}; + +/** * Truncates given text * * @param {String} string diff --git a/app/assets/javascripts/notes.js b/app/assets/javascripts/notes.js index 1e168742667..8b1d8f6055e 100644 --- a/app/assets/javascripts/notes.js +++ b/app/assets/javascripts/notes.js @@ -154,7 +154,11 @@ export default class Notes { this.$wrapperEl.on('click', '.system-note-commit-list-toggler', this.toggleCommitList); this.$wrapperEl.on('click', '.js-toggle-lazy-diff', this.loadLazyDiff); - this.$wrapperEl.on('click', '.js-toggle-lazy-diff-retry-button', this.onClickRetryLazyLoad.bind(this)); + this.$wrapperEl.on( + 'click', + '.js-toggle-lazy-diff-retry-button', + this.onClickRetryLazyLoad.bind(this), + ); // fetch notes when tab becomes visible this.$wrapperEl.on('visibilitychange', this.visibilityChange); @@ -252,9 +256,7 @@ export default class Notes { discussionNoteForm = $textarea.closest('.js-discussion-note-form'); if (discussionNoteForm.length) { if ($textarea.val() !== '') { - if ( - !window.confirm('Are you sure you want to cancel creating this comment?') - ) { + if (!window.confirm('Are you sure you want to cancel creating this comment?')) { return; } } @@ -266,9 +268,7 @@ export default class Notes { originalText = $textarea.closest('form').data('originalNote'); newText = $textarea.val(); if (originalText !== newText) { - if ( - !window.confirm('Are you sure you want to cancel editing this comment?') - ) { + if (!window.confirm('Are you sure you want to cancel editing this comment?')) { return; } } @@ -1316,8 +1316,7 @@ export default class Notes { $retryButton.prop('disabled', true); - return this.loadLazyDiff(e) - .then(() => { + return this.loadLazyDiff(e).then(() => { $retryButton.prop('disabled', false); }); } @@ -1343,18 +1342,18 @@ export default class Notes { */ if (url) { return axios - .get(url) - .then(({ data }) => { - // Reset state in case last request returned error - $successContainer.removeClass('hidden'); - $errorContainer.addClass('hidden'); - - Notes.renderDiffContent($container, data); - }) - .catch(() => { - $successContainer.addClass('hidden'); - $errorContainer.removeClass('hidden'); - }); + .get(url) + .then(({ data }) => { + // Reset state in case last request returned error + $successContainer.removeClass('hidden'); + $errorContainer.addClass('hidden'); + + Notes.renderDiffContent($container, data); + }) + .catch(() => { + $successContainer.addClass('hidden'); + $errorContainer.removeClass('hidden'); + }); } return Promise.resolve(); } @@ -1545,12 +1544,8 @@ export default class Notes { <div class="note-header"> <div class="note-header-info"> <a href="/${_.escape(currentUsername)}"> - <span class="d-none d-sm-inline-block">${_.escape( - currentUsername, - )}</span> - <span class="note-headline-light">${_.escape( - currentUsername, - )}</span> + <span class="d-none d-sm-inline-block">${_.escape(currentUsername)}</span> + <span class="note-headline-light">${_.escape(currentUsername)}</span> </a> </div> </div> @@ -1565,9 +1560,7 @@ export default class Notes { ); $tempNote.find('.d-none.d-sm-inline-block').text(_.escape(currentUserFullname)); - $tempNote - .find('.note-headline-light') - .text(`@${_.escape(currentUsername)}`); + $tempNote.find('.note-headline-light').text(`@${_.escape(currentUsername)}`); return $tempNote; } diff --git a/app/assets/javascripts/notes/components/noteable_discussion.vue b/app/assets/javascripts/notes/components/noteable_discussion.vue index 0fe1c16854a..afe86911230 100644 --- a/app/assets/javascripts/notes/components/noteable_discussion.vue +++ b/app/assets/javascripts/notes/components/noteable_discussion.vue @@ -137,8 +137,10 @@ export default { return this.unresolvedDiscussions.length > 1; }, showJumpToNextDiscussion() { - return this.hasMultipleUnresolvedDiscussions && - !this.isLastUnresolvedDiscussion(this.discussion.id, this.discussionsByDiffOrder); + return ( + this.hasMultipleUnresolvedDiscussions && + !this.isLastUnresolvedDiscussion(this.discussion.id, this.discussionsByDiffOrder) + ); }, shouldRenderDiffs() { const { diffDiscussion, diffFile } = this.transformedDiscussion; @@ -256,11 +258,16 @@ Please check your network connection and try again.`; }); }, jumpToNextDiscussion() { - const nextId = - this.nextUnresolvedDiscussionId(this.discussion.id, this.discussionsByDiffOrder); + const nextId = this.nextUnresolvedDiscussionId( + this.discussion.id, + this.discussionsByDiffOrder, + ); this.jumpToDiscussion(nextId); }, + deleteNoteHandler(note) { + this.$emit('noteDeleted', this.discussion, note); + }, }, }; </script> @@ -270,6 +277,7 @@ Please check your network connection and try again.`; <div class="timeline-entry-inner"> <div class="timeline-icon"> <user-avatar-link + v-if="author" :link-href="author.path" :img-src="author.avatar_url" :img-alt="author.name" @@ -344,6 +352,7 @@ Please check your network connection and try again.`; :is="componentName(note)" :note="componentData(note)" :key="note.id" + @handleDeleteNote="deleteNoteHandler" /> </ul> <div diff --git a/app/assets/javascripts/notes/components/noteable_note.vue b/app/assets/javascripts/notes/components/noteable_note.vue index 4ebeb5599f2..7579fc852c6 100644 --- a/app/assets/javascripts/notes/components/noteable_note.vue +++ b/app/assets/javascripts/notes/components/noteable_note.vue @@ -86,6 +86,7 @@ export default { // eslint-disable-next-line no-alert if (window.confirm('Are you sure you want to delete this comment?')) { this.isDeleting = true; + this.$emit('handleDeleteNote', this.note); this.deleteNote(this.note) .then(() => { diff --git a/app/assets/javascripts/notes/components/notes_app.vue b/app/assets/javascripts/notes/components/notes_app.vue index 9b8713b40fb..7f9d23b211b 100644 --- a/app/assets/javascripts/notes/components/notes_app.vue +++ b/app/assets/javascripts/notes/components/notes_app.vue @@ -138,6 +138,7 @@ export default { .then(() => { this.isLoading = false; this.setNotesFetchedState(true); + eventHub.$emit('fetchedNotesData'); }) .then(() => this.$nextTick()) .then(() => this.checkLocationHash()) diff --git a/app/assets/javascripts/notes/stores/actions.js b/app/assets/javascripts/notes/stores/actions.js index 3eefbe11c37..9a2ec15debd 100644 --- a/app/assets/javascripts/notes/stores/actions.js +++ b/app/assets/javascripts/notes/stores/actions.js @@ -43,14 +43,23 @@ export const fetchDiscussions = ({ commit }, path) => commit(types.SET_INITIAL_DISCUSSIONS, discussions); }); -export const refetchDiscussionById = ({ commit }, { path, discussionId }) => - service - .fetchDiscussions(path) - .then(res => res.json()) - .then(discussions => { - const selectedDiscussion = discussions.find(discussion => discussion.id === discussionId); - if (selectedDiscussion) commit(types.UPDATE_DISCUSSION, selectedDiscussion); - }); +export const refetchDiscussionById = ({ commit, state }, { path, discussionId }) => + new Promise(resolve => { + service + .fetchDiscussions(path) + .then(res => res.json()) + .then(discussions => { + const selectedDiscussion = discussions.find(discussion => discussion.id === discussionId); + if (selectedDiscussion) { + commit(types.UPDATE_DISCUSSION, selectedDiscussion); + // We need to refetch as it is now the transformed one in state + const discussion = utils.findNoteObjectById(state.discussions, discussionId); + + resolve(discussion); + } + }) + .catch(() => {}); + }); export const deleteNote = ({ commit }, note) => service.deleteNote(note.path).then(() => { @@ -152,26 +161,28 @@ export const saveNote = ({ commit, dispatch }, noteData) => { const replyId = noteData.data.in_reply_to_discussion_id; const methodToDispatch = replyId ? 'replyToDiscussion' : 'createNewNote'; - commit(types.REMOVE_PLACEHOLDER_NOTES); // remove previous placeholders $('.notes-form .flash-container').hide(); // hide previous flash notification + commit(types.REMOVE_PLACEHOLDER_NOTES); // remove previous placeholders - if (hasQuickActions) { - placeholderText = utils.stripQuickActions(placeholderText); - } + if (replyId) { + if (hasQuickActions) { + placeholderText = utils.stripQuickActions(placeholderText); + } - if (placeholderText.length) { - commit(types.SHOW_PLACEHOLDER_NOTE, { - noteBody: placeholderText, - replyId, - }); - } + if (placeholderText.length) { + commit(types.SHOW_PLACEHOLDER_NOTE, { + noteBody: placeholderText, + replyId, + }); + } - if (hasQuickActions) { - commit(types.SHOW_PLACEHOLDER_NOTE, { - isSystemNote: true, - noteBody: utils.getQuickActionText(note), - replyId, - }); + if (hasQuickActions) { + commit(types.SHOW_PLACEHOLDER_NOTE, { + isSystemNote: true, + noteBody: utils.getQuickActionText(note), + replyId, + }); + } } return dispatch(methodToDispatch, noteData).then(res => { @@ -211,7 +222,9 @@ export const saveNote = ({ commit, dispatch }, noteData) => { if (errors && errors.commands_only) { Flash(errors.commands_only, 'notice', noteData.flashContainer); } - commit(types.REMOVE_PLACEHOLDER_NOTES); + if (replyId) { + commit(types.REMOVE_PLACEHOLDER_NOTES); + } return res; }); diff --git a/app/assets/javascripts/notes/stores/getters.js b/app/assets/javascripts/notes/stores/getters.js index 5b3b9f8776f..d4babf1fab2 100644 --- a/app/assets/javascripts/notes/stores/getters.js +++ b/app/assets/javascripts/notes/stores/getters.js @@ -1,5 +1,6 @@ import _ from 'underscore'; import * as constants from '../constants'; +import { reduceDiscussionsToLineCodes } from './utils'; import { collapseSystemNotes } from './collapse_utils'; export const discussions = state => collapseSystemNotes(state.discussions); @@ -28,17 +29,8 @@ export const notesById = state => return acc; }, {}); -export const discussionsByLineCode = state => - state.discussions.reduce((acc, note) => { - if (note.diff_discussion && note.line_code && note.resolvable) { - // For context about line notes: there might be multiple notes with the same line code - const items = acc[note.line_code] || []; - items.push(note); - - Object.assign(acc, { [note.line_code]: items }); - } - return acc; - }, {}); +export const discussionsStructuredByLineCode = state => + reduceDiscussionsToLineCodes(state.discussions); export const noteableType = state => { const { ISSUE_NOTEABLE_TYPE, MERGE_REQUEST_NOTEABLE_TYPE, EPIC_NOTEABLE_TYPE } = constants; diff --git a/app/assets/javascripts/notes/stores/mutations.js b/app/assets/javascripts/notes/stores/mutations.js index ab6a95e2601..2c04bfea122 100644 --- a/app/assets/javascripts/notes/stores/mutations.js +++ b/app/assets/javascripts/notes/stores/mutations.js @@ -54,13 +54,12 @@ export default { [types.EXPAND_DISCUSSION](state, { discussionId }) { const discussion = utils.findNoteObjectById(state.discussions, discussionId); - - discussion.expanded = true; + Object.assign(discussion, { expanded: true }); }, [types.COLLAPSE_DISCUSSION](state, { discussionId }) { const discussion = utils.findNoteObjectById(state.discussions, discussionId); - discussion.expanded = false; + Object.assign(discussion, { expanded: false }); }, [types.REMOVE_PLACEHOLDER_NOTES](state) { @@ -95,10 +94,15 @@ export default { [types.SET_USER_DATA](state, data) { Object.assign(state, { userData: data }); }, + [types.SET_INITIAL_DISCUSSIONS](state, discussionsData) { const discussions = []; discussionsData.forEach(discussion => { + if (discussion.diff_file) { + Object.assign(discussion, { fileHash: discussion.diff_file.file_hash }); + } + // To support legacy notes, should be very rare case. if (discussion.individual_note && discussion.notes.length > 1) { discussion.notes.forEach(n => { @@ -168,8 +172,7 @@ export default { [types.TOGGLE_DISCUSSION](state, { discussionId }) { const discussion = utils.findNoteObjectById(state.discussions, discussionId); - - discussion.expanded = !discussion.expanded; + Object.assign(discussion, { expanded: !discussion.expanded }); }, [types.UPDATE_NOTE](state, note) { @@ -185,16 +188,12 @@ export default { [types.UPDATE_DISCUSSION](state, noteData) { const note = noteData; - let index = 0; - - state.discussions.forEach((n, i) => { - if (n.id === note.id) { - index = i; - } - }); - + const selectedDiscussion = state.discussions.find(disc => disc.id === note.id); note.expanded = true; // override expand flag to prevent collapse - state.discussions.splice(index, 1, note); + if (note.diff_file) { + Object.assign(note, { fileHash: note.diff_file.file_hash }); + } + Object.assign(selectedDiscussion, { ...note }); }, [types.CLOSE_ISSUE](state) { diff --git a/app/assets/javascripts/notes/stores/utils.js b/app/assets/javascripts/notes/stores/utils.js index a0e096ebfaf..8ccbdb4c130 100644 --- a/app/assets/javascripts/notes/stores/utils.js +++ b/app/assets/javascripts/notes/stores/utils.js @@ -2,13 +2,11 @@ import AjaxCache from '~/lib/utils/ajax_cache'; const REGEX_QUICK_ACTIONS = /^\/\w+.*$/gm; -export const findNoteObjectById = (notes, id) => - notes.filter(n => n.id === id)[0]; +export const findNoteObjectById = (notes, id) => notes.filter(n => n.id === id)[0]; export const getQuickActionText = note => { let text = 'Applying command'; - const quickActions = - AjaxCache.get(gl.GfmAutoComplete.dataSources.commands) || []; + const quickActions = AjaxCache.get(gl.GfmAutoComplete.dataSources.commands) || []; const executedCommands = quickActions.filter(command => { const commandRegex = new RegExp(`/${command.name}`); @@ -27,7 +25,18 @@ export const getQuickActionText = note => { return text; }; +export const reduceDiscussionsToLineCodes = selectedDiscussions => + selectedDiscussions.reduce((acc, note) => { + if (note.diff_discussion && note.line_code && note.resolvable) { + // For context about line notes: there might be multiple notes with the same line code + const items = acc[note.line_code] || []; + items.push(note); + + Object.assign(acc, { [note.line_code]: items }); + } + return acc; + }, {}); + export const hasQuickActions = note => REGEX_QUICK_ACTIONS.test(note); -export const stripQuickActions = note => - note.replace(REGEX_QUICK_ACTIONS, '').trim(); +export const stripQuickActions = note => note.replace(REGEX_QUICK_ACTIONS, '').trim(); diff --git a/app/assets/javascripts/pages/projects/wikis/components/delete_wiki_modal.vue b/app/assets/javascripts/pages/projects/wikis/components/delete_wiki_modal.vue index 0289209ff1e..42c37bc8cd8 100644 --- a/app/assets/javascripts/pages/projects/wikis/components/delete_wiki_modal.vue +++ b/app/assets/javascripts/pages/projects/wikis/components/delete_wiki_modal.vue @@ -25,6 +25,9 @@ export default { }, }, computed: { + modalId() { + return 'delete-wiki-modal'; + }, message() { return s__('WikiPageConfirmDelete|Are you sure you want to delete this page?'); }, @@ -47,31 +50,41 @@ export default { </script> <template> - <gl-modal - id="delete-wiki-modal" - :header-title-text="title" - :footer-primary-button-text="s__('WikiPageConfirmDelete|Delete page')" - footer-primary-button-variant="danger" - @submit="onSubmit" - > - {{ message }} - <form - ref="form" - :action="deleteWikiUrl" - method="post" - class="js-requires-input" + <div class="d-inline-block"> + <button + v-gl-modal="modalId" + type="button" + class="btn btn-danger" + > + {{ __('Delete') }} + </button> + <gl-ui-modal + :title="title" + :ok-title="s__('WikiPageConfirmDelete|Delete page')" + :modal-id="modalId" + title-tag="h4" + ok-variant="danger" + @ok="onSubmit" > - <input - ref="method" - type="hidden" - name="_method" - value="delete" - /> - <input - :value="csrfToken" - type="hidden" - name="authenticity_token" - /> - </form> - </gl-modal> + {{ message }} + <form + ref="form" + :action="deleteWikiUrl" + method="post" + class="js-requires-input" + > + <input + ref="method" + type="hidden" + name="_method" + value="delete" + /> + <input + :value="csrfToken" + type="hidden" + name="authenticity_token" + /> + </form> + </gl-ui-modal> + </div> </template> diff --git a/app/assets/javascripts/pages/projects/wikis/index.js b/app/assets/javascripts/pages/projects/wikis/index.js index 0a0fe3fc137..b0a323a71cd 100644 --- a/app/assets/javascripts/pages/projects/wikis/index.js +++ b/app/assets/javascripts/pages/projects/wikis/index.js @@ -14,15 +14,15 @@ document.addEventListener('DOMContentLoaded', () => { new ZenMode(); // eslint-disable-line no-new new GLForm($('.wiki-form')); // eslint-disable-line no-new - const deleteWikiButton = document.getElementById('delete-wiki-button'); + const deleteWikiModalWrapperEl = document.getElementById('delete-wiki-modal-wrapper'); - if (deleteWikiButton) { + if (deleteWikiModalWrapperEl) { Vue.use(Translate); - const { deleteWikiUrl, pageTitle } = deleteWikiButton.dataset; - const deleteWikiModalEl = document.getElementById('delete-wiki-modal'); - const deleteModal = new Vue({ // eslint-disable-line - el: deleteWikiModalEl, + const { deleteWikiUrl, pageTitle } = deleteWikiModalWrapperEl.dataset; + + new Vue({ // eslint-disable-line no-new + el: deleteWikiModalWrapperEl, data: { deleteWikiUrl: '', }, diff --git a/app/assets/javascripts/projects/project_import_gitlab_project.js b/app/assets/javascripts/projects/project_import_gitlab_project.js index 4e20fce1460..fbef3a0b059 100644 --- a/app/assets/javascripts/projects/project_import_gitlab_project.js +++ b/app/assets/javascripts/projects/project_import_gitlab_project.js @@ -1,9 +1,19 @@ import $ from 'jquery'; import { getParameterValues } from '../lib/utils/url_utility'; +import projectNew from './project_new'; export default () => { - const path = getParameterValues('path')[0]; + const pathParam = getParameterValues('path')[0]; + const nameParam = getParameterValues('name')[0]; + const $projectPath = $('.js-path-name'); + const $projectName = $('.js-project-name'); - // get the path url and append it in the inputS - $('.js-path-name').val(path); + // get the path url and append it in the input + $projectPath.val(pathParam); + + // get the project name from the URL and set it as input value + $projectName.val(nameParam); + + // generate slug when project name changes + $projectName.keyup(() => projectNew.onProjectNameChange($projectName, $projectPath)); }; diff --git a/app/assets/javascripts/projects/project_new.js b/app/assets/javascripts/projects/project_new.js index 04badad0f34..8a079b4b38a 100644 --- a/app/assets/javascripts/projects/project_new.js +++ b/app/assets/javascripts/projects/project_new.js @@ -1,5 +1,6 @@ import $ from 'jquery'; import { addSelectOnFocusBehaviour } from '../lib/utils/common_utils'; +import { slugifyWithHyphens } from '../lib/utils/text_utility'; let hasUserDefinedProjectPath = false; @@ -29,18 +30,23 @@ const deriveProjectPathFromUrl = ($projectImportUrl) => { } }; +const onProjectNameChange = ($projectNameInput, $projectPathInput) => { + const slug = slugifyWithHyphens($projectNameInput.val()); + $projectPathInput.val(slug); +}; + const bindEvents = () => { const $newProjectForm = $('#new_project'); const $projectImportUrl = $('#project_import_url'); - const $projectPath = $('#project_path'); + const $projectPath = $('.tab-pane.active #project_path'); const $useTemplateBtn = $('.template-button > input'); const $projectFieldsForm = $('.project-fields-form'); const $selectedTemplateText = $('.selected-template'); const $changeTemplateBtn = $('.change-template'); const $selectedIcon = $('.selected-icon'); - const $templateProjectNameInput = $('#template-project-name #project_path'); const $pushNewProjectTipTrigger = $('.push-new-project-tip'); const $projectTemplateButtons = $('.project-templates-buttons'); + const $projectName = $('.tab-pane.active #project_name'); if ($newProjectForm.length !== 1) { return; @@ -57,7 +63,8 @@ const bindEvents = () => { $('.btn_import_gitlab_project').on('click', () => { const importHref = $('a.btn_import_gitlab_project').attr('href'); - $('.btn_import_gitlab_project').attr('href', `${importHref}?namespace_id=${$('#project_namespace_id').val()}&path=${$projectPath.val()}`); + $('.btn_import_gitlab_project') + .attr('href', `${importHref}?namespace_id=${$('#project_namespace_id').val()}&name=${$projectName.val()}&path=${$projectPath.val()}`); }); if ($pushNewProjectTipTrigger) { @@ -111,7 +118,15 @@ const bindEvents = () => { const selectedTemplate = templates[value]; $selectedTemplateText.text(selectedTemplate.text); $(selectedTemplate.icon).clone().addClass('d-block').appendTo($selectedIcon); - $templateProjectNameInput.focus(); + + const $activeTabProjectName = $('.tab-pane.active #project_name'); + const $activeTabProjectPath = $('.tab-pane.active #project_path'); + $activeTabProjectName.focus(); + $activeTabProjectName + .keyup(() => { + onProjectNameChange($activeTabProjectName, $activeTabProjectPath); + hasUserDefinedProjectPath = $activeTabProjectPath.val().trim().length > 0; + }); } $useTemplateBtn.on('change', chooseTemplate); @@ -131,9 +146,15 @@ const bindEvents = () => { }); $projectImportUrl.keyup(() => deriveProjectPathFromUrl($projectImportUrl)); + + $projectName.keyup(() => { + onProjectNameChange($projectName, $projectPath); + hasUserDefinedProjectPath = $projectPath.val().trim().length > 0; + }); }; export default { bindEvents, deriveProjectPathFromUrl, + onProjectNameChange, }; diff --git a/app/assets/javascripts/registry/components/collapsible_container.vue b/app/assets/javascripts/registry/components/collapsible_container.vue index 4116c4a0489..cea409aa130 100644 --- a/app/assets/javascripts/registry/components/collapsible_container.vue +++ b/app/assets/javascripts/registry/components/collapsible_container.vue @@ -6,6 +6,7 @@ import tooltip from '../../vue_shared/directives/tooltip'; import tableRegistry from './table_registry.vue'; import { errorMessages, errorMessagesTypes } from '../constants'; + import { __ } from '../../locale'; export default { name: 'CollapsibeContainerRegisty', @@ -46,7 +47,10 @@ handleDeleteRepository() { this.deleteRepo(this.repo) - .then(() => this.fetchRepos()) + .then(() => { + Flash(__('This container registry has been scheduled for deletion.'), 'notice'); + this.fetchRepos(); + }) .catch(() => this.showError(errorMessagesTypes.DELETE_REPO)); }, diff --git a/app/assets/stylesheets/pages/diff.scss b/app/assets/stylesheets/pages/diff.scss index d673b59e1c0..207c68432a7 100644 --- a/app/assets/stylesheets/pages/diff.scss +++ b/app/assets/stylesheets/pages/diff.scss @@ -72,6 +72,7 @@ .line_holder td { line-height: $code-line-height; font-size: $code-font-size; + vertical-align: top; &.noteable_line { position: relative; diff --git a/app/controllers/groups/labels_controller.rb b/app/controllers/groups/labels_controller.rb index 3e0076ac935..e95123c0933 100644 --- a/app/controllers/groups/labels_controller.rb +++ b/app/controllers/groups/labels_controller.rb @@ -2,7 +2,6 @@ class Groups::LabelsController < Groups::ApplicationController include ToggleSubscriptionAction before_action :label, only: [:edit, :update, :destroy] - before_action :available_labels, only: [:index] before_action :authorize_admin_labels!, only: [:new, :create, :edit, :update, :destroy] before_action :save_previous_label_path, only: [:edit] @@ -11,10 +10,12 @@ class Groups::LabelsController < Groups::ApplicationController def index respond_to do |format| format.html do - @labels = @available_labels.page(params[:page]) + @labels = @group.labels + .optionally_search(params[:search]) + .page(params[:page]) end format.json do - render json: LabelSerializer.new.represent_appearance(@available_labels) + render json: LabelSerializer.new.represent_appearance(available_labels) end end end diff --git a/app/controllers/projects/registry/repositories_controller.rb b/app/controllers/projects/registry/repositories_controller.rb index 32c0fc6d14a..ef0433795f4 100644 --- a/app/controllers/projects/registry/repositories_controller.rb +++ b/app/controllers/projects/registry/repositories_controller.rb @@ -18,14 +18,10 @@ module Projects end def destroy - if image.destroy - respond_to do |format| - format.json { head :no_content } - end - else - respond_to do |format| - format.json { head :bad_request } - end + DeleteContainerRepositoryWorker.perform_async(current_user.id, image.id) + + respond_to do |format| + format.json { head :no_content } end end @@ -41,10 +37,10 @@ module Projects # Needed to maintain a backwards compatibility. # def ensure_root_container_repository! - ContainerRegistry::Path.new(@project.full_path).tap do |path| + ::ContainerRegistry::Path.new(@project.full_path).tap do |path| break if path.has_repository? - ContainerRepository.build_from_path(path).tap do |repository| + ::ContainerRepository.build_from_path(path).tap do |repository| repository.save! if repository.has_tags? end end diff --git a/app/helpers/accounts_helper.rb b/app/helpers/accounts_helper.rb index 5d27d30eaa3..a4f19480539 100644 --- a/app/helpers/accounts_helper.rb +++ b/app/helpers/accounts_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module AccountsHelper def incoming_email_token_enabled? current_user.incoming_email_token && Gitlab::IncomingEmail.supports_issue_creation? diff --git a/app/helpers/active_sessions_helper.rb b/app/helpers/active_sessions_helper.rb index 97b6dac67c5..84aa1160f12 100644 --- a/app/helpers/active_sessions_helper.rb +++ b/app/helpers/active_sessions_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActiveSessionsHelper # Maps a device type as defined in `ActiveSession` to an svg icon name and # outputs the icon html. diff --git a/app/helpers/appearances_helper.rb b/app/helpers/appearances_helper.rb index f48db024e3f..ed13c5cfdd6 100644 --- a/app/helpers/appearances_helper.rb +++ b/app/helpers/appearances_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module AppearancesHelper def brand_title current_appearance&.title.presence || 'GitLab Community Edition' diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 0190aa90763..bb7ae03313c 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'digest/md5' require 'uri' @@ -106,11 +108,11 @@ module ApplicationHelper # # Returns an HTML-safe String def time_ago_with_tooltip(time, placement: 'top', html_class: '', short_format: false) - css_classes = short_format ? 'js-short-timeago' : 'js-timeago' - css_classes << " #{html_class}" unless html_class.blank? + css_classes = [short_format ? 'js-short-timeago' : 'js-timeago'] + css_classes << html_class unless html_class.blank? element = content_tag :time, l(time, format: "%b %d, %Y"), - class: css_classes, + class: css_classes.join(' '), title: l(time.to_time.in_time_zone, format: :timeago_tooltip), datetime: time.to_time.getutc.iso8601, data: { diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb index 90fbf49be4a..3ebf0162cb6 100644 --- a/app/helpers/application_settings_helper.rb +++ b/app/helpers/application_settings_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ApplicationSettingsHelper extend self @@ -73,12 +75,12 @@ module ApplicationSettingsHelper def oauth_providers_checkboxes button_based_providers.map do |source| disabled = Gitlab::CurrentSettings.disabled_oauth_sign_in_sources.include?(source.to_s) - css_class = 'btn' - css_class << ' active' unless disabled + css_class = ['btn'] + css_class << 'active' unless disabled checkbox_name = 'application_setting[enabled_oauth_sign_in_sources][]' name = Gitlab::Auth::OAuth::Provider.label_for(source) - label_tag(checkbox_name, class: css_class) do + label_tag(checkbox_name, class: css_class.join(' ')) do check_box_tag(checkbox_name, source, !disabled, autocomplete: 'off', id: name.tr(' ', '_')) + name diff --git a/app/helpers/auth_helper.rb b/app/helpers/auth_helper.rb index 18f0979fc86..c17a54a6dff 100644 --- a/app/helpers/auth_helper.rb +++ b/app/helpers/auth_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module AuthHelper PROVIDERS_WITH_ICONS = %w(twitter github gitlab bitbucket google_oauth2 facebook azure_oauth2 authentiq).freeze LDAP_PROVIDER = /\Aldap/ diff --git a/app/helpers/auto_devops_helper.rb b/app/helpers/auto_devops_helper.rb index 7b076728685..62fc6fb279f 100644 --- a/app/helpers/auto_devops_helper.rb +++ b/app/helpers/auto_devops_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module AutoDevopsHelper def show_auto_devops_callout?(project) Feature.get(:auto_devops_banner_disabled).off? && diff --git a/app/helpers/avatars_helper.rb b/app/helpers/avatars_helper.rb index 494f785e305..321811a3ca3 100644 --- a/app/helpers/avatars_helper.rb +++ b/app/helpers/avatars_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module AvatarsHelper def project_icon(project_id, options = {}) source_icon(Project, project_id, options) @@ -125,9 +127,9 @@ module AvatarsHelper def source_identicon(source, options = {}) bg_key = (source.id % 7) + 1 - options[:class] ||= '' - options[:class] << ' identicon' - options[:class] << " bg#{bg_key}" + + options[:class] = + [*options[:class], "identicon bg#{bg_key}"].join(' ') content_tag(:div, class: options[:class].strip) do source.name[0, 1].upcase diff --git a/app/helpers/award_emoji_helper.rb b/app/helpers/award_emoji_helper.rb index 86b19368cfd..b97a95629f7 100644 --- a/app/helpers/award_emoji_helper.rb +++ b/app/helpers/award_emoji_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module AwardEmojiHelper def toggle_award_url(awardable) return url_for([:toggle_award_emoji, awardable]) unless @project || awardable.is_a?(Note) diff --git a/app/helpers/blame_helper.rb b/app/helpers/blame_helper.rb index 089d9e3e387..82c74e2416d 100644 --- a/app/helpers/blame_helper.rb +++ b/app/helpers/blame_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module BlameHelper def age_map_duration(blame_groups, project) now = Time.zone.now diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb index 96f7415ae98..9cbd5b5f785 100644 --- a/app/helpers/blob_helper.rb +++ b/app/helpers/blob_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module BlobHelper def highlight(blob_name, blob_content, repository: nil, plain: false) plain ||= blob_content.length > Blob::MAXIMUM_TEXT_HIGHLIGHT_SIZE diff --git a/app/helpers/boards_helper.rb b/app/helpers/boards_helper.rb index af878bcf9a0..e3b74f443f7 100644 --- a/app/helpers/boards_helper.rb +++ b/app/helpers/boards_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module BoardsHelper def board @board ||= @board || @boards.first diff --git a/app/helpers/branches_helper.rb b/app/helpers/branches_helper.rb index 07b1fc3d7cf..eadf48205fc 100644 --- a/app/helpers/branches_helper.rb +++ b/app/helpers/branches_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module BranchesHelper def project_branches options_for_select(@project.repository.branch_names, @project.default_branch) diff --git a/app/helpers/breadcrumbs_helper.rb b/app/helpers/breadcrumbs_helper.rb index e88fe6bcd7e..b067376cea0 100644 --- a/app/helpers/breadcrumbs_helper.rb +++ b/app/helpers/breadcrumbs_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module BreadcrumbsHelper def add_to_breadcrumbs(text, link) @breadcrumbs_extra_links ||= [] diff --git a/app/helpers/broadcast_messages_helper.rb b/app/helpers/broadcast_messages_helper.rb index 0a15c29cfb5..289cb44f1e8 100644 --- a/app/helpers/broadcast_messages_helper.rb +++ b/app/helpers/broadcast_messages_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module BroadcastMessagesHelper def broadcast_message(message) return unless message.present? @@ -8,18 +10,17 @@ module BroadcastMessagesHelper end def broadcast_message_style(broadcast_message) - style = '' + style = [] if broadcast_message.color.present? style << "background-color: #{broadcast_message.color}" - style << '; ' if broadcast_message.font.present? end if broadcast_message.font.present? style << "color: #{broadcast_message.font}" end - style + style.join('; ') end def broadcast_message_status(broadcast_message) diff --git a/app/helpers/builds_helper.rb b/app/helpers/builds_helper.rb index 4ec63fdaffc..3c8caec3fe5 100644 --- a/app/helpers/builds_helper.rb +++ b/app/helpers/builds_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module BuildsHelper def build_summary(build, skip: false) if build.has_trace? @@ -12,10 +14,10 @@ module BuildsHelper end def sidebar_build_class(build, current_build) - build_class = '' - build_class += ' active' if build.id === current_build.id - build_class += ' retried' if build.retried? - build_class + build_class = [] + build_class << 'active' if build.id === current_build.id + build_class << 'retried' if build.retried? + build_class.join(' ') end def javascript_build_options diff --git a/app/helpers/button_helper.rb b/app/helpers/button_helper.rb index 2b3fe57767c..7f071d55a6b 100644 --- a/app/helpers/button_helper.rb +++ b/app/helpers/button_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ButtonHelper # Output a "Copy to Clipboard" button # diff --git a/app/helpers/calendar_helper.rb b/app/helpers/calendar_helper.rb index c54b91b0ce5..ad4116fc3da 100644 --- a/app/helpers/calendar_helper.rb +++ b/app/helpers/calendar_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module CalendarHelper def calendar_url_options { format: :ics, diff --git a/app/helpers/ci_status_helper.rb b/app/helpers/ci_status_helper.rb index 330959e536d..f8d36dce45d 100644 --- a/app/helpers/ci_status_helper.rb +++ b/app/helpers/ci_status_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + ## # DEPRECATED # diff --git a/app/helpers/clusters_helper.rb b/app/helpers/clusters_helper.rb index 73049c74d80..a67c91b21d7 100644 --- a/app/helpers/clusters_helper.rb +++ b/app/helpers/clusters_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ClustersHelper def has_multiple_clusters?(project) false diff --git a/app/helpers/commits_helper.rb b/app/helpers/commits_helper.rb index 7a942c44ac4..d52cfd6e37a 100644 --- a/app/helpers/commits_helper.rb +++ b/app/helpers/commits_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module CommitsHelper # Returns a link to the commit author. If the author has a matching user and # is a member of the current @project it will link to the team member page. diff --git a/app/helpers/compare_helper.rb b/app/helpers/compare_helper.rb index 2df5b5d1695..9ece8b0bc5b 100644 --- a/app/helpers/compare_helper.rb +++ b/app/helpers/compare_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module CompareHelper def create_mr_button?(from = params[:from], to = params[:to], project = @project) from.present? && diff --git a/app/helpers/components_helper.rb b/app/helpers/components_helper.rb index 8893209b314..d0ef86851ad 100644 --- a/app/helpers/components_helper.rb +++ b/app/helpers/components_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ComponentsHelper def gitlab_workhorse_version if request.headers['Gitlab-Workhorse'].present? diff --git a/app/helpers/conversational_development_index_helper.rb b/app/helpers/conversational_development_index_helper.rb index 1ff54415811..37e5bb325fb 100644 --- a/app/helpers/conversational_development_index_helper.rb +++ b/app/helpers/conversational_development_index_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ConversationalDevelopmentIndexHelper def score_level(score) if score < 33.33 diff --git a/app/helpers/count_helper.rb b/app/helpers/count_helper.rb index 5cd98f40f78..e16223a82c9 100644 --- a/app/helpers/count_helper.rb +++ b/app/helpers/count_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module CountHelper def approximate_count_with_delimiters(count_data, model) count = count_data[model] diff --git a/app/helpers/dashboard_helper.rb b/app/helpers/dashboard_helper.rb index 19aa55a8d49..463f4145bdd 100644 --- a/app/helpers/dashboard_helper.rb +++ b/app/helpers/dashboard_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module DashboardHelper def assigned_issues_dashboard_path issues_dashboard_path(assignee_id: current_user.id) diff --git a/app/helpers/defer_script_tag_helper.rb b/app/helpers/defer_script_tag_helper.rb index e1567556e5e..d91c6d52683 100644 --- a/app/helpers/defer_script_tag_helper.rb +++ b/app/helpers/defer_script_tag_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module DeferScriptTagHelper # Override the default ActionView `javascript_include_tag` helper to support page specific deferred loading def javascript_include_tag(*sources) diff --git a/app/helpers/deploy_tokens_helper.rb b/app/helpers/deploy_tokens_helper.rb index bd921322476..80a5bb44c69 100644 --- a/app/helpers/deploy_tokens_helper.rb +++ b/app/helpers/deploy_tokens_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module DeployTokensHelper def expand_deploy_tokens_section?(deploy_token) deploy_token.persisted? || diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb index 1bb82fd8150..7684734c014 100644 --- a/app/helpers/diff_helper.rb +++ b/app/helpers/diff_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module DiffHelper def mark_inline_diffs(old_line, new_line) old_diffs, new_diffs = Gitlab::Diff::InlineDiff.new(old_line, new_line).inline_diffs @@ -39,7 +41,8 @@ module DiffHelper line_num_class = %w[diff-line-num unfold js-unfold] line_num_class << 'js-unfold-bottom' if bottom - html = '' + html = [] + if old_pos html << content_tag(:td, '...', class: [*line_num_class, 'old_line'], data: { linenumber: old_pos }) html << content_tag(:td, text, class: [*content_line_class, 'left-side']) if view == :parallel @@ -50,7 +53,7 @@ module DiffHelper html << content_tag(:td, text, class: [*content_line_class, ('right-side' if view == :parallel)]) end - html.html_safe + html.join.html_safe end def diff_line_content(line) @@ -215,9 +218,7 @@ module DiffHelper end def toggle_whitespace_link(url, options) - options[:class] ||= '' - options[:class] << ' btn btn-default' - + options[:class] = [*options[:class], 'btn btn-default'].join(' ') link_to "#{hide_whitespace? ? 'Show' : 'Hide'} whitespace changes", url, class: options[:class] end diff --git a/app/helpers/dropdowns_helper.rb b/app/helpers/dropdowns_helper.rb index 5a2360b4661..4b6c5b215e8 100644 --- a/app/helpers/dropdowns_helper.rb +++ b/app/helpers/dropdowns_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module DropdownsHelper def dropdown_tag(toggle_text, options: {}, &block) content_tag :div, class: "dropdown #{options[:wrapper_class] if options.key?(:wrapper_class)}" do @@ -10,7 +12,7 @@ module DropdownsHelper dropdown_output = dropdown_toggle(toggle_text, data_attr, options) dropdown_output << content_tag(:div, class: "dropdown-menu dropdown-select #{options[:dropdown_class] if options.key?(:dropdown_class)}") do - output = "" + output = [] if options.key?(:title) output << dropdown_title(options[:title]) @@ -31,8 +33,7 @@ module DropdownsHelper end output << dropdown_loading - - output.html_safe + output.join.html_safe end dropdown_output.html_safe @@ -50,7 +51,7 @@ module DropdownsHelper def dropdown_title(title, options: {}) content_tag :div, class: "dropdown-title" do - title_output = "" + title_output = [] if options.fetch(:back, false) title_output << content_tag(:button, class: "dropdown-title-button dropdown-menu-back", aria: { label: "Go back" }, type: "button") do @@ -66,7 +67,7 @@ module DropdownsHelper end end - title_output.html_safe + title_output.join.html_safe end end diff --git a/app/helpers/emails_helper.rb b/app/helpers/emails_helper.rb index c86a26ac30f..2d2e89a2a50 100644 --- a/app/helpers/emails_helper.rb +++ b/app/helpers/emails_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module EmailsHelper include AppearancesHelper @@ -49,8 +51,8 @@ module EmailsHelper def reset_token_expire_message link_tag = link_to('request a new one', new_user_password_url(user_email: @user.email)) - msg = "This link is valid for #{password_reset_token_valid_time}. " - msg << "After it expires, you can #{link_tag}." + "This link is valid for #{password_reset_token_valid_time}. " \ + "After it expires, you can #{link_tag}." end def header_logo diff --git a/app/helpers/emoji_helper.rb b/app/helpers/emoji_helper.rb index 482f68f412b..51b7fd7f352 100644 --- a/app/helpers/emoji_helper.rb +++ b/app/helpers/emoji_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module EmojiHelper def emoji_icon(*args) raw Gitlab::Emoji.gl_emoji_tag(*args) diff --git a/app/helpers/environment_helper.rb b/app/helpers/environment_helper.rb index 1e78a189c08..4b3ef2de701 100644 --- a/app/helpers/environment_helper.rb +++ b/app/helpers/environment_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module EnvironmentHelper def environment_for_build(project, build) return unless build.environment diff --git a/app/helpers/environments_helper.rb b/app/helpers/environments_helper.rb index c005ecbb56b..7b22bc8f98f 100644 --- a/app/helpers/environments_helper.rb +++ b/app/helpers/environments_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module EnvironmentsHelper def environments_list_data { diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb index 34d54e2d681..c94946a04e7 100644 --- a/app/helpers/events_helper.rb +++ b/app/helpers/events_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module EventsHelper ICON_NAMES_BY_EVENT_TYPE = { 'pushed to' => 'commit', diff --git a/app/helpers/explore_helper.rb b/app/helpers/explore_helper.rb index f062a91a166..62be591ec47 100644 --- a/app/helpers/explore_helper.rb +++ b/app/helpers/explore_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ExploreHelper def filter_projects_path(options = {}) exist_opts = { diff --git a/app/helpers/external_wiki_helper.rb b/app/helpers/external_wiki_helper.rb index 8cf890b74a8..e36d63b2946 100644 --- a/app/helpers/external_wiki_helper.rb +++ b/app/helpers/external_wiki_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ExternalWikiHelper def get_project_wiki_path(project) external_wiki_service = project.external_wiki diff --git a/app/helpers/favicon_helper.rb b/app/helpers/favicon_helper.rb index 3a5342a8d9d..4a809731d97 100644 --- a/app/helpers/favicon_helper.rb +++ b/app/helpers/favicon_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module FaviconHelper def favicon_extension_whitelist FaviconUploader::EXTENSION_WHITELIST diff --git a/app/helpers/form_helper.rb b/app/helpers/form_helper.rb index 905e2002592..5705ee54cee 100644 --- a/app/helpers/form_helper.rb +++ b/app/helpers/form_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module FormHelper def form_errors(model, type: 'form') return unless model.errors.any? diff --git a/app/helpers/git_helper.rb b/app/helpers/git_helper.rb index 8ab394384f3..5edc6dcf454 100644 --- a/app/helpers/git_helper.rb +++ b/app/helpers/git_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module GitHelper def strip_gpg_signature(text) text.gsub(/-----BEGIN PGP SIGNATURE-----(.*)-----END PGP SIGNATURE-----/m, "") diff --git a/app/helpers/gitlab_routing_helper.rb b/app/helpers/gitlab_routing_helper.rb index 61e12b0f31e..04cf43be452 100644 --- a/app/helpers/gitlab_routing_helper.rb +++ b/app/helpers/gitlab_routing_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Shorter routing method for some project items module GitlabRoutingHelper extend ActiveSupport::Concern diff --git a/app/helpers/graph_helper.rb b/app/helpers/graph_helper.rb index 1022070ab6f..49b15cde009 100644 --- a/app/helpers/graph_helper.rb +++ b/app/helpers/graph_helper.rb @@ -1,12 +1,14 @@ +# frozen_string_literal: true + module GraphHelper def refs(repo, commit) - refs = commit.ref_names(repo).join(' ') + refs = [commit.ref_names(repo).join(' ')] # append note count notes_count = @graph.notes[commit.id] refs << "[#{pluralize(notes_count, 'note')}]" if notes_count > 0 - refs + refs.join end def parents_zip_spaces(parents, parent_spaces) diff --git a/app/helpers/groups_helper.rb b/app/helpers/groups_helper.rb index 5b51d2f2425..f573fd399a5 100644 --- a/app/helpers/groups_helper.rb +++ b/app/helpers/groups_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module GroupsHelper def group_nav_link_paths %w[groups#projects groups#edit badges#index ci_cd#show ldap_group_links#index hooks#index audit_events#index pipeline_quota#index] @@ -43,22 +45,22 @@ module GroupsHelper def group_title(group, name = nil, url = nil) @has_group_title = true - full_title = '' + full_title = [] group.ancestors.reverse.each_with_index do |parent, index| if index > 0 add_to_breadcrumb_dropdown(group_title_link(parent, hidable: false, show_avatar: true, for_dropdown: true), location: :before) else - full_title += breadcrumb_list_item group_title_link(parent, hidable: false) + full_title << breadcrumb_list_item(group_title_link(parent, hidable: false)) end end - full_title += render "layouts/nav/breadcrumbs/collapsed_dropdown", location: :before, title: _("Show parent subgroups") + full_title << render("layouts/nav/breadcrumbs/collapsed_dropdown", location: :before, title: _("Show parent subgroups")) - full_title += breadcrumb_list_item group_title_link(group) - full_title += ' · '.html_safe + link_to(simple_sanitize(name), url, class: 'group-path breadcrumb-item-text js-breadcrumb-item-text') if name + full_title << breadcrumb_list_item(group_title_link(group)) + full_title << ' · '.html_safe + link_to(simple_sanitize(name), url, class: 'group-path breadcrumb-item-text js-breadcrumb-item-text') if name - full_title.html_safe + full_title.join.html_safe end def projects_lfs_status(group) @@ -138,15 +140,8 @@ module GroupsHelper def group_title_link(group, hidable: false, show_avatar: false, for_dropdown: false) link_to(group_path(group), class: "group-path #{'breadcrumb-item-text' unless for_dropdown} js-breadcrumb-item-text #{'hidable' if hidable}") do - output = - if (group.try(:avatar_url) || show_avatar) && !Rails.env.test? - group_icon(group, class: "avatar-tile", width: 15, height: 15) - else - "" - end - - output << simple_sanitize(group.name) - output.html_safe + icon = group_icon(group, class: "avatar-tile", width: 15, height: 15) if (group.try(:avatar_url) || show_avatar) && !Rails.env.test? + [icon, simple_sanitize(group.name)].join.html_safe end end diff --git a/app/helpers/hooks_helper.rb b/app/helpers/hooks_helper.rb index 0a356ba55d2..c4b39939192 100644 --- a/app/helpers/hooks_helper.rb +++ b/app/helpers/hooks_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module HooksHelper def link_to_test_hook(hook, trigger) path = case hook diff --git a/app/helpers/icons_helper.rb b/app/helpers/icons_helper.rb index a5612372aa6..037004327b9 100644 --- a/app/helpers/icons_helper.rb +++ b/app/helpers/icons_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'json' module IconsHelper @@ -47,9 +49,10 @@ module IconsHelper end end - css_classes = size ? "s#{size}" : "" - css_classes << " #{css_class}" unless css_class.blank? - content_tag(:svg, content_tag(:use, "", { "xlink:href" => "#{sprite_icon_path}##{icon_name}" } ), class: css_classes.empty? ? nil : css_classes) + css_classes = [] + css_classes << "s#{size}" if size + css_classes << "#{css_class}" unless css_class.blank? + content_tag(:svg, content_tag(:use, "", { "xlink:href" => "#{sprite_icon_path}##{icon_name}" } ), class: css_classes.empty? ? nil : css_classes.join(' ')) end def external_snippet_icon(name) @@ -70,10 +73,10 @@ module IconsHelper end def spinner(text = nil, visible = false) - css_class = 'loading' - css_class << ' hide' unless visible + css_class = ['loading'] + css_class << 'hide' unless visible - content_tag :div, class: css_class do + content_tag :div, class: css_class.join(' ') do icon('spinner spin') + text end end @@ -97,9 +100,10 @@ module IconsHelper 'globe' end - name << " fw" if fw + name = [name] + name << "fw" if fw - icon(name, options) + icon(name.join(' '), options) end def file_type_icon_class(type, mode, name) diff --git a/app/helpers/import_helper.rb b/app/helpers/import_helper.rb index c65f1565425..3d0eb3d0d51 100644 --- a/app/helpers/import_helper.rb +++ b/app/helpers/import_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ImportHelper include ::Gitlab::Utils::StrongMemoize diff --git a/app/helpers/instance_configuration_helper.rb b/app/helpers/instance_configuration_helper.rb index cee319f20bc..f695be32743 100644 --- a/app/helpers/instance_configuration_helper.rb +++ b/app/helpers/instance_configuration_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module InstanceConfigurationHelper def instance_configuration_cell_html(value, &block) return '-' unless value.to_s.presence diff --git a/app/helpers/issuables_helper.rb b/app/helpers/issuables_helper.rb index 79449a30305..8396cfe0ac8 100644 --- a/app/helpers/issuables_helper.rb +++ b/app/helpers/issuables_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module IssuablesHelper include GitlabRoutingHelper @@ -167,8 +169,9 @@ module IssuablesHelper end def issuable_meta(issuable, project, text) - output = "" + output = [] output << "Opened #{time_ago_with_tooltip(issuable.created_at)} by ".html_safe + output << content_tag(:strong) do author_output = link_to_member(project, issuable.author, size: 24, mobile_classes: "d-none d-sm-inline", tooltip: true) author_output << link_to_member(project, issuable.author, size: 24, by_username: true, avatar: false, mobile_classes: "d-block d-sm-none") @@ -185,7 +188,7 @@ module IssuablesHelper output << content_tag(:span, (issuable.task_status if issuable.tasks?), id: "task_status", class: "d-none d-sm-none d-md-inline-block") output << content_tag(:span, (issuable.task_status_short if issuable.tasks?), id: "task_status_short", class: "d-md-none") - output.html_safe + output.join.html_safe end def issuable_todo(issuable) diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb index 5b27d1d9404..f7d448ea3a7 100644 --- a/app/helpers/issues_helper.rb +++ b/app/helpers/issues_helper.rb @@ -1,9 +1,11 @@ +# frozen_string_literal: true + module IssuesHelper def issue_css_classes(issue) - classes = "issue" - classes << " closed" if issue.closed? - classes << " today" if issue.today? - classes + classes = ["issue"] + classes << "closed" if issue.closed? + classes << "today" if issue.today? + classes.join(' ') end # Returns an OpenStruct object suitable for use by <tt>options_from_collection_for_select</tt> @@ -105,8 +107,8 @@ module IssuesHelper end def link_to_discussions_to_resolve(merge_request, single_discussion = nil) - link_text = merge_request.to_reference - link_text += " (discussion #{single_discussion.first_note.id})" if single_discussion + link_text = [merge_request.to_reference] + link_text << "(discussion #{single_discussion.first_note.id})" if single_discussion path = if single_discussion Gitlab::UrlBuilder.build(single_discussion.first_note) @@ -115,7 +117,7 @@ module IssuesHelper project_merge_request_path(project, merge_request) end - link_to link_text, path + link_to link_text.join(' '), path end def show_new_issue_link?(project) diff --git a/app/helpers/javascript_helper.rb b/app/helpers/javascript_helper.rb index cd4075b340d..7cb6da26236 100644 --- a/app/helpers/javascript_helper.rb +++ b/app/helpers/javascript_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module JavascriptHelper def page_specific_javascript_tag(js) javascript_include_tag asset_path(js) diff --git a/app/helpers/kerberos_spnego_helper.rb b/app/helpers/kerberos_spnego_helper.rb index f5b0aa7549a..c0eb8f83f56 100644 --- a/app/helpers/kerberos_spnego_helper.rb +++ b/app/helpers/kerberos_spnego_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module KerberosSpnegoHelper def allow_basic_auth? true # different behavior in GitLab Enterprise Edition diff --git a/app/helpers/labels_helper.rb b/app/helpers/labels_helper.rb index c7df25cecef..6c51739ba1a 100644 --- a/app/helpers/labels_helper.rb +++ b/app/helpers/labels_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module LabelsHelper extend self include ActionView::Helpers::TagHelper diff --git a/app/helpers/lazy_image_tag_helper.rb b/app/helpers/lazy_image_tag_helper.rb index 603b9438e35..ac987a04895 100644 --- a/app/helpers/lazy_image_tag_helper.rb +++ b/app/helpers/lazy_image_tag_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module LazyImageTagHelper def placeholder_image "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" @@ -11,9 +13,11 @@ module LazyImageTagHelper options[:data] ||= {} options[:data][:src] = path_to_image(source) - options[:class] ||= "" - options[:class] << " lazy" + # options[:class] can be either String or Array. + klass_opts = Array.wrap(options[:class]) + klass_opts << "lazy" + options[:class] = klass_opts.join(' ') source = placeholder_image end diff --git a/app/helpers/markup_helper.rb b/app/helpers/markup_helper.rb index 3adaa1366c0..f2cd676bb1b 100644 --- a/app/helpers/markup_helper.rb +++ b/app/helpers/markup_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'nokogiri' module MarkupHelper diff --git a/app/helpers/mattermost_helper.rb b/app/helpers/mattermost_helper.rb index 27ff4051c8d..b211fe5076a 100644 --- a/app/helpers/mattermost_helper.rb +++ b/app/helpers/mattermost_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module MattermostHelper def mattermost_teams_options(teams) teams.map do |team| diff --git a/app/helpers/members_helper.rb b/app/helpers/members_helper.rb index a3129cac2b1..5a21403bc5e 100644 --- a/app/helpers/members_helper.rb +++ b/app/helpers/members_helper.rb @@ -1,8 +1,10 @@ +# frozen_string_literal: true + module MembersHelper def remove_member_message(member, user: nil) user = current_user if defined?(current_user) + text = 'Are you sure you want to' - text = 'Are you sure you want to ' action = if member.request? if member.user == user @@ -16,13 +18,12 @@ module MembersHelper "remove #{member.user.name} from" end - text << action << " the #{member.source.human_name} #{member.real_source_type.humanize(capitalize: false)}?" + "#{text} #{action} the #{member.source.human_name} #{member.real_source_type.humanize(capitalize: false)}?" end def remove_member_title(member) - text = " from #{member.real_source_type.humanize(capitalize: false)}" - - text.prepend(member.request? ? 'Deny access request' : 'Remove user') + action = member.request? ? 'Deny access request' : 'Remove user' + "#{action} from #{member.real_source_type.humanize(capitalize: false)}" end def leave_confirmation_message(member_source) @@ -32,9 +33,6 @@ module MembersHelper def filter_group_project_member_path(options = {}) options = params.slice(:search, :sort).merge(options) - - path = request.path - path << "?#{options.to_param}" - path + "#{request.path}?#{options.to_param}" end end diff --git a/app/helpers/merge_requests_helper.rb b/app/helpers/merge_requests_helper.rb index 097be8a0643..87af6fb08f0 100644 --- a/app/helpers/merge_requests_helper.rb +++ b/app/helpers/merge_requests_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module MergeRequestsHelper def new_mr_path_from_push_event(event) target_project = event.project.default_merge_request_target @@ -19,10 +21,10 @@ module MergeRequestsHelper end def mr_css_classes(mr) - classes = "merge-request" - classes << " closed" if mr.closed? - classes << " merged" if mr.merged? - classes + classes = ["merge-request"] + classes << "closed" if mr.closed? + classes << "merged" if mr.merged? + classes.join(' ') end def ci_build_details_path(merge_request) diff --git a/app/helpers/milestones_helper.rb b/app/helpers/milestones_helper.rb index 95da8f00aff..999143002bb 100644 --- a/app/helpers/milestones_helper.rb +++ b/app/helpers/milestones_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module MilestonesHelper include EntityDateHelper @@ -119,20 +121,18 @@ module MilestonesHelper title = date_type == :start ? "Start date" : "End date" if date - time_ago = time_ago_in_words(date) - time_ago.slice!("about ") - - time_ago << if date.past? - " ago" - else - " remaining" - end + time_ago = time_ago_in_words(date).sub("about ", "") + state = if date.past? + "ago" + else + "remaining" + end content = [ title, "<br />", date.to_s(:medium), - "(#{time_ago})" + "(#{time_ago} #{state})" ].join(" ") content.html_safe diff --git a/app/helpers/milestones_routing_helper.rb b/app/helpers/milestones_routing_helper.rb index a0b2616f224..a49b561533a 100644 --- a/app/helpers/milestones_routing_helper.rb +++ b/app/helpers/milestones_routing_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module MilestonesRoutingHelper def milestone_path(milestone, *args) if milestone.group_milestone? diff --git a/app/helpers/mirror_helper.rb b/app/helpers/mirror_helper.rb index 93ed22513ac..a4025730397 100644 --- a/app/helpers/mirror_helper.rb +++ b/app/helpers/mirror_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module MirrorHelper def mirrors_form_data_attributes { project_mirror_endpoint: project_mirror_path(@project) } diff --git a/app/helpers/namespaces_helper.rb b/app/helpers/namespaces_helper.rb index 6535afb6425..e7537ca5733 100644 --- a/app/helpers/namespaces_helper.rb +++ b/app/helpers/namespaces_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module NamespacesHelper def namespace_id_from(params) params.dig(:project, :namespace_id) || params[:namespace_id] diff --git a/app/helpers/nav_helper.rb b/app/helpers/nav_helper.rb index a84a39235d8..761f42f2f0f 100644 --- a/app/helpers/nav_helper.rb +++ b/app/helpers/nav_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module NavHelper def header_links @header_links ||= get_header_links diff --git a/app/helpers/notes_helper.rb b/app/helpers/notes_helper.rb index 6285b43f917..a80c8f273a8 100644 --- a/app/helpers/notes_helper.rb +++ b/app/helpers/notes_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module NotesHelper def note_target_fields(note) if note.noteable diff --git a/app/helpers/notifications_helper.rb b/app/helpers/notifications_helper.rb index a185f2916d4..5318ab4ddef 100644 --- a/app/helpers/notifications_helper.rb +++ b/app/helpers/notifications_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module NotificationsHelper include IconsHelper diff --git a/app/helpers/numbers_helper.rb b/app/helpers/numbers_helper.rb index 45bd3606076..f609b6c0cec 100644 --- a/app/helpers/numbers_helper.rb +++ b/app/helpers/numbers_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module NumbersHelper def limited_counter_with_delimiter(resource, **options) limit = options.fetch(:limit, 1000).to_i diff --git a/app/helpers/page_layout_helper.rb b/app/helpers/page_layout_helper.rb index 68d892393ef..b33c074d1af 100644 --- a/app/helpers/page_layout_helper.rb +++ b/app/helpers/page_layout_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module PageLayoutHelper def page_title(*titles) @page_title ||= [] @@ -65,14 +67,14 @@ module PageLayoutHelper end def page_card_meta_tags - tags = '' + tags = [] page_card_attributes.each_with_index do |pair, i| tags << tag(:meta, property: "twitter:label#{i + 1}", content: pair[0]) tags << tag(:meta, property: "twitter:data#{i + 1}", content: pair[1]) end - tags.html_safe + tags.join.html_safe end def header_title(title = nil, title_url = nil) @@ -115,16 +117,16 @@ module PageLayoutHelper end def container_class - css_class = "container-fluid" + css_class = ["container-fluid"] unless fluid_layout - css_class += " container-limited" + css_class << "container-limited" end if blank_container - css_class += " container-blank" + css_class << "container-blank" end - css_class + css_class.join(' ') end end diff --git a/app/helpers/pagination_helper.rb b/app/helpers/pagination_helper.rb index 83dd76a01dd..d05153c9d4b 100644 --- a/app/helpers/pagination_helper.rb +++ b/app/helpers/pagination_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module PaginationHelper def paginate_collection(collection, remote: nil) if collection.is_a?(Kaminari::PaginatableWithoutCount) diff --git a/app/helpers/performance_bar_helper.rb b/app/helpers/performance_bar_helper.rb index d24efe37f5f..7518cec160c 100644 --- a/app/helpers/performance_bar_helper.rb +++ b/app/helpers/performance_bar_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module PerformanceBarHelper # This is a hack since using `alias_method :performance_bar_enabled?, :peek_enabled?` # in WithPerformanceBar breaks tests (but works in the browser). diff --git a/app/helpers/pipeline_schedules_helper.rb b/app/helpers/pipeline_schedules_helper.rb index 4b9f6bd2caf..0e166106b32 100644 --- a/app/helpers/pipeline_schedules_helper.rb +++ b/app/helpers/pipeline_schedules_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module PipelineSchedulesHelper def timezone_data ActiveSupport::TimeZone.all.map do |timezone| diff --git a/app/helpers/preferences_helper.rb b/app/helpers/preferences_helper.rb index fb523cb865b..ff9842d4cd9 100644 --- a/app/helpers/preferences_helper.rb +++ b/app/helpers/preferences_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Helper methods for per-User preferences module PreferencesHelper def layout_choices diff --git a/app/helpers/profiles_helper.rb b/app/helpers/profiles_helper.rb index e7aa92e6e5c..55674e37a34 100644 --- a/app/helpers/profiles_helper.rb +++ b/app/helpers/profiles_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ProfilesHelper def attribute_provider_label(attribute) user_synced_attributes_metadata = current_user.user_synced_attributes_metadata diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index 7a9b63d8852..89fee06ee77 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ProjectsHelper def link_to_project(project) link_to [project.namespace.becomes(Namespace), project], title: h(project.name) do @@ -50,7 +52,7 @@ module ProjectsHelper return "(deleted)" unless author - author_html = "" + author_html = [] # Build avatar image tag author_html << link_to_member_avatar(author, opts) if opts[:avatar] @@ -60,7 +62,7 @@ module ProjectsHelper author_html << capture(&block) if block - author_html = author_html.html_safe + author_html = author_html.join.html_safe if opts[:name] link_to(author_html, user_path(author), class: "author-link #{"#{opts[:extra_class]}" if opts[:extra_class]} #{"#{opts[:mobile_classes]}" if opts[:mobile_classes]}").html_safe @@ -80,15 +82,8 @@ module ProjectsHelper end project_link = link_to project_path(project) do - output = - if project.avatar_url && !Rails.env.test? - project_icon(project, alt: project.name, class: 'avatar-tile', width: 15, height: 15) - else - "" - end - - output << content_tag("span", simple_sanitize(project.name), class: "breadcrumb-item-text js-breadcrumb-item-text") - output.html_safe + icon = project_icon(project, alt: project.name, class: 'avatar-tile', width: 15, height: 15) if project.avatar_url && !Rails.env.test? + [icon, content_tag("span", simple_sanitize(project.name), class: "breadcrumb-item-text js-breadcrumb-item-text")].join.html_safe end namespace_link = breadcrumb_list_item(namespace_link) unless project.group diff --git a/app/helpers/repository_languages_helper.rb b/app/helpers/repository_languages_helper.rb index 9a842cf5ce0..c1505b52808 100644 --- a/app/helpers/repository_languages_helper.rb +++ b/app/helpers/repository_languages_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module RepositoryLanguagesHelper def repository_languages_bar(languages) return if languages.none? diff --git a/app/helpers/rss_helper.rb b/app/helpers/rss_helper.rb index 7d4fa83a67a..67c7d244f11 100644 --- a/app/helpers/rss_helper.rb +++ b/app/helpers/rss_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module RssHelper def rss_url_options { format: :atom, feed_token: current_user.try(:feed_token) } diff --git a/app/helpers/runners_helper.rb b/app/helpers/runners_helper.rb index 9fb42487a75..cb21f922401 100644 --- a/app/helpers/runners_helper.rb +++ b/app/helpers/runners_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module RunnersHelper def runner_status_icon(runner) status = runner.status diff --git a/app/helpers/safe_params_helper.rb b/app/helpers/safe_params_helper.rb index b568e8810cc..72bf1377b02 100644 --- a/app/helpers/safe_params_helper.rb +++ b/app/helpers/safe_params_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module SafeParamsHelper # Rails 5.0 requires to permit `params` if they're used in url helpers. # Use this helper when generating links with `params.merge(...)` diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb index 98074a4c0c5..c509cd592c4 100644 --- a/app/helpers/search_helper.rb +++ b/app/helpers/search_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module SearchHelper def search_autocomplete_opts(term) return unless current_user diff --git a/app/helpers/selects_helper.rb b/app/helpers/selects_helper.rb index 6cefcde558a..cf60696ef39 100644 --- a/app/helpers/selects_helper.rb +++ b/app/helpers/selects_helper.rb @@ -1,12 +1,14 @@ +# frozen_string_literal: true + module SelectsHelper def users_select_tag(id, opts = {}) - css_class = "ajax-users-select " - css_class << "multiselect " if opts[:multiple] - css_class << "skip_ldap " if opts[:skip_ldap] + css_class = ["ajax-users-select"] + css_class << "multiselect" if opts[:multiple] + css_class << "skip_ldap" if opts[:skip_ldap] css_class << (opts[:class] || '') value = opts[:selected] || '' html = { - class: css_class, + class: css_class.join(' '), data: users_select_data_attributes(opts) } @@ -24,20 +26,21 @@ module SelectsHelper end def groups_select_tag(id, opts = {}) - opts[:class] ||= '' - opts[:class] << ' ajax-groups-select' + classes = Array.wrap(opts[:class]) + classes << 'ajax-groups-select' + + opts[:class] = classes.join(' ') + select2_tag(id, opts) end def namespace_select_tag(id, opts = {}) - opts[:class] ||= '' - opts[:class] << ' ajax-namespace-select' + opts[:class] = [*opts[:class], 'ajax-namespace-select'].join(' ') select2_tag(id, opts) end def project_select_tag(id, opts = {}) - opts[:class] ||= '' - opts[:class] << ' ajax-project-select' + opts[:class] = [*opts[:class], 'ajax-project-select'].join(' ') unless opts.delete(:scope) == :all if @group @@ -57,7 +60,10 @@ module SelectsHelper end def select2_tag(id, opts = {}) - opts[:class] << ' multiselect' if opts[:multiple] + klass_opts = [opts[:class]] + klass_opts << 'multiselect' if opts[:multiple] + + opts[:class] = klass_opts.join(' ') value = opts[:selected] || '' hidden_field_tag(id, value, opts) diff --git a/app/helpers/sentry_helper.rb b/app/helpers/sentry_helper.rb index 3d255df66a0..d53eaef9952 100644 --- a/app/helpers/sentry_helper.rb +++ b/app/helpers/sentry_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module SentryHelper def sentry_enabled? Gitlab::Sentry.enabled? diff --git a/app/helpers/services_helper.rb b/app/helpers/services_helper.rb index f872990122e..8b554e1aaa9 100644 --- a/app/helpers/services_helper.rb +++ b/app/helpers/services_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ServicesHelper def service_event_description(event) case event diff --git a/app/helpers/sidekiq_helper.rb b/app/helpers/sidekiq_helper.rb index 50aeb7f4b82..32bf3526571 100644 --- a/app/helpers/sidekiq_helper.rb +++ b/app/helpers/sidekiq_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module SidekiqHelper SIDEKIQ_PS_REGEXP = %r{\A (?<pid>\d+)\s+ diff --git a/app/helpers/snippets_helper.rb b/app/helpers/snippets_helper.rb index a05640773ad..c7d31f3469d 100644 --- a/app/helpers/snippets_helper.rb +++ b/app/helpers/snippets_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module SnippetsHelper def reliable_snippet_path(snippet, opts = nil) if snippet.project_id? diff --git a/app/helpers/sorting_helper.rb b/app/helpers/sorting_helper.rb index 36a311dfa8a..731b6806b5f 100644 --- a/app/helpers/sorting_helper.rb +++ b/app/helpers/sorting_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module SortingHelper def sort_options_hash { diff --git a/app/helpers/storage_health_helper.rb b/app/helpers/storage_health_helper.rb index b76c1228220..182e8e6641b 100644 --- a/app/helpers/storage_health_helper.rb +++ b/app/helpers/storage_health_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module StorageHealthHelper def failing_storage_health_message(storage_health) storage_name = content_tag(:strong, h(storage_health.storage_name)) diff --git a/app/helpers/storage_helper.rb b/app/helpers/storage_helper.rb index e19c67a37ca..be8761db562 100644 --- a/app/helpers/storage_helper.rb +++ b/app/helpers/storage_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module StorageHelper def storage_counter(size_in_bytes) precision = size_in_bytes < 1.megabyte ? 0 : 1 diff --git a/app/helpers/submodule_helper.rb b/app/helpers/submodule_helper.rb index ec2cf2b16c0..164c69ca50b 100644 --- a/app/helpers/submodule_helper.rb +++ b/app/helpers/submodule_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module SubmoduleHelper extend self diff --git a/app/helpers/system_note_helper.rb b/app/helpers/system_note_helper.rb index 5b4a141dbcf..ac4e8f54260 100644 --- a/app/helpers/system_note_helper.rb +++ b/app/helpers/system_note_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module SystemNoteHelper ICON_NAMES_BY_ACTION = { 'commit' => 'commit', @@ -21,7 +23,8 @@ module SystemNoteHelper 'outdated' => 'pencil-square', 'duplicate' => 'issue-duplicate', 'locked' => 'lock', - 'unlocked' => 'lock-open' + 'unlocked' => 'lock-open', + 'due_date' => 'calendar' }.freeze def system_note_icon_name(note) diff --git a/app/helpers/tab_helper.rb b/app/helpers/tab_helper.rb index ee701076a14..e310fda51d7 100644 --- a/app/helpers/tab_helper.rb +++ b/app/helpers/tab_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module TabHelper # Navigation link helper # @@ -47,9 +49,7 @@ module TabHelper # Add our custom class into the html_options, which may or may not exist # and which may or may not already have a :class key o = options.delete(:html_options) || {} - o[:class] ||= '' - o[:class] += ' ' + klass - o[:class].strip! + o[:class] = [*o[:class], klass].join(' ').strip if block_given? content_tag(:li, capture(&block), o) diff --git a/app/helpers/tags_helper.rb b/app/helpers/tags_helper.rb index d000d6b1c0a..de0b92b6fd7 100644 --- a/app/helpers/tags_helper.rb +++ b/app/helpers/tags_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module TagsHelper def tag_path(tag) "/tags/#{tag}" @@ -14,12 +16,13 @@ module TagsHelper end def tag_list(project) - html = '' + html = [] + project.tag_list.each do |tag| html << link_to(tag, tag_path(tag)) end - html.html_safe + html.join.html_safe end def protected_tag?(project, tag) diff --git a/app/helpers/time_helper.rb b/app/helpers/time_helper.rb index 336385f6798..94044d7b85e 100644 --- a/app/helpers/time_helper.rb +++ b/app/helpers/time_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module TimeHelper def time_interval_in_words(interval_in_seconds) interval_in_seconds = interval_in_seconds.to_i diff --git a/app/helpers/todos_helper.rb b/app/helpers/todos_helper.rb index 7cd74358168..6bd78336ed3 100644 --- a/app/helpers/todos_helper.rb +++ b/app/helpers/todos_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module TodosHelper def todos_pending_count @todos_pending_count ||= current_user.todos_pending_count @@ -94,9 +96,7 @@ module TodosHelper end end - path = request.path - path << "?#{options.to_param}" - path + "#{request.path}?#{options.to_param}" end def todo_actions_options @@ -152,10 +152,11 @@ module TodosHelper '' end - html = "· ".html_safe - html << content_tag(:span, class: css_class) do + content = content_tag(:span, class: css_class) do "Due #{is_due_today ? "today" : todo.target.due_date.to_s(:medium)}" end + + "· #{content}".html_safe end private diff --git a/app/helpers/tree_helper.rb b/app/helpers/tree_helper.rb index dc42caa70e5..80f61a371fd 100644 --- a/app/helpers/tree_helper.rb +++ b/app/helpers/tree_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module TreeHelper FILE_LIMIT = 1_000 @@ -8,7 +10,7 @@ module TreeHelper def render_tree(tree) # Sort submodules and folders together by name ahead of files folders, files, submodules = tree.trees, tree.blobs, tree.submodules - tree = '' + tree = [] items = (folders + submodules).sort_by(&:name) + files if items.size > FILE_LIMIT @@ -18,7 +20,7 @@ module TreeHelper end tree << render(partial: 'projects/tree/tree_row', collection: items) if items.present? - tree.html_safe + tree.join.html_safe end # Return an image icon depending on the file type and mode diff --git a/app/helpers/triggers_helper.rb b/app/helpers/triggers_helper.rb index ce435ca2241..5cfdc0971f0 100644 --- a/app/helpers/triggers_helper.rb +++ b/app/helpers/triggers_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module TriggersHelper def builds_trigger_url(project_id, ref: nil) if ref.nil? diff --git a/app/helpers/user_callouts_helper.rb b/app/helpers/user_callouts_helper.rb index 657a3227dd4..bae01d476df 100644 --- a/app/helpers/user_callouts_helper.rb +++ b/app/helpers/user_callouts_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module UserCalloutsHelper GKE_CLUSTER_INTEGRATION = 'gke_cluster_integration'.freeze GCP_SIGNUP_OFFER = 'gcp_signup_offer'.freeze diff --git a/app/helpers/users_helper.rb b/app/helpers/users_helper.rb index 2c0c4254a0c..bcd91f619c8 100644 --- a/app/helpers/users_helper.rb +++ b/app/helpers/users_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module UsersHelper def user_link(user) link_to(user.name, user_path(user), diff --git a/app/helpers/version_check_helper.rb b/app/helpers/version_check_helper.rb index a7fef93e7f1..75637eb0676 100644 --- a/app/helpers/version_check_helper.rb +++ b/app/helpers/version_check_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module VersionCheckHelper def version_status_badge return unless Rails.env.production? diff --git a/app/helpers/visibility_level_helper.rb b/app/helpers/visibility_level_helper.rb index 7b64869c9ea..e690350a0d1 100644 --- a/app/helpers/visibility_level_helper.rb +++ b/app/helpers/visibility_level_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module VisibilityLevelHelper def visibility_level_color(level) case level @@ -82,7 +84,7 @@ module VisibilityLevelHelper def disallowed_project_visibility_level_description(level, project) level_name = Gitlab::VisibilityLevel.level_name(level).downcase reasons = [] - instructions = '' + instructions = [] unless project.visibility_level_allowed_as_fork?(level) reasons << "the fork source project has lower visibility" @@ -96,7 +98,7 @@ module VisibilityLevelHelper end reasons = reasons.any? ? ' because ' + reasons.to_sentence : '' - "This project cannot be #{level_name}#{reasons}.#{instructions}".html_safe + "This project cannot be #{level_name}#{reasons}.#{instructions.join}".html_safe end # Note: these messages closely mirror the form validation strings found in the group @@ -104,7 +106,7 @@ module VisibilityLevelHelper def disallowed_group_visibility_level_description(level, group) level_name = Gitlab::VisibilityLevel.level_name(level).downcase reasons = [] - instructions = '' + instructions = [] unless group.visibility_level_allowed_by_projects?(level) reasons << "it contains projects with higher visibility" @@ -122,7 +124,7 @@ module VisibilityLevelHelper end reasons = reasons.any? ? ' because ' + reasons.to_sentence : '' - "This group cannot be #{level_name}#{reasons}.#{instructions}".html_safe + "This group cannot be #{level_name}#{reasons}.#{instructions.join}".html_safe end def visibility_icon_description(form_model) diff --git a/app/helpers/webpack_helper.rb b/app/helpers/webpack_helper.rb index 72f6b397046..345ddcf023a 100644 --- a/app/helpers/webpack_helper.rb +++ b/app/helpers/webpack_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module WebpackHelper def webpack_bundle_tag(bundle) javascript_include_tag(*webpack_entrypoint_paths(bundle)) diff --git a/app/helpers/wiki_helper.rb b/app/helpers/wiki_helper.rb index 17940aeb900..647f34e57ed 100644 --- a/app/helpers/wiki_helper.rb +++ b/app/helpers/wiki_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module WikiHelper include API::Helpers::RelatedResourcesHelpers diff --git a/app/helpers/workhorse_helper.rb b/app/helpers/workhorse_helper.rb index fd1d78bd9b8..f19445fca1a 100644 --- a/app/helpers/workhorse_helper.rb +++ b/app/helpers/workhorse_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Helpers to send Git blobs, diffs, patches or archives through Workhorse. # Workhorse will also serve files when using `send_file`. module WorkhorseHelper diff --git a/app/models/label.rb b/app/models/label.rb index 96c1515b41a..8db7c3abd10 100644 --- a/app/models/label.rb +++ b/app/models/label.rb @@ -5,6 +5,7 @@ class Label < ActiveRecord::Base include Referable include Subscribable include Gitlab::SQL::Pattern + include OptionallySearch # Represents a "No Label" state used for filtering Issues and Merge # Requests that have no label assigned. diff --git a/app/models/license_template.rb b/app/models/license_template.rb index 0ad75b27827..693a6a89fd2 100644 --- a/app/models/license_template.rb +++ b/app/models/license_template.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class LicenseTemplate PROJECT_TEMPLATE_REGEX = %r{[\<\{\[] diff --git a/app/models/project.rb b/app/models/project.rb index 45cf527d7c6..8928bffd36c 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -2063,6 +2063,12 @@ class Project < ActiveRecord::Base auto_cancel_pending_pipelines == 'enabled' end + # Update the default branch querying the remote to determine its HEAD + def update_root_ref(remote_name) + root_ref = repository.find_remote_root_ref(remote_name) + change_head(root_ref) if root_ref.present? && root_ref != default_branch + end + private def rename_or_migrate_repository! diff --git a/app/models/repository.rb b/app/models/repository.rb index 929d28b9d88..e98021af818 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -24,6 +24,7 @@ class Repository delegate :ref_name_for_sha, to: :raw_repository delegate :bundle_to_disk, to: :raw_repository + delegate :find_remote_root_ref, to: :raw_repository CreateTreeError = Class.new(StandardError) diff --git a/app/models/system_note_metadata.rb b/app/models/system_note_metadata.rb index 376ef673ca8..6fadbcefa53 100644 --- a/app/models/system_note_metadata.rb +++ b/app/models/system_note_metadata.rb @@ -15,7 +15,7 @@ class SystemNoteMetadata < ActiveRecord::Base commit description merge confidential visible label assignee cross_reference title time_tracking branch milestone discussion task moved opened closed merged duplicate locked unlocked - outdated tag + outdated tag due_date ].freeze validates :note, presence: true diff --git a/app/serializers/discussion_entity.rb b/app/serializers/discussion_entity.rb index ed09db0f3f4..ebe76c9fcda 100644 --- a/app/serializers/discussion_entity.rb +++ b/app/serializers/discussion_entity.rb @@ -6,6 +6,7 @@ class DiscussionEntity < Grape::Entity expose :id, :reply_id expose :position, if: -> (d, _) { d.diff_discussion? && !d.legacy_diff_discussion? } + expose :original_position, if: -> (d, _) { d.diff_discussion? && !d.legacy_diff_discussion? } expose :line_code, if: -> (d, _) { d.diff_discussion? } expose :expanded?, as: :expanded expose :active?, as: :active, if: -> (d, _) { d.diff_discussion? } diff --git a/app/services/issuable/common_system_notes_service.rb b/app/services/issuable/common_system_notes_service.rb index ab53c38aa3a..765de9c66b0 100644 --- a/app/services/issuable/common_system_notes_service.rb +++ b/app/services/issuable/common_system_notes_service.rb @@ -17,6 +17,7 @@ module Issuable create_labels_note(old_labels) if issuable.labels != old_labels create_discussion_lock_note if issuable.previous_changes.include?('discussion_locked') create_milestone_note if issuable.previous_changes.include?('milestone_id') + create_due_date_note if issuable.previous_changes.include?('due_date') end private @@ -90,6 +91,10 @@ module Issuable SystemNoteService.change_milestone(issuable, issuable.project, current_user, issuable.milestone) end + def create_due_date_note + SystemNoteService.change_due_date(issuable, issuable.project, current_user, issuable.due_date) + end + def create_discussion_lock_note SystemNoteService.discussion_lock(issuable, current_user) end diff --git a/app/services/projects/container_repository/destroy_service.rb b/app/services/projects/container_repository/destroy_service.rb new file mode 100644 index 00000000000..a8e7eab6068 --- /dev/null +++ b/app/services/projects/container_repository/destroy_service.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module Projects + module ContainerRepository + class DestroyService < BaseService + def execute(container_repository) + return false unless can?(current_user, :update_container_image, project) + + container_repository.destroy + end + end + end +end diff --git a/app/services/projects/destroy_service.rb b/app/services/projects/destroy_service.rb index 76e22507698..01de6afcd8e 100644 --- a/app/services/projects/destroy_service.rb +++ b/app/services/projects/destroy_service.rb @@ -159,7 +159,7 @@ module Projects def remove_legacy_registry_tags return true unless Gitlab.config.registry.enabled - ContainerRepository.build_root_repository(project).tap do |repository| + ::ContainerRepository.build_root_repository(project).tap do |repository| break repository.has_tags? ? repository.delete_tags! : true end end diff --git a/app/services/projects/update_remote_mirror_service.rb b/app/services/projects/update_remote_mirror_service.rb index 591b38b8151..85b9eb02803 100644 --- a/app/services/projects/update_remote_mirror_service.rb +++ b/app/services/projects/update_remote_mirror_service.rb @@ -5,13 +5,14 @@ module Projects attr_reader :errors def execute(remote_mirror) - @errors = [] - return success unless remote_mirror.enabled? + errors = [] + begin remote_mirror.ensure_remote! repository.fetch_remote(remote_mirror.remote_name, no_tags: true) + project.update_root_ref(remote_mirror.remote_name) opts = {} if remote_mirror.only_protected_branches? diff --git a/app/services/quick_actions/interpret_service.rb b/app/services/quick_actions/interpret_service.rb index a4c4c9e4812..be9d1e48435 100644 --- a/app/services/quick_actions/interpret_service.rb +++ b/app/services/quick_actions/interpret_service.rb @@ -489,6 +489,30 @@ module QuickActions "#{comment} #{TABLEFLIP}" end + desc "Lock the discussion" + explanation "Locks the discussion" + condition do + issuable.is_a?(Issuable) && + issuable.persisted? && + !issuable.discussion_locked? && + current_user.can?(:"admin_#{issuable.to_ability_name}", issuable) + end + command :lock do + @updates[:discussion_locked] = true + end + + desc "Unlock the discussion" + explanation "Unlocks the discussion" + condition do + issuable.is_a?(Issuable) && + issuable.persisted? && + issuable.discussion_locked? && + current_user.can?(:"admin_#{issuable.to_ability_name}", issuable) + end + command :unlock do + @updates[:discussion_locked] = false + end + # This is a dummy command, so that it appears in the autocomplete commands desc 'CC' params '@user' diff --git a/app/services/system_note_service.rb b/app/services/system_note_service.rb index 3ea81445798..c5d05992575 100644 --- a/app/services/system_note_service.rb +++ b/app/services/system_note_service.rb @@ -119,6 +119,26 @@ module SystemNoteService create_note(NoteSummary.new(noteable, project, author, body, action: 'milestone')) end + # Called when the due_date of a Noteable is changed + # + # noteable - Noteable object + # project - Project owning noteable + # author - User performing the change + # due_date - Due date being assigned, or nil + # + # Example Note text: + # + # "removed due date" + # + # "changed due date to September 20, 2018" + # + # Returns the created Note object + def change_due_date(noteable, project, author, due_date) + body = due_date ? "changed due date to #{due_date.to_s(:long)}" : 'removed due date' + + create_note(NoteSummary.new(noteable, project, author, body, action: 'due_date')) + end + # Called when the estimated time of a Noteable is changed # # noteable - Noteable object diff --git a/app/views/import/gitlab_projects/new.html.haml b/app/views/import/gitlab_projects/new.html.haml index 4225ee19217..c4218f3d787 100644 --- a/app/views/import/gitlab_projects/new.html.haml +++ b/app/views/import/gitlab_projects/new.html.haml @@ -8,8 +8,11 @@ = form_tag import_gitlab_project_path, class: 'new_project', multipart: true do .row + .form-group.project-name.col-sm-12 + = label_tag :name, _('Project name'), class: 'label-bold' + = text_field_tag :name, @name, placeholder: "My awesome project", class: "js-project-name form-control input-lg", autofocus: true, required: true .form-group.col-12.col-sm-6 - = label_tag :namespace_id, 'Project path', class: 'label-bold' + = label_tag :namespace_id, _('Project URL'), class: 'label-bold' .form-group .input-group - if current_user.can_select_namespace? @@ -24,8 +27,8 @@ #{user_url(current_user.username)}/ = hidden_field_tag :namespace_id, value: current_user.namespace_id .form-group.col-12.col-sm-6.project-path - = label_tag :path, _('Project name'), class: 'label-bold' - = text_field_tag :path, @path, placeholder: "my-awesome-project", class: "js-path-name form-control", tabindex: 2, autofocus: true, required: true + = label_tag :path, _('Project slug'), class: 'label-bold' + = text_field_tag :path, @path, placeholder: "my-awesome-project", class: "js-path-name form-control", tabindex: 2, required: true .row .form-group.col-md-12 diff --git a/app/views/projects/_new_project_fields.html.haml b/app/views/projects/_new_project_fields.html.haml index ad8c7911fad..3b6090211c0 100644 --- a/app/views/projects/_new_project_fields.html.haml +++ b/app/views/projects/_new_project_fields.html.haml @@ -3,10 +3,13 @@ .row{ id: project_name_id } = f.hidden_field :ci_cd_only, value: ci_cd_only + .form-group.project-name.col-sm-12 + = f.label :name, class: 'label-bold' do + %span= _("Project name") + = f.text_field :name, placeholder: "My awesome project", class: "form-control input-lg", autofocus: true, required: true .form-group.project-path.col-sm-6 = f.label :namespace_id, class: 'label-bold' do - %span - Project path + %span= s_("Project URL") .input-group - if current_user.can_select_namespace? .input-group-prepend.has-tooltip{ title: root_url } @@ -27,13 +30,12 @@ = f.hidden_field :namespace_id, value: current_user.namespace_id .form-group.project-path.col-sm-6 = f.label :path, class: 'label-bold' do - %span - Project name - = f.text_field :path, placeholder: "my-awesome-project", class: "form-control", tabindex: 2, autofocus: true, required: true + %span= _("Project slug") + = f.text_field :path, placeholder: "my-awesome-project", class: "form-control", tabindex: 2, required: true - if current_user.can_create_group? .form-text.text-muted Want to house several dependent projects under the same namespace? - = link_to "Create a group", new_group_path + = link_to "Create a group.", new_group_path .form-group = f.label :description, class: 'label-bold' do diff --git a/app/views/projects/wikis/edit.html.haml b/app/views/projects/wikis/edit.html.haml index d4afa995d63..e12b8f2858c 100644 --- a/app/views/projects/wikis/edit.html.haml +++ b/app/views/projects/wikis/edit.html.haml @@ -28,16 +28,8 @@ = link_to project_wiki_history_path(@project, @page), class: "btn" do = s_("Wiki|Page history") - if can?(current_user, :admin_wiki, @project) - %button.btn.btn-danger{ data: { toggle: 'modal', - target: '#delete-wiki-modal', - delete_wiki_url: project_wiki_path(@project, @page), - page_title: @page.title.capitalize }, - id: 'delete-wiki-button', - type: 'button' } - = _('Delete') + #delete-wiki-modal-wrapper{ data: { delete_wiki_url: project_wiki_path(@project, @page), page_title: @page.title.capitalize } } = render 'form', uploads_path: wiki_attachment_upload_url = render 'sidebar' - -#delete-wiki-modal.modal.fade diff --git a/app/workers/all_queues.yml b/app/workers/all_queues.yml index ae9dc8d4857..1eeb972cee9 100644 --- a/app/workers/all_queues.yml +++ b/app/workers/all_queues.yml @@ -87,6 +87,7 @@ - authorized_projects - background_migration - create_gpg_signature +- delete_container_repository - delete_merged_branches - delete_user - email_receiver diff --git a/app/workers/delete_container_repository_worker.rb b/app/workers/delete_container_repository_worker.rb new file mode 100644 index 00000000000..b703530d3a0 --- /dev/null +++ b/app/workers/delete_container_repository_worker.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +class DeleteContainerRepositoryWorker + include ApplicationWorker + include ExclusiveLeaseGuard + + LEASE_TIMEOUT = 1.hour + + attr_reader :container_repository + + def perform(current_user_id, container_repository_id) + current_user = User.find_by(id: current_user_id) + @container_repository = ContainerRepository.find_by(id: container_repository_id) + project = container_repository&.project + + return unless current_user && container_repository && project + + # If a user accidentally attempts to delete the same container registry in quick succession, + # this can lead to orphaned tags. + try_obtain_lease do + Projects::ContainerRepository::DestroyService.new(project, current_user).execute(container_repository) + end + end + + # For ExclusiveLeaseGuard concern + def lease_key + @lease_key ||= "container_repository:delete:#{container_repository.id}" + end + + # For ExclusiveLeaseGuard concern + def lease_timeout + LEASE_TIMEOUT + end +end diff --git a/changelogs/unreleased/21371-avatar-fix.yml b/changelogs/unreleased/21371-avatar-fix.yml new file mode 100644 index 00000000000..6e00a4ba360 --- /dev/null +++ b/changelogs/unreleased/21371-avatar-fix.yml @@ -0,0 +1,5 @@ +--- +title: "Vertically centres landscape avatars." +merge_request: 21371 +author: Vicary Archangel +type: fixed diff --git a/changelogs/unreleased/2934-create-new-project-re-add-project-name-field.yml b/changelogs/unreleased/2934-create-new-project-re-add-project-name-field.yml new file mode 100644 index 00000000000..ad9136b69c2 --- /dev/null +++ b/changelogs/unreleased/2934-create-new-project-re-add-project-name-field.yml @@ -0,0 +1,5 @@ +--- +title: Re-add project name field on "Create new project" page +merge_request: 21386 +author: +type: other diff --git a/changelogs/unreleased/38208-due-dates-system-notes.yml b/changelogs/unreleased/38208-due-dates-system-notes.yml new file mode 100644 index 00000000000..60e09ff64de --- /dev/null +++ b/changelogs/unreleased/38208-due-dates-system-notes.yml @@ -0,0 +1,5 @@ +--- +title: Add system note when due date is changed +merge_request: +author: Eva Kadlecova +type: added diff --git a/changelogs/unreleased/48167-fix-outdated-discussions-new-datastructure.yml b/changelogs/unreleased/48167-fix-outdated-discussions-new-datastructure.yml new file mode 100644 index 00000000000..a8fcce2eeb8 --- /dev/null +++ b/changelogs/unreleased/48167-fix-outdated-discussions-new-datastructure.yml @@ -0,0 +1,5 @@ +--- +title: Fix outdated discussions being shown on Merge Request Changes tab +merge_request: 21543 +author: +type: fixed diff --git a/changelogs/unreleased/48902-fix-diff-vertical-alignment.yml b/changelogs/unreleased/48902-fix-diff-vertical-alignment.yml new file mode 100644 index 00000000000..75018d57e5b --- /dev/null +++ b/changelogs/unreleased/48902-fix-diff-vertical-alignment.yml @@ -0,0 +1,5 @@ +--- +title: Fix vertical alignment of text in diffs +merge_request: 21573 +author: +type: fixed diff --git a/changelogs/unreleased/51281-on-master-diff-view-contains-extra-and-signs.yml b/changelogs/unreleased/51281-on-master-diff-view-contains-extra-and-signs.yml new file mode 100644 index 00000000000..2ca74b4bc48 --- /dev/null +++ b/changelogs/unreleased/51281-on-master-diff-view-contains-extra-and-signs.yml @@ -0,0 +1,5 @@ +--- +title: Fixes double +/- on inline diff view +merge_request: 21634 +author: +type: fixed diff --git a/changelogs/unreleased/api-promote-find-branch.yml b/changelogs/unreleased/api-promote-find-branch.yml new file mode 100644 index 00000000000..cfa767809b2 --- /dev/null +++ b/changelogs/unreleased/api-promote-find-branch.yml @@ -0,0 +1,5 @@ +--- +title: 'API: Use find_branch! in all places' +merge_request: 21614 +author: Robert Schilling +type: fixed diff --git a/changelogs/unreleased/da-synchronize-the-default-branch-when-updating-a-remote-mirror.yml b/changelogs/unreleased/da-synchronize-the-default-branch-when-updating-a-remote-mirror.yml new file mode 100644 index 00000000000..723aa3eee8a --- /dev/null +++ b/changelogs/unreleased/da-synchronize-the-default-branch-when-updating-a-remote-mirror.yml @@ -0,0 +1,5 @@ +--- +title: Synchronize the default branch when updating a remote mirror +merge_request: 21653 +author: +type: fixed diff --git a/changelogs/unreleased/frozen-string-enable-app-helpers.yml b/changelogs/unreleased/frozen-string-enable-app-helpers.yml new file mode 100644 index 00000000000..7f6805ccb5a --- /dev/null +++ b/changelogs/unreleased/frozen-string-enable-app-helpers.yml @@ -0,0 +1,5 @@ +--- +title: Enable frozen string for app/helpers/**/*.rb +merge_request: +author: gfyoung +type: performance diff --git a/changelogs/unreleased/lock-unlock-quick-actions.yml b/changelogs/unreleased/lock-unlock-quick-actions.yml new file mode 100644 index 00000000000..9322d60ba52 --- /dev/null +++ b/changelogs/unreleased/lock-unlock-quick-actions.yml @@ -0,0 +1,5 @@ +--- +title: Add /lock and /unlock quick actions +merge_request: 15197 +author: Mehdi Lahmam (@mehlah) +type: added diff --git a/changelogs/unreleased/sh-delete-container-registry-async.yml b/changelogs/unreleased/sh-delete-container-registry-async.yml new file mode 100644 index 00000000000..dfe0e812112 --- /dev/null +++ b/changelogs/unreleased/sh-delete-container-registry-async.yml @@ -0,0 +1,5 @@ +--- +title: Delete a container registry asynchronously +merge_request: 21553 +author: +type: fixed diff --git a/changelogs/unreleased/sh-upgrade-katex-0-9-0.yml b/changelogs/unreleased/sh-upgrade-katex-0-9-0.yml new file mode 100644 index 00000000000..2a27e37c053 --- /dev/null +++ b/changelogs/unreleased/sh-upgrade-katex-0-9-0.yml @@ -0,0 +1,5 @@ +--- +title: Bump KaTeX version to 0.9.0 +merge_request: 21625 +author: +type: fixed diff --git a/config/sidekiq_queues.yml b/config/sidekiq_queues.yml index dc49403aca1..0e723cdeb9c 100644 --- a/config/sidekiq_queues.yml +++ b/config/sidekiq_queues.yml @@ -46,6 +46,7 @@ - [project_service, 1] - [delete_user, 1] - [todos_destroyer, 1] + - [delete_container_repository, 1] - [delete_merged_branches, 1] - [authorized_projects, 1] - [expire_build_instance_artifacts, 1] diff --git a/danger/commit_messages/Dangerfile b/danger/commit_messages/Dangerfile new file mode 100644 index 00000000000..0341429d3cc --- /dev/null +++ b/danger/commit_messages/Dangerfile @@ -0,0 +1,192 @@ +# frozen_string_literal: true + +# rubocop: disable Style/SignalException +# rubocop: disable Metrics/CyclomaticComplexity +# rubocop: disable Metrics/PerceivedComplexity + +# Perform various checks against commits. We're not using +# https://github.com/jonallured/danger-commit_lint because its output is not +# very helpful, and it doesn't offer the means of ignoring merge commits. + +def fail_commit(commit, message) + fail("#{commit.sha}: #{message}") +end + +def lines_changed_in_commit(commit) + commit.diff_parent.stats[:total][:lines] +end + +def subject_starts_with_capital?(subject) + first_char = subject.chars.first + + first_char.upcase == first_char +end + +def ce_upstream? + gitlab.mr_labels.any? { |label| label == 'CE upstream' } +end + +def lint_commits(commits) + failures = false + + unicode_emoji_regex = %r(( + [\u{1F300}-\u{1F5FF}] | + [\u{1F1E6}-\u{1F1FF}] | + [\u{2700}-\u{27BF}] | + [\u{1F900}-\u{1F9FF}] | + [\u{1F600}-\u{1F64F}] | + [\u{1F680}-\u{1F6FF}] | + [\u{2600}-\u{26FF}] + ))x + + commits.each do |commit| + # For now we'll ignore merge commits, as getting rid of those is a problem + # separate from enforcing good commit messages. + next if commit.message.start_with?('Merge branch') + + subject, separator, details = commit.message.split("\n", 3) + + if subject.split.length < 3 + fail_commit( + commit, + 'The commit subject must contain at least three words' + ) + + failures = true + end + + if subject.length > 50 + fail_commit( + commit, + 'The commit subject may not be longer than 50 characters' + ) + + failures = true + end + + unless subject_starts_with_capital?(subject) + fail_commit(commit, 'The commit subject must start with a capital letter') + failures = true + end + + if subject.end_with?('.') + fail_commit(commit, 'The commit subject must not end with a period') + failures = true + end + + if separator && !separator.empty? + fail_commit( + commit, + 'The commit subject and body must be separated by a blank line' + ) + + failures = true + end + + details&.each_line do |line| + line = line.strip + + next if line.length <= 72 + + url_size = line.scan(%r((https?://\S+))).sum { |(url)| url.length } + + # If the line includes a URL, we'll allow it to exceed 72 characters, but + # only if the line _without_ the URL does not exceed this limit. + next if line.length - url_size <= 72 + + fail_commit( + commit, + 'The commit body should not contain more than 72 characters per line' + ) + + failures = true + end + + if !details && lines_changed_in_commit(commit) >= 20 + fail_commit( + commit, + 'Commits that change more than 20 lines ' \ + 'must describe these changes in the commit body' + ) + + failures = true + end + + if commit.message.match?(/:[\+a-z0-9_\-]+:/) + fail_commit( + commit, + 'Avoid the use of Markdown Emoji such as `:+1:`. ' \ + 'These add no value to the commit message, ' \ + 'and are displayed as plain text outside of GitLab' + ) + + failures = true + end + + if commit.message.match?(unicode_emoji_regex) + fail_commit( + commit, + 'Avoid the use of Unicode Emoji. ' \ + 'These add no value to the commit message, ' \ + 'and may not be displayed properly everywhere' + ) + + failures = true + end + + if commit.message.match?(%r(([\w\-\/]+)?(#|!|&|%)\d+)) + fail_commit( + commit, + 'Use full URLs instead of short references ' \ + '(`gitlab-org/gitlab-ce#123` or `!123`), as short references are ' \ + 'displayed as plain text outside of GitLab' + ) + + failures = true + end + end + + if failures + markdown(<<~MARKDOWN) + ## Commit message standards + + One or more commit messages do not meet our Git commit message standards. + For more information on how to write a good commit message, take a look at + [How to Write a Git Commit Message](https://chris.beams.io/posts/git-commit/). + + Here is an example of a good commit message: + + Reject ruby interpolation in externalized strings + + When using ruby interpolation in externalized strings, they can't be + detected. Which means they will never be presented to be translated. + + To mix variables into translations we need to use `sprintf` + instead. + + Instead of: + + _("Hello \#{subject}") + + Use: + + _("Hello %{subject}) % { subject: 'world' } + + This is an example of a bad commit message: + + updated README.md + + This commit message is bad because although it tells us that README.md is + updated, it doesn't tell us why or how it was updated. + MARKDOWN + end +end + +if git.commits.length > 10 && !ce_upstream? + warn( + 'This merge request includes more than 10 commits. ' \ + 'Please rebase these commits into a smaller number of commits.' + ) +else + lint_commits(git.commits) +end diff --git a/danger/documentation/Dangerfile b/danger/documentation/Dangerfile new file mode 100644 index 00000000000..d65bec123a9 --- /dev/null +++ b/danger/documentation/Dangerfile @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +# All the files/directories that should be reviewed by the Docs team. +DOCS_FILES = [ + 'doc/' +].freeze + +def docs_paths_requiring_review(files) + files.select do |file| + DOCS_FILES.any? { |pattern| file.start_with?(pattern) } + end +end + +all_files = git.added_files + git.modified_files + +docs_paths_to_review = docs_paths_requiring_review(all_files) + +unless docs_paths_to_review.empty? + message 'This merge request adds or changes files that require a ' \ + 'review from the docs team.' + + markdown(<<~MARKDOWN) +## Docs Review + +The following files require a review from the Documentation team: + +* #{docs_paths_to_review.map { |path| "`#{path}`" }.join("\n* ")} + +To make sure these changes are reviewed, mention `@gl-docsteam` in a separate +comment, and explain what needs to be reviewed by the team. Please don't mention +the team until your changes are ready for review. + MARKDOWN + + unless gitlab.mr_labels.include?('Documentation') + warn 'This merge request is missing the ~Documentation label.' + end +end diff --git a/db/importers/common_metrics_importer.rb b/db/importers/common_metrics_importer.rb index 3a150e8fc5f..01fbbd6866b 100644 --- a/db/importers/common_metrics_importer.rb +++ b/db/importers/common_metrics_importer.rb @@ -40,6 +40,8 @@ module Importers end def execute + PrometheusMetric.reset_column_information + process_content do |id, attributes| find_or_build_metric!(id) .update!(**attributes) diff --git a/doc/api/jobs.md b/doc/api/jobs.md index 5f9556726d1..cf292adf150 100644 --- a/doc/api/jobs.md +++ b/doc/api/jobs.md @@ -33,7 +33,9 @@ Example of response }, "coverage": null, "created_at": "2015-12-24T15:51:21.727Z", + "started_at": "2015-12-24T17:54:24.729Z", "finished_at": "2015-12-24T17:54:24.921Z", + "duration": 0.192, "artifacts_expire_at": "2016-01-23T17:54:24.921Z", "id": 6, "name": "rspec:other", @@ -47,7 +49,6 @@ Example of response "artifacts": [], "runner": null, "stage": "test", - "started_at": "2015-12-24T17:54:24.729Z", "status": "failed", "tag": false, "web_url": "https://example.com/foo/bar/-/jobs/6", @@ -78,6 +79,9 @@ Example of response }, "coverage": null, "created_at": "2015-12-24T15:51:21.802Z", + "started_at": "2015-12-24T17:54:27.722Z", + "finished_at": "2015-12-24T17:54:27.895Z", + "duration": 0.173, "artifacts_file": { "filename": "artifacts.zip", "size": 1000 @@ -88,7 +92,6 @@ Example of response {"file_type": "trace", "size": 1500, "filename": "job.log", "file_format": "raw"}, {"file_type": "junit", "size": 750, "filename": "junit.xml.gz", "file_format": "gzip"} ], - "finished_at": "2015-12-24T17:54:27.895Z", "artifacts_expire_at": "2016-01-23T17:54:27.895Z", "id": 7, "name": "teaspoon", @@ -102,7 +105,6 @@ Example of response "artifacts": [], "runner": null, "stage": "test", - "started_at": "2015-12-24T17:54:27.722Z", "status": "failed", "tag": false, "web_url": "https://example.com/foo/bar/-/jobs/7", @@ -158,7 +160,9 @@ Example of response }, "coverage": null, "created_at": "2015-12-24T15:51:21.727Z", + "started_at": "2015-12-24T17:54:24.729Z", "finished_at": "2015-12-24T17:54:24.921Z", + "duration": 0.192, "artifacts_expire_at": "2016-01-23T17:54:24.921Z", "id": 6, "name": "rspec:other", @@ -172,7 +176,6 @@ Example of response "artifacts": [], "runner": null, "stage": "test", - "started_at": "2015-12-24T17:54:24.729Z", "status": "failed", "tag": false, "web_url": "https://example.com/foo/bar/-/jobs/6", @@ -203,6 +206,9 @@ Example of response }, "coverage": null, "created_at": "2015-12-24T15:51:21.802Z", + "started_at": "2015-12-24T17:54:27.722Z", + "finished_at": "2015-12-24T17:54:27.895Z", + "duration": 0.173, "artifacts_file": { "filename": "artifacts.zip", "size": 1000 @@ -213,7 +219,6 @@ Example of response {"file_type": "trace", "size": 1500, "filename": "job.log", "file_format": "raw"}, {"file_type": "junit", "size": 750, "filename": "junit.xml.gz", "file_format": "gzip"} ], - "finished_at": "2015-12-24T17:54:27.895Z", "artifacts_expire_at": "2016-01-23T17:54:27.895Z", "id": 7, "name": "teaspoon", @@ -227,7 +232,6 @@ Example of response "artifacts": [], "runner": null, "stage": "test", - "started_at": "2015-12-24T17:54:27.722Z", "status": "failed", "tag": false, "web_url": "https://example.com/foo/bar/-/jobs/7", @@ -281,7 +285,9 @@ Example of response }, "coverage": null, "created_at": "2015-12-24T15:51:21.880Z", + "started_at": "2015-12-24T17:54:30.733Z", "finished_at": "2015-12-24T17:54:31.198Z", + "duration": 0.465, "artifacts_expire_at": "2016-01-23T17:54:31.198Z", "id": 8, "name": "rubocop", @@ -295,7 +301,6 @@ Example of response "artifacts": [], "runner": null, "stage": "test", - "started_at": "2015-12-24T17:54:30.733Z", "status": "failed", "tag": false, "web_url": "https://example.com/foo/bar/-/jobs/8", @@ -319,7 +324,7 @@ Example of response ## Get job artifacts > **Notes**: -> +> > - [Introduced][ce-2893] in GitLab 8.5. Get job artifacts of a project. @@ -351,7 +356,7 @@ Response: ## Download the artifacts archive > **Notes**: -> +> > - [Introduced][ce-5347] in GitLab 8.10. Download the artifacts archive from the given reference name and job provided the @@ -474,14 +479,15 @@ Example of response }, "coverage": null, "created_at": "2016-01-11T10:13:33.506Z", - "finished_at": "2016-01-11T10:14:09.526Z", + "started_at": "2016-01-11T10:14:09.526Z", + "finished_at": null, + "duration": 8, "id": 42, "name": "rubocop", "ref": "master", "artifacts": [], "runner": null, "stage": "test", - "started_at": null, "status": "canceled", "tag": false, "web_url": "https://example.com/foo/bar/-/jobs/42", @@ -521,14 +527,15 @@ Example of response }, "coverage": null, "created_at": "2016-01-11T10:13:33.506Z", + "started_at": null, "finished_at": null, + "duration": null, "id": 42, "name": "rubocop", "ref": "master", "artifacts": [], "runner": null, "stage": "test", - "started_at": null, "status": "pending", "tag": false, "web_url": "https://example.com/foo/bar/-/jobs/42", @@ -581,6 +588,7 @@ Example of response "created_at": "2016-01-11T10:13:33.506Z", "started_at": "2016-01-11T10:13:33.506Z", "finished_at": "2016-01-11T10:15:10.506Z", + "duration": 97.0, "status": "failed", "tag": false, "web_url": "https://example.com/foo/bar/-/jobs/42", @@ -633,6 +641,7 @@ Example response: "created_at": "2016-01-11T10:13:33.506Z", "started_at": "2016-01-11T10:13:33.506Z", "finished_at": "2016-01-11T10:15:10.506Z", + "duration": 97.0, "status": "failed", "tag": false, "web_url": "https://example.com/foo/bar/-/jobs/42", @@ -672,14 +681,15 @@ Example of response }, "coverage": null, "created_at": "2016-01-11T10:13:33.506Z", + "started_at": null, "finished_at": null, + "duration": null, "id": 42, "name": "rubocop", "ref": "master", "artifacts": [], "runner": null, "stage": "test", - "started_at": null, "status": "started", "tag": false, "web_url": "https://example.com/foo/bar/-/jobs/42", diff --git a/doc/ci/caching/index.md b/doc/ci/caching/index.md index 01e95b54fc4..b41101695f6 100644 --- a/doc/ci/caching/index.md +++ b/doc/ci/caching/index.md @@ -24,14 +24,14 @@ Don't mix the caching with passing artifacts between stages. Caching is not designed to pass artifacts between stages. Cache is for runtime dependencies needed to compile the project: -- `cache` - **Use for temporary storage for project dependencies.** Not useful +- `cache`: **Use for temporary storage for project dependencies.** Not useful for keeping intermediate build results, like `jar` or `apk` files. Cache was designed to be used to speed up invocations of subsequent runs of a given job, by keeping things like dependencies (e.g., npm packages, Go vendor packages, etc.) so they don't have to be re-fetched from the public internet. While the cache can be abused to pass intermediate build results between stages, there may be cases where artifacts are a better fit. -- `artifacts` - **Use for stage results that will be passed between stages.** +- `artifacts`: **Use for stage results that will be passed between stages.** Artifacts were designed to upload some compiled/generated bits of the build, and they can be fetched by any number of concurrent Runners. They are guaranteed to be available and are there to pass data between jobs. They are @@ -57,19 +57,20 @@ control exactly where artifacts are passed around. In summary: -- Caches are disabled if not defined globally or per job (using `cache:`) -- Caches are available for all jobs in your `.gitlab-ci.yml` if enabled globally +- Caches are disabled if not defined globally or per job (using `cache:`). +- Caches are available for all jobs in your `.gitlab-ci.yml` if enabled globally. - Caches can be used by subsequent pipelines of that very same job (a script in a stage) in which the cache was created (if not defined globally). - Caches are stored where the Runner is installed **and** uploaded to S3 if - [distributed cache is enabled](https://docs.gitlab.com/runner/configuration/autoscale.html#distributed-runners-caching) -- Caches defined per job are only used either a) for the next pipeline of that job, - or b) if that same cache is also defined in a subsequent job of the same pipeline -- Artifacts are disabled if not defined per job (using `artifacts:`) -- Artifacts can only be enabled per job, not globally + [distributed cache is enabled](https://docs.gitlab.com/runner/configuration/autoscale.html#distributed-runners-caching). +- Caches defined per job are only used, either: + - For the next pipeline of that job. + - If that same cache is also defined in a subsequent job of the same pipeline. +- Artifacts are disabled if not defined per job (using `artifacts:`). +- Artifacts can only be enabled per job, not globally. - Artifacts are created during a pipeline and can be used by the subsequent - jobs of that currently active pipeline -- Artifacts are always uploaded to GitLab (known as coordinator) + jobs of that currently active pipeline. +- Artifacts are always uploaded to GitLab (known as coordinator). - Artifacts can have an expiration value for controlling disk usage (30 days by default). ## Good caching practices @@ -97,13 +98,13 @@ or pipelines in a guaranteed manner. From the perspective of the Runner, in order for cache to work effectively, one of the following must be true: -- Use a single Runner for all your jobs -- Use multiple Runners (in autoscale mode or not) that use +- Use a single Runner for all your jobs. +- Use multiple Runners (in autoscale mode or not) that use. [distributed caching](https://docs.gitlab.com/runner/configuration/autoscale.html#distributed-runners-caching), - where the cache is stored in S3 buckets (like shared Runners on GitLab.com) + where the cache is stored in S3 buckets (like shared Runners on GitLab.com). - Use multiple Runners (not in autoscale mode) of the same architecture that share a common network-mounted directory (using NFS or something similar) - where the cache will be stored + where the cache will be stored. TIP: **Tip:** Read about the [availability of the cache](#availability-of-the-cache) @@ -367,19 +368,19 @@ job B: Here's what happens behind the scenes: -1. Pipeline starts -1. `job A` runs -1. `before_script` is executed -1. `script` is executed -1. `after_script` is executed +1. Pipeline starts. +1. `job A` runs. +1. `before_script` is executed. +1. `script` is executed. +1. `after_script` is executed. 1. `cache` runs and the `vendor/` directory is zipped into `cache.zip`. This file is then saved in the directory based on the [Runner's setting](#where-the-caches-are-stored) and the `cache: key`. -1. `job B` runs -1. The cache is extracted (if found) -1. `before_script` is executed -1. `script` is executed -1. Pipeline finishes +1. `job B` runs. +1. The cache is extracted (if found). +1. `before_script` is executed. +1. `script` is executed. +1. Pipeline finishes. By using a single Runner on a single machine, you'll not have the issue where `job B` might execute on a Runner different from `job A`, thus guaranteeing the @@ -451,13 +452,13 @@ job B: - vendor/ ``` -1. `job A` runs -1. `public/` is cached as cache.zip -1. `job B` runs -1. The previous cache, if any, is unzipped -1. `vendor/` is cached as cache.zip and overwrites the previous one +1. `job A` runs. +1. `public/` is cached as cache.zip. +1. `job B` runs. +1. The previous cache, if any, is unzipped. +1. `vendor/` is cached as cache.zip and overwrites the previous one. 1. The next time `job A` runs it will use the cache of `job B` which is different - and thus will be ineffective + and thus will be ineffective. To fix that, use different `keys` for each job. @@ -514,12 +515,12 @@ next run of the pipeline, the cache will be stored in a different location. If you want to avoid editing `.gitlab-ci.yml`, you can easily clear the cache via GitLab's UI: -1. Navigate to your project's **CI/CD > Pipelines** page -1. Click on the **Clear Runner caches** button to clean up the cache +1. Navigate to your project's **CI/CD > Pipelines** page. +1. Click on the **Clear Runner caches** button to clean up the cache. ![Clear Runners cache](img/clear_runners_cache.png) -1. On the next push, your CI/CD job will use a new cache +1. On the next push, your CI/CD job will use a new cache. Behind the scenes, this works by increasing a counter in the database, and the value of that counter is used to create the key for the cache by appending an diff --git a/doc/ci/docker/using_docker_build.md b/doc/ci/docker/using_docker_build.md index 54a8cfe7fd8..aa997d15b64 100644 --- a/doc/ci/docker/using_docker_build.md +++ b/doc/ci/docker/using_docker_build.md @@ -151,16 +151,16 @@ In order to do that, follow the steps: DOCKER_DRIVER: overlay2 services: - - docker:dind + - docker:dind before_script: - - docker info + - docker info build: stage: build script: - - docker build -t my-docker-image . - - docker run my-docker-image /script/to/run/tests + - docker build -t my-docker-image . + - docker run my-docker-image /script/to/run/tests ``` Docker-in-Docker works well, and is the recommended configuration, but it is @@ -246,13 +246,13 @@ In order to do that, follow the steps: image: docker:stable before_script: - - docker info + - docker info build: stage: build script: - - docker build -t my-docker-image . - - docker run my-docker-image /script/to/run/tests + - docker build -t my-docker-image . + - docker run my-docker-image /script/to/run/tests ``` While the above method avoids using Docker in privileged mode, you should be @@ -403,7 +403,7 @@ could look like: build: image: docker:stable services: - - docker:dind + - docker:dind variables: DOCKER_HOST: tcp://docker:2375 DOCKER_DRIVER: overlay2 @@ -456,13 +456,13 @@ an application-specific deploy script: ```yaml image: docker:stable services: -- docker:dind + - docker:dind stages: -- build -- test -- release -- deploy + - build + - test + - release + - deploy variables: DOCKER_HOST: tcp://docker:2375 diff --git a/doc/ci/interactive_web_terminal/index.md b/doc/ci/interactive_web_terminal/index.md index 507aceb27fa..8ce4fe55cec 100644 --- a/doc/ci/interactive_web_terminal/index.md +++ b/doc/ci/interactive_web_terminal/index.md @@ -1,10 +1,6 @@ # Getting started with interactive web terminals -> Introduced in GitLab 11.3. - -CAUTION: **Warning:** -Interactive web terminals are in beta, so they might not work properly and -lack features. For more information [follow issue #25990](https://gitlab.com/gitlab-org/gitlab-ce/issues/25990). +> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/50144) in GitLab 11.3. Interactive web terminals give the user access to a terminal in GitLab for running one-of commands for their CI pipeline. diff --git a/doc/ci/pipelines.md b/doc/ci/pipelines.md index 4e964af97f5..ea47d676edb 100644 --- a/doc/ci/pipelines.md +++ b/doc/ci/pipelines.md @@ -9,7 +9,7 @@ you may need to enable pipeline triggering in your project's ## Pipelines -A pipeline is a group of [jobs][] that get executed in [stages][](batches). +A pipeline is a group of [jobs] that get executed in [stages]. All of the jobs in a stage are executed in parallel (if there are enough concurrent [Runners]), and if they all succeed, the pipeline moves on to the next stage. If one of the jobs fails, the next stage is not (usually) @@ -29,17 +29,17 @@ There are three types of pipelines that often use the single shorthand of "pipel ![Types of Pipelines](img/types-of-pipelines.svg) -1. **CI Pipeline**: Build and test stages defined in `.gitlab-ci.yml` -2. **Deploy Pipeline**: Deploy stage(s) defined in `.gitlab-ci.yml` The flow of deploying code to servers through various stages: e.g. development to staging to production -3. **Project Pipeline**: Cross-project CI dependencies [triggered via API][triggers], particularly for micro-services, but also for complicated build dependencies: e.g. api -> front-end, ce/ee -> omnibus. +1. **CI Pipeline**: Build and test stages defined in `.gitlab-ci.yml`. +1. **Deploy Pipeline**: Deploy stage(s) defined in `.gitlab-ci.yml` The flow of deploying code to servers through various stages: e.g. development to staging to production. +1. **Project Pipeline**: Cross-project CI dependencies [triggered via API][triggers], particularly for micro-services, but also for complicated build dependencies: e.g. api -> front-end, ce/ee -> omnibus. ## Development workflows Pipelines accommodate several development workflows: -1. **Branch Flow** (e.g. different branch for dev, qa, staging, production) -2. **Trunk-based Flow** (e.g. feature branches and single master branch, possibly with tags for releases) -3. **Fork-based Flow** (e.g. merge requests come from forks) +1. **Branch Flow** (e.g. different branch for dev, qa, staging, production). +1. **Trunk-based Flow** (e.g. feature branches and single master branch, possibly with tags for releases). +1. **Fork-based Flow** (e.g. merge requests come from forks). Example continuous delivery flow: @@ -57,6 +57,16 @@ Pipelines are defined in `.gitlab-ci.yml` by specifying [jobs] that run in See the reference [documentation for jobs](yaml/README.md#jobs). +## Manually executing pipelines + +Pipelines can be manually executed, with predefined or manually-specified [variables](variables/README.md). + +To execute a pipeline manually: + +1. Navigate to your project's **CI/CD > Pipelines**. +1. Click on the **Run Pipeline** button. +1. Select the branch to run the pipeline for and enter any environment variables required for the pipeline run. + ## Seeing pipeline status You can find the current and historical pipeline runs under your project's @@ -112,9 +122,9 @@ Then, there is the pipeline mini graph which takes less space and can give you a quick glance if all jobs pass or something failed. The pipeline mini graph can be found when you visit: -- the pipelines index page -- a single commit page -- a merge request page +- The pipelines index page. +- A single commit page. +- A merge request page. That way, you can see all related jobs for a single commit and the net result of each stage of your pipeline. This allows you to quickly see what failed and @@ -142,9 +152,9 @@ jobs. Click to expand them. The basic requirements is that there are two numbers separated with one of the following (you can even use them interchangeably): -- a space -- a slash (`/`) -- a colon (`:`) +- A space (` `) +- A slash (`/`) +- A colon (`:`) >**Note:** More specifically, [it uses][regexp] this regular expression: `\d+[\s:\/\\]+\d+\s*`. @@ -252,11 +262,12 @@ A strict security model is enforced when pipelines are executed on The following actions are allowed on protected branches only if the user is [allowed to merge or push](../user/project/protected_branches.md#using-the-allowed-to-merge-and-allowed-to-push-settings) on that specific branch: -- run **manual pipelines** (using Web UI or Pipelines API) -- run **scheduled pipelines** -- run pipelines using **triggers** -- trigger **manual actions** on existing pipelines -- **retry/cancel** existing jobs (using Web UI or Pipelines API) + +- Run **manual pipelines** (using [Web UI](#manually-executing-pipelines) or Pipelines API). +- Run **scheduled pipelines**. +- Run pipelines using **triggers**. +- Trigger **manual actions** on existing pipelines. +- **Retry/cancel** existing jobs (using Web UI or Pipelines API). **Variables** marked as **protected** are accessible only to jobs that run on protected branches, avoiding untrusted users to get unintended access to diff --git a/doc/ci/variables/README.md b/doc/ci/variables/README.md index 115e6e390c9..f11949da64e 100644 --- a/doc/ci/variables/README.md +++ b/doc/ci/variables/README.md @@ -34,7 +34,7 @@ Some of the predefined environment variables are available only if a minimum version of [GitLab Runner][runner] is used. Consult the table below to find the version of Runner required. ->**Note:** +NOTE: **Note:** Starting with GitLab 9.0, we have deprecated some variables. Read the [9.0 Renaming](#9-0-renaming) section to find out their replacements. **You are strongly advised to use the new variables as we will remove the old ones in @@ -109,7 +109,7 @@ To follow conventions of naming across GitLab, and to further move away from the `build` term and toward `job` CI variables have been renamed for the 9.0 release. ->**Note:** +NOTE: **Note:** Starting with GitLab 9.0, we have deprecated the `$CI_BUILD_*` variables. **You are strongly advised to use the new variables as we will remove the old ones in future GitLab releases.** @@ -131,7 +131,7 @@ future GitLab releases.** ## `.gitlab-ci.yml` defined variables ->**Note:** +NOTE **Note:** This feature requires GitLab Runner 0.5.0 or higher and GitLab CI 7.14 or higher. GitLab CI allows you to add to `.gitlab-ci.yml` variables that are set in the @@ -215,9 +215,15 @@ Protected variables can be added by going to your project's Once you set them, they will be available for all subsequent pipelines. +### Manually-specified variables + +> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/44059) in GitLab 10.8. + +Variables can be specified for a single pipeline run when a [manual pipeline](../pipelines.md#manually-executing-pipelines) is created. + ## Deployment variables ->**Note:** +NOTE: **Note:** This feature requires GitLab CI 8.15 or higher. [Project services](../../user/project/integrations/project_services.md) that are @@ -567,4 +573,4 @@ Below you can find supported syntax reference: [builds-policies]: ../yaml/README.md#only-and-except-complex [gitlab-deploy-token]: ../../user/project/deploy_tokens/index.md#gitlab-deploy-token [registry]: ../../user/project/container_registry.md -[dependent-repositories]: ../../user/project/new_ci_build_permissions_model.md#dependent-repositories
\ No newline at end of file +[dependent-repositories]: ../../user/project/new_ci_build_permissions_model.md#dependent-repositories diff --git a/doc/ci/variables/where_variables_can_be_used.md b/doc/ci/variables/where_variables_can_be_used.md index b2b4a26bdda..b0d2ea6484d 100644 --- a/doc/ci/variables/where_variables_can_be_used.md +++ b/doc/ci/variables/where_variables_can_be_used.md @@ -8,10 +8,10 @@ This document describes where and how the different types of variables can be us ## Variables usage -There are basically two places where you can use any defined variables: +There are two places defined variables can be used. On the: -1. On GitLab's side there's `.gitlab-ci.yml` -1. On the Runner's side there's `config.toml` +1. GitLab side, in `.gitlab-ci.yml`. +1. The runner side, in `config.toml`. ### `.gitlab-ci.yml` file @@ -56,8 +56,8 @@ since the expansion is done in GitLab before any Runner will get the job. ### GitLab Runner internal variable expansion mechanism - **Supported:** project/group variables, `.gitlab-ci.yml` variables, `config.toml` variables, and - variables from triggers and pipeline schedules -- **Not supported:** variables defined inside of scripts (e.g., `export MY_VARIABLE="test"`) + variables from triggers, pipeline schedules, and manual pipelines. +- **Not supported:** variables defined inside of scripts (e.g., `export MY_VARIABLE="test"`). The Runner uses Go's `os.Expand()` method for variable expansion. It means that it will handle only variables defined as `$variable` and `${variable}`. What's also important, is that @@ -80,11 +80,10 @@ are using a different variables syntax. `.gitlab-ci.yml` variables, `config.toml` variables, and variables from triggers and pipeline schedules). - The `script` may also use all variables defined in the lines before. So, for example, if you define a variable `export MY_VARIABLE="test"`: - - - in `before_script`, it will work in the following lines of `before_script` and - all lines of the related `script` - - in `script`, it will work in the following lines of `script` - - in `after_script`, it will work in following lines of `after_script` + - In `before_script`, it will work in the following lines of `before_script` and + all lines of the related `script`. + - In `script`, it will work in the following lines of `script`. + - In `after_script`, it will work in following lines of `after_script`. ## Persisted variables @@ -107,7 +106,7 @@ The following variables are known as "persisted": They are: -- **supported** for all definitions as [described in the table](#gitlab-ci-yml-file) where the "Expansion place" is "Runner" -- **not supported:** - - by the definitions [described in the table](#gitlab-ci-yml-file) where the "Expansion place" is "GitLab" - - in the `only` and `except` [variables expressions](README.md#variables-expressions) +- **Supported** for all definitions as [described in the table](#gitlab-ci-yml-file) where the "Expansion place" is "Runner". +- **Not supported:** + - By the definitions [described in the table](#gitlab-ci-yml-file) where the "Expansion place" is "GitLab". + - In the `only` and `except` [variables expressions](README.md#variables-expressions). diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md index d89705e8ead..72b90ac6334 100644 --- a/doc/ci/yaml/README.md +++ b/doc/ci/yaml/README.md @@ -1456,7 +1456,9 @@ There are three possible values: `none`, `normal`, and `recursive`: ``` - `recursive` means that all submodules (including submodules of submodules) - will be included. It is equivalent to: + will be included. This feature needs Git v1.8.1 and later. When using a + GitLab Runner with an executor not based on Docker, make sure the Git version + meets that requirement. It is equivalent to: ``` git submodule sync --recursive diff --git a/doc/development/README.md b/doc/development/README.md index e786d6594c7..b37403552fe 100644 --- a/doc/development/README.md +++ b/doc/development/README.md @@ -47,6 +47,7 @@ description: 'Learn how to contribute to GitLab.' - [How to dump production data to staging](db_dump.md) - [Working with the GitHub importer](github_importer.md) - [Working with Merge Request diffs](diffs.md) +- [Permissions](permissions.md) - [Prometheus metrics](prometheus_metrics.md) ## Performance guides diff --git a/doc/development/documentation/index.md b/doc/development/documentation/index.md index f46c171d9f1..7ac211ed550 100644 --- a/doc/development/documentation/index.md +++ b/doc/development/documentation/index.md @@ -257,6 +257,15 @@ choices: If your branch name matches any of the above, it will run only the docs tests. If it doesn't, the whole test suite will run (including docs). +## Danger bot + +GitLab uses [danger bot](https://github.com/danger/danger) for some elements in +code review. For docs changes in merge requests, the following actions are taken: + +1. Whenever a change under `/doc` is made, the bot leaves a comment for the + author to mention `@gl-docsteam`, so that the docs can be properly + reviewed. + ## Merge requests for GitLab documentation Before getting started, make sure you read the introductory section diff --git a/doc/development/documentation/styleguide.md b/doc/development/documentation/styleguide.md index e610c7595a8..8083f219d4a 100644 --- a/doc/development/documentation/styleguide.md +++ b/doc/development/documentation/styleguide.md @@ -13,10 +13,10 @@ Check the GitLab handbook for the [writing styles guidelines](https://about.gitl ## Files - [Directory structure](index.md#location-and-naming-documents): place the docs -in the correct location -- [Documentation files](index.md#documentation-files): name the files accordingly +in the correct location. +- [Documentation files](index.md#documentation-files): name the files accordingly. - [Markdown](../../user/markdown.md): use the GitLab Flavored Markdown in the -documentation +documentation. NOTE: **Note:** **Do not** use capital letters, spaces, or special chars in file names, @@ -30,17 +30,17 @@ a test that will fail if it spots a new `README.md` file. - Split up long lines (wrap text), this makes it much easier to review and edit. Only double line breaks are shown as a full line break in [GitLab markdown][gfm]. - 80-100 characters is a good line length + 80-100 characters is a good line length. - Make sure that the documentation is added in the correct [directory](index.md#documentation-directory-structure) and that - there's a link to it somewhere useful -- Do not duplicate information -- Be brief and clear -- Unless there's a logical reason not to, add documents in alphabetical order -- Write in US English -- Use [single spaces][] instead of double spaces + there's a link to it somewhere useful. +- Do not duplicate information. +- Be brief and clear. +- Unless there's a logical reason not to, add documents in alphabetical order. +- Write in US English. +- Use [single spaces][] instead of double spaces. - Jump a line between different markups (e.g., after every paragraph, header, list, etc) -- Capitalize "G" and "L" in GitLab +- Capitalize "G" and "L" in GitLab. - Use sentence case for titles, headings, labels, menu items, and buttons. - Use title case when referring to [features](https://about.gitlab.com/features/) or [products](https://about.gitlab.com/pricing/) (e.g., GitLab Runner, Geo, @@ -50,10 +50,9 @@ some features are also objects (e.g. "Merge Requests" and "merge requests"). ## Formatting -- Use double asterisks (`**`) to mark a word or text in bold (`**bold**`) -- Use undescore (`_`) for text in italics (`_italic_`) -- Jump a line between different markups, for example: - +- Use double asterisks (`**`) to mark a word or text in bold (`**bold**`). +- Use undescore (`_`) for text in italics (`_italic_`). +- Put an empty line between different markups. For example: ```md ## Header @@ -69,9 +68,16 @@ For punctuation rules, please refer to the [GitLab UX guide](https://design.gitl ### Ordered and unordered lists -- Use dashes (`-`) for unordered lists instead of asterisks (`*`) -- Use the number one (`1`) for ordered lists -- For punctuation in bullet lists, please refer to the [GitLab UX guide](https://design.gitlab.com/content/punctuation/) +- Use dashes (`-`) for unordered lists instead of asterisks (`*`). +- Use the number one (`1`) for ordered lists. +- Separate list items from explanatory text with a colon (`:`). For example: + ```md + The list is as follows: + + - First item: This explains the first item. + - Second item: This explains the second item. + ``` +- For further guidance on punctuation in bullet lists, please refer to the [GitLab UX guide](https://design.gitlab.com/content/punctuation/). ## Headings @@ -82,7 +88,7 @@ For punctuation rules, please refer to the [GitLab UX guide](https://design.gitl - Avoid putting numbers in headings. Numbers shift, hence documentation anchor links shift too, which eventually leads to dead links. If you think it is compelling to add numbers in headings, make sure to at least discuss it with - someone in the Merge Request + someone in the Merge Request. - [Avoid using symbols and special chars](https://gitlab.com/gitlab-com/gitlab-docs/issues/84) in headers. Whenever possible, they should be plain and short text. - Avoid adding things that show ephemeral statuses. For example, if a feature is @@ -92,8 +98,8 @@ For punctuation rules, please refer to the [GitLab UX guide](https://design.gitl of the following GitLab members for a review: `@axil` or `@marcia`. This is to ensure that no document with wrong heading is going live without an audit, thus preventing dead links and redirection issues when - corrected -- Leave exactly one new line after a heading + corrected. +- Leave exactly one new line after a heading. ## Links @@ -120,11 +126,11 @@ For punctuation rules, please refer to the [GitLab UX guide](https://design.gitl To indicate the steps of navigation through the UI: -- Use the exact word as shown in the UI, including any capital letters as-is +- Use the exact word as shown in the UI, including any capital letters as-is. - Use bold text for navigation items and the char `>` as separator -(e.g., `Navigate to your project's **Settings > CI/CD**` ) +(e.g., `Navigate to your project's **Settings > CI/CD**` ). - If there are any expandable menus, make sure to mention that the user -needs to expand the tab to find the settings you're referring to +needs to expand the tab to find the settings you're referring to. ## Images @@ -149,12 +155,12 @@ Inside the document: `![Proper description what the image is about](img/document_image_title.png)` - Always use a proper description for what the image is about. That way, when a browser fails to show the image, this text will be used as an alternative - description + description. - If there are consecutive images with little text between them, always add three dashes (`---`) between the image and the text to create a horizontal - line for better clarity + line for better clarity. - If a heading is placed right after an image, always add three dashes (`---`) - between the image and the heading + between the image and the heading. ## Alert boxes @@ -262,18 +268,18 @@ below. When a feature is available in EE-only tiers, add the corresponding tier according to the feature availability: -- For GitLab Starter and GitLab.com Bronze: `**[STARTER]**` -- For GitLab Premium and GitLab.com Silver: `**[PREMIUM]**` -- For GitLab Ultimate and GitLab.com Gold: `**[ULTIMATE]**` -- For GitLab Core and GitLab.com Free: `**[CORE]**` +- For GitLab Starter and GitLab.com Bronze: `**[STARTER]**`. +- For GitLab Premium and GitLab.com Silver: `**[PREMIUM]**`. +- For GitLab Ultimate and GitLab.com Gold: `**[ULTIMATE]**`. +- For GitLab Core and GitLab.com Free: `**[CORE]**`. To exclude GitLab.com tiers (when the feature is not available in GitLab.com), add the keyword "only": -- For GitLab Starter: `**[STARTER ONLY]**` -- For GitLab Premium: `**[PREMIUM ONLY]**` -- For GitLab Ultimate: `**[ULTIMATE ONLY]**` -- For GitLab Core: `**[CORE ONLY]**` +- For GitLab Starter: `**[STARTER ONLY]**`. +- For GitLab Premium: `**[PREMIUM ONLY]**`. +- For GitLab Ultimate: `**[ULTIMATE ONLY]**`. +- For GitLab Core: `**[CORE ONLY]**`. The tier should be ideally added to headers, so that the full badge will be displayed. But it can be also mentioned from paragraphs, list items, and table cells. For these cases, @@ -328,8 +334,8 @@ prefer to document it in the CE docs to avoid duplication. Configuration settings include: -- settings that touch configuration files in `config/` -- NGINX settings and settings in `lib/support/` in general +- Settings that touch configuration files in `config/`. +- NGINX settings and settings in `lib/support/` in general. When there is a list of steps to perform, usually that entails editing the configuration file and reconfiguring/restarting GitLab. In such case, follow diff --git a/doc/development/performance.md b/doc/development/performance.md index 6b4cb6d72d1..05caffb150a 100644 --- a/doc/development/performance.md +++ b/doc/development/performance.md @@ -43,7 +43,7 @@ GitLab provides built-in tools to aid the process of improving performance: * [QueryRecoder](query_recorder.md) for preventing `N+1` regressions GitLab employees can use GitLab.com's performance monitoring systems located at -<http://performance.gitlab.net>, this requires you to log in using your +<https://dashboards.gitlab.net>, this requires you to log in using your `@gitlab.com` Email address. Non-GitLab employees are advised to set up their own InfluxDB + Grafana stack. diff --git a/doc/development/permissions.md b/doc/development/permissions.md new file mode 100644 index 00000000000..5d409c9461e --- /dev/null +++ b/doc/development/permissions.md @@ -0,0 +1,63 @@ +# GitLab permissions guide + +There are multiple types of permissions across GitLab, and when implementing +anything that deals with permissions, all of them should be considered. + +## Groups and Projects + +### General permissions + +Groups and projects can have the following visibility levels: + +- public (20) - an entity is visible to everyone +- internal (10) - an entity is visible to logged in users +- private (0) - an entity is visible only to the approved members of the entity + +The visibility level of a group can be changed only if all subgroups and +subprojects have the same or lower visibility level. (e.g., a group can be set +to internal only if all subgroups and projects are internal or private). + +Visibility levels can be found in the `Gitlab::VisibilityLevel` module. + +### Feature specific permissions + +Additionally, the following project features can have different visibility levels: + +- Issues +- Repository + - Merge Request + - Pipelines + - Container Registry + - Git Large File Storage +- Wiki +- Snippets + +These features can be set to "Everyone with Access" or "Only Project Members". +They make sense only for public or internal projects because private projects +can be accessed only by project members by default. + +### Members + +Users can be members of multiple groups and projects. The following access +levels are available (defined in the `Gitlab::Access` module): + +- Guest +- Reporter +- Developer +- Maintainer +- Owner + +If a user is the member of both a project and the project parent group, the +higher permission is taken into account for the project. + +If a user is the member of a project, but not the parent group (or groups), they +can still view the groups and their entities (like epics). + +Project membership (where the group membership is already taken into account) +is stored in the `project_authorizations` table. + +### Confidential issues + +Confidential issues can be accessed only by project members who are at least +reporters (they can't be accessed by guests). Additionally they can be accessed +by their authors and assignees. diff --git a/doc/install/kubernetes/index.md b/doc/install/kubernetes/index.md index e67d5ba4d4c..df74d2aeab3 100644 --- a/doc/install/kubernetes/index.md +++ b/doc/install/kubernetes/index.md @@ -4,23 +4,12 @@ description: 'Read through the different methods to deploy GitLab on Kubernetes. # Installing GitLab on Kubernetes -NOTE: **Note**: These charts have been tested on Google Kubernetes Engine. Other -Kubernetes installations may work as well, if not please [open an issue](https://gitlab.com/charts/issues). - The easiest method to deploy GitLab on [Kubernetes](https://kubernetes.io/) is to take advantage of GitLab's Helm charts. [Helm] is a package management tool for Kubernetes, allowing apps to be easily managed via their Charts. A [Chart] is a detailed description of the application including how it should be deployed, upgraded, and configured. -## Chart Overview - -- **[GitLab Chart](gitlab_chart.html)**: Deploys GitLab on Kubernetes. Includes all the required components to get started, and can scale to large deployments. -- **[GitLab Runner Chart](gitlab_runner_chart.md)**: For deploying just the GitLab Runner. -- Other Charts - - [GitLab-Omnibus](gitlab_omnibus.md): Chart based on the Omnibus GitLab package, only suitable for small deployments. Deprecated, we strongly recommend using the [gitlab](#gitlab-chart) chart. - - [Community contributed charts](#community-contributed-charts): Community contributed charts. - ## GitLab Chart This chart contains all the required components to get started, and can scale to @@ -43,13 +32,13 @@ it can be deployed with the GitLab Runner chart. Learn more about [gitlab-runner chart](gitlab_runner_chart.md). -## Other Charts - -### GitLab-Omnibus Chart +## Deprecated Charts CAUTION: **Deprecated:** -This chart is **deprecated**. We recommend using the [GitLab Chart](gitlab_chart.md) -instead. A comparison of the two charts is available in [this video](https://youtu.be/Z6jWR8Z8dv8). +These charts are **deprecated**. We recommend using the [GitLab Chart](gitlab_chart.md) +instead. + +### GitLab-Omnibus Chart This chart is based on the [GitLab Omnibus Docker images](https://docs.gitlab.com/omnibus/docker/). It deploys and configures nearly all features of GitLab, including: @@ -64,7 +53,7 @@ Learn more about the [gitlab-omnibus chart](gitlab_omnibus.md). ### Community Contributed Charts -The community has also contributed GitLab [CE](https://github.com/kubernetes/charts/tree/master/stable/gitlab-ce) and [EE](https://github.com/kubernetes/charts/tree/master/stable/gitlab-ee) charts to the [Helm Stable Repository](https://github.com/kubernetes/charts#repository-structure). These charts should be considered [deprecated](https://github.com/kubernetes/charts/issues/1138) in favor of the [official Charts](gitlab_omnibus.md). +The community has also contributed GitLab [CE](https://github.com/kubernetes/charts/tree/master/stable/gitlab-ce) and [EE](https://github.com/kubernetes/charts/tree/master/stable/gitlab-ee) charts to the [Helm Stable Repository](https://github.com/kubernetes/charts#repository-structure). These charts are [deprecated](https://github.com/kubernetes/charts/issues/1138) in favor of the [official Chart](gitlab_chart.md). [chart]: https://github.com/kubernetes/charts [helm]: https://github.com/kubernetes/helm/blob/master/README.md diff --git a/doc/raketasks/backup_restore.md b/doc/raketasks/backup_restore.md index c2cf0d54aeb..1d29f6d4e43 100644 --- a/doc/raketasks/backup_restore.md +++ b/doc/raketasks/backup_restore.md @@ -16,17 +16,27 @@ and is flexible enough to fit your needs. ### Requirements -If you're using GitLab with the Omnibus package, you're all set. If you -installed GitLab from source, make sure the following packages are installed: - * rsync +If you're using GitLab with the Omnibus package, you're all set. If you +installed GitLab from source, make sure you have rsync installed. + If you're using Ubuntu, you could run: ``` sudo apt-get install -y rsync ``` +* tar + +Backup and restore tasks use `tar` under the hood to create and extract +archives. Ensure you have version 1.30 or above of `tar` available in your +system. To check the version, run: + +``` +tar --version +``` + ### Backup timestamp >**Note:** diff --git a/doc/topics/autodevops/index.md b/doc/topics/autodevops/index.md index c0268ce136c..e778f1d83df 100644 --- a/doc/topics/autodevops/index.md +++ b/doc/topics/autodevops/index.md @@ -238,6 +238,12 @@ There is also a feature flag to enable Auto DevOps to a percentage of projects which can be enabled from the console with `Feature.get(:force_autodevops_on_by_default).enable_percentage_of_actors(10)`. +NOTE: **Enabled by default:** +Starting with GitLab 11.3, the Auto DevOps pipeline will be enabled by default for all +projects. If it's not explicitly enabled for the project, Auto DevOps will be automatically +disabled on the first pipeline failure. Your project will continue to use an alternative +[CI/CD configuration file](../../ci/yaml/README.md) if one is found. + ### Deployment strategy > [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/38542) in GitLab 11.0. diff --git a/doc/user/gitlab_com/index.md b/doc/user/gitlab_com/index.md index de5d7d0a3a0..0b9395914f9 100644 --- a/doc/user/gitlab_com/index.md +++ b/doc/user/gitlab_com/index.md @@ -99,7 +99,7 @@ Below are the shared Runners settings. | Default Docker image | `ruby:2.5` | - | | `privileged` (run [Docker in Docker]) | `true` | `false` | -[ci_version_dashboard]: https://monitor.gitlab.net/dashboard/db/ci?from=now-1h&to=now&refresh=5m&orgId=1&panelId=12&fullscreen&theme=light +[ci_version_dashboard]: https://dashboards.gitlab.com/dashboard/db/ci?from=now-1h&to=now&refresh=5m&orgId=1&panelId=12&fullscreen&theme=light ### `config.toml` diff --git a/doc/user/project/pipelines/settings.md b/doc/user/project/pipelines/settings.md index 14f2e522f01..15eacc48dfe 100644 --- a/doc/user/project/pipelines/settings.md +++ b/doc/user/project/pipelines/settings.md @@ -157,6 +157,10 @@ into your `README.md`: ![coverage](https://gitlab.com/gitlab-org/gitlab-ce/badges/master/coverage.svg?job=coverage) ``` +### Environment Variables + +[Environment variables](../../../ci/variables/README.html#variables) can be set in an environment to be available to a runner. + [var]: ../../../ci/yaml/README.md#git-strategy [coverage report]: #test-coverage-parsing [timeout overriding]: ../../../ci/runners/README.html#setting-maximum-job-timeout-for-a-runner diff --git a/doc/user/project/quick_actions.md b/doc/user/project/quick_actions.md index 8fdfd2a6f4d..9ad9155258f 100644 --- a/doc/user/project/quick_actions.md +++ b/doc/user/project/quick_actions.md @@ -44,3 +44,5 @@ do. | `/shrug` | Append the comment with `¯\_(ツ)_/¯` | | <code>/copy_metadata #issue | !merge_request</code> | Copy labels and milestone from other issue or merge request | | `/confidential` | Makes the issue confidential | +| `/lock` | Lock the discussion | +| `/unlock` | Unlock the discussion | diff --git a/doc/workflow/todos.md b/doc/workflow/todos.md index dda82352c67..f94d592d0db 100644 --- a/doc/workflow/todos.md +++ b/doc/workflow/todos.md @@ -14,7 +14,7 @@ in a simple dashboard. --- -You can quickly access the Todos dashboard using the bell icon next to the +You can quickly access the Todos dashboard using the checkmark icon next to the search bar in the upper right corner. The number in blue is the number of Todos you still have open if the count is < 100, else it's 99+. The exact number will still be shown in the body of the _To do_ tab. diff --git a/lib/api/branches.rb b/lib/api/branches.rb index 3e445e6b1fa..6c1d445e53d 100644 --- a/lib/api/branches.rb +++ b/lib/api/branches.rb @@ -9,14 +9,6 @@ module API before { authorize! :download_code, user_project } helpers do - def find_branch!(branch_name) - begin - user_project.repository.find_branch(branch_name) || not_found!('Branch') - rescue Gitlab::Git::CommandError - render_api_error!('The branch refname is invalid', 400) - end - end - params :filter_params do optional :search, type: String, desc: 'Return list of branches matching the search criteria' optional :sort, type: String, desc: 'Return list of branches sorted by the given field' diff --git a/lib/api/commits.rb b/lib/api/commits.rb index 92329465b2c..3e8de3c8dae 100644 --- a/lib/api/commits.rb +++ b/lib/api/commits.rb @@ -159,8 +159,7 @@ module API commit = user_project.commit(params[:sha]) not_found!('Commit') unless commit - branch = user_project.repository.find_branch(params[:branch]) - not_found!('Branch') unless branch + find_branch!(params[:branch]) commit_params = { commit: commit, @@ -171,7 +170,7 @@ module API result = ::Commits::CherryPickService.new(user_project, current_user, commit_params).execute if result[:status] == :success - branch = user_project.repository.find_branch(params[:branch]) + branch = find_branch!(params[:branch]) present user_project.repository.commit(branch.dereferenced_target), with: Entities::Commit else render_api_error!(result[:message], 400) diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index be17653dbb2..5505d7a7b08 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -156,6 +156,12 @@ module API end end + def find_branch!(branch_name) + user_project.repository.find_branch(branch_name) || not_found!('Branch') + rescue Gitlab::Git::CommandError + render_api_error!('The branch refname is invalid', 400) + end + def find_project_label(id) labels = available_labels_for(user_project) label = labels.find_by_id(id) || labels.find_by_title(id) diff --git a/lib/banzai/filter/spaced_link_filter.rb b/lib/banzai/filter/spaced_link_filter.rb index a4dd6abfe03..a27f1d46863 100644 --- a/lib/banzai/filter/spaced_link_filter.rb +++ b/lib/banzai/filter/spaced_link_filter.rb @@ -10,11 +10,12 @@ module Banzai # # CommonMark does not allow spaces in the url portion of a link/url. # For example, `[example](page slug)` is not valid. - # Neither is `![example](test image.jpg)`. However, + # Neither is `![example](test image.jpg)`. However, particularly # in our wikis, we support (via RedCarpet) this type of link, allowing # wiki pages to be easily linked by their title. This filter adds that functionality. - # The intent is for this to only be used in Wikis - in general, we want - # to adhere to CommonMark's spec. + # + # This is a small extension to the CommonMark spec. If they start allowing + # spaces in urls, we could then remove this filter. # class SpacedLinkFilter < HTML::Pipeline::Filter include ActionView::Helpers::TagHelper diff --git a/lib/banzai/pipeline/gfm_pipeline.rb b/lib/banzai/pipeline/gfm_pipeline.rb index e9be05e174e..bd34614f149 100644 --- a/lib/banzai/pipeline/gfm_pipeline.rb +++ b/lib/banzai/pipeline/gfm_pipeline.rb @@ -16,6 +16,7 @@ module Banzai Filter::MathFilter, Filter::ColorFilter, Filter::MermaidFilter, + Filter::SpacedLinkFilter, Filter::VideoLinkFilter, Filter::ImageLazyLoadFilter, Filter::ImageLinkFilter, diff --git a/lib/banzai/pipeline/wiki_pipeline.rb b/lib/banzai/pipeline/wiki_pipeline.rb index d2fe5a6492f..c37b8e71cb0 100644 --- a/lib/banzai/pipeline/wiki_pipeline.rb +++ b/lib/banzai/pipeline/wiki_pipeline.rb @@ -5,7 +5,6 @@ module Banzai @filters ||= begin super.insert_after(Filter::TableOfContentsFilter, Filter::GollumTagsFilter) .insert_before(Filter::TaskListFilter, Filter::WikiLinkFilter) - .insert_before(Filter::VideoLinkFilter, Filter::SpacedLinkFilter) end end end diff --git a/lib/gitlab/current_settings.rb b/lib/gitlab/current_settings.rb index 9147ef401da..c9dbd2d2e5f 100644 --- a/lib/gitlab/current_settings.rb +++ b/lib/gitlab/current_settings.rb @@ -13,6 +13,10 @@ module Gitlab Gitlab::FakeApplicationSettings.new(::ApplicationSetting.defaults.merge(attributes || {})) end + def clear_in_memory_application_settings! + @in_memory_application_settings = nil + end + def method_missing(name, *args, &block) current_application_settings.send(name, *args, &block) # rubocop:disable GitlabSecurity/PublicSend end diff --git a/lib/gitlab/fake_application_settings.rb b/lib/gitlab/fake_application_settings.rb index bb14a8cd9e7..753160cc562 100644 --- a/lib/gitlab/fake_application_settings.rb +++ b/lib/gitlab/fake_application_settings.rb @@ -11,6 +11,10 @@ module Gitlab FakeApplicationSettings.define_predicate_methods(options) end + def pick_repository_storage + repository_storages.sample + end + # Mimic ActiveRecord predicate methods for boolean values def self.define_predicate_methods(options) options.each do |key, value| diff --git a/lib/gitlab/git_access.rb b/lib/gitlab/git_access.rb index 93720500711..30cd09a0ca7 100644 --- a/lib/gitlab/git_access.rb +++ b/lib/gitlab/git_access.rb @@ -241,8 +241,6 @@ module Gitlab end elsif user # User access is verified in check_change_access! - elsif authed_via_jwt? - # Authenticated via JWT else raise UnauthorizedError, ERROR_MESSAGES[:upload] end @@ -331,10 +329,6 @@ module Gitlab !Gitlab.config.gitlab_shell.receive_pack end - def authed_via_jwt? - false - end - protected def changes_list diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 7f85d6e0519..7b6c15abd4f 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -4681,6 +4681,9 @@ msgstr "" msgid "Project Badges" msgstr "" +msgid "Project URL" +msgstr "" + msgid "Project access must be granted explicitly to each user." msgstr "" @@ -4708,6 +4711,9 @@ msgstr "" msgid "Project name" msgstr "" +msgid "Project slug" +msgstr "" + msgid "ProjectActivityRSS|Subscribe" msgstr "" @@ -5934,6 +5940,9 @@ msgstr "" msgid "This branch has changed since you started editing. Would you like to create a new branch?" msgstr "" +msgid "This container registry has been scheduled for deletion." +msgstr "" + msgid "This diff is collapsed." msgstr "" diff --git a/package.json b/package.json index d5b747b4131..f7b5e84548b 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ }, "dependencies": { "@gitlab-org/gitlab-svgs": "^1.29.0", - "@gitlab-org/gitlab-ui": "1.0.5", + "@gitlab-org/gitlab-ui": "^1.2.0", "autosize": "^4.0.0", "axios": "^0.17.1", "babel-core": "^6.26.3", @@ -67,7 +67,7 @@ "js-cookie": "^2.1.3", "jszip": "^3.1.3", "jszip-utils": "^0.0.2", - "katex": "^0.8.3", + "katex": "^0.9.0", "marked": "^0.3.12", "monaco-editor": "^0.14.3", "monaco-editor-webpack-plugin": "^1.5.2", @@ -133,7 +133,7 @@ "jasmine-core": "^2.9.0", "jasmine-diff": "^0.1.3", "jasmine-jquery": "^2.1.1", - "karma": "^2.0.4", + "karma": "^3.0.0", "karma-chrome-launcher": "^2.2.0", "karma-coverage-istanbul-reporter": "^1.4.2", "karma-jasmine": "^1.1.2", diff --git a/qa/qa/page/main/login.rb b/qa/qa/page/main/login.rb index 1ea98b94aeb..3fb5e6cbdc4 100644 --- a/qa/qa/page/main/login.rb +++ b/qa/qa/page/main/login.rb @@ -68,7 +68,7 @@ module QA end def ldap_tab? - page.has_button?('LDAP') + page.has_link?('LDAP') end def switch_to_sign_in_tab diff --git a/qa/qa/page/project/new.rb b/qa/qa/page/project/new.rb index 1fb569b0f29..0766c98da6f 100644 --- a/qa/qa/page/project/new.rb +++ b/qa/qa/page/project/new.rb @@ -11,6 +11,7 @@ module QA view 'app/views/projects/_new_project_fields.html.haml' do element :project_namespace_select element :project_namespace_field, 'namespaces_options' + element :project_name, 'text_field :name' element :project_path, 'text_field :path' element :project_description, 'text_area :description' element :project_create_button, "submit 'Create project'" @@ -32,7 +33,7 @@ module QA end def choose_name(name) - fill_in 'project_path', with: name + fill_in 'project_name', with: name end def add_description(description) diff --git a/qa/qa/specs/runner.rb b/qa/qa/specs/runner.rb index 5b5699d8a93..fea0ef94df3 100644 --- a/qa/qa/specs/runner.rb +++ b/qa/qa/specs/runner.rb @@ -5,10 +5,12 @@ module QA class Runner < Scenario::Template attr_accessor :tty, :tags, :options + DEFAULT_TEST_PATH_ARGS = ['--', File.expand_path('./features', __dir__)].freeze + def initialize @tty = false @tags = [] - @options = [File.expand_path('./features', __dir__)] + @options = [] end def perform @@ -18,10 +20,11 @@ module QA if tags.any? tags.each { |tag| args.push(['--tag', tag.to_s]) } else - args.push(%w[--tag ~orchestrated]) + args.push(%w[--tag ~orchestrated]) unless (%w[-t --tag] & options).any? end args.push(options) + args.push(DEFAULT_TEST_PATH_ARGS) unless options.any? { |opt| opt =~ %r{/features/} } Runtime::Browser.configure! diff --git a/qa/spec/specs/runner_spec.rb b/qa/spec/specs/runner_spec.rb index b237b954889..cf22d1c9395 100644 --- a/qa/spec/specs/runner_spec.rb +++ b/qa/spec/specs/runner_spec.rb @@ -7,43 +7,65 @@ describe QA::Specs::Runner do end it 'excludes the orchestrated tag by default' do - expect(RSpec::Core::Runner).to receive(:run) - .with(['--tag', '~orchestrated', File.expand_path('../../qa/specs/features', __dir__)], $stderr, $stdout) - .and_return(0) + expect_rspec_runner_arguments(['--tag', '~orchestrated', *described_class::DEFAULT_TEST_PATH_ARGS]) subject.perform end context 'when tty is set' do - subject do - described_class.new.tap do |runner| - runner.tty = true - end - end + subject { described_class.new.tap { |runner| runner.tty = true } } it 'sets the `--tty` flag' do - expect(RSpec::Core::Runner).to receive(:run) - .with(['--tty', '--tag', '~orchestrated', File.expand_path('../../qa/specs/features', __dir__)], $stderr, $stdout) - .and_return(0) + expect_rspec_runner_arguments(['--tty', '--tag', '~orchestrated', *described_class::DEFAULT_TEST_PATH_ARGS]) subject.perform end end context 'when tags are set' do - subject do - described_class.new.tap do |runner| - runner.tags = %i[orchestrated github] - end - end + subject { described_class.new.tap { |runner| runner.tags = %i[orchestrated github] } } it 'focuses on the given tags' do - expect(RSpec::Core::Runner).to receive(:run) - .with(['--tag', 'orchestrated', '--tag', 'github', File.expand_path('../../qa/specs/features', __dir__)], $stderr, $stdout) - .and_return(0) + expect_rspec_runner_arguments(['--tag', 'orchestrated', '--tag', 'github', *described_class::DEFAULT_TEST_PATH_ARGS]) + + subject.perform + end + end + + context 'when "--tag smoke" is set as options' do + subject { described_class.new.tap { |runner| runner.options = %w[--tag smoke] } } + + it 'focuses on the given tag without excluded the orchestrated tag' do + expect_rspec_runner_arguments(['--tag', 'smoke', *described_class::DEFAULT_TEST_PATH_ARGS]) + + subject.perform + end + end + + context 'when "qa/specs/features/foo" is set as options' do + subject { described_class.new.tap { |runner| runner.options = %w[qa/specs/features/foo] } } + + it 'passes the given tests path and excludes the orchestrated tag' do + expect_rspec_runner_arguments(['--tag', '~orchestrated', 'qa/specs/features/foo']) subject.perform end end + + context 'when "-- qa/specs/features/foo" is set as options' do + subject { described_class.new.tap { |runner| runner.options = %w[-- qa/specs/features/foo] } } + + it 'passes the given tests path and excludes the orchestrated tag' do + expect_rspec_runner_arguments(['--tag', '~orchestrated', '--', 'qa/specs/features/foo']) + + subject.perform + end + end + + def expect_rspec_runner_arguments(arguments) + expect(RSpec::Core::Runner).to receive(:run) + .with(arguments, $stderr, $stdout) + .and_return(0) + end end end diff --git a/spec/controllers/projects/registry/repositories_controller_spec.rb b/spec/controllers/projects/registry/repositories_controller_spec.rb index 17769a14def..d11e42b411b 100644 --- a/spec/controllers/projects/registry/repositories_controller_spec.rb +++ b/spec/controllers/projects/registry/repositories_controller_spec.rb @@ -86,9 +86,10 @@ describe Projects::Registry::RepositoriesController do stub_container_registry_tags(repository: :any, tags: []) end - it 'deletes a repository' do - expect { delete_repository(repository) }.to change { ContainerRepository.all.count }.by(-1) + it 'schedules a job to delete a repository' do + expect(DeleteContainerRepositoryWorker).to receive(:perform_async).with(user.id, repository.id) + delete_repository(repository) expect(response).to have_gitlab_http_status(:no_content) end end diff --git a/spec/features/commits/user_uses_slash_commands_spec.rb b/spec/features/commits/user_uses_quick_actions_spec.rb index 9a4b7bd2444..9a4b7bd2444 100644 --- a/spec/features/commits/user_uses_slash_commands_spec.rb +++ b/spec/features/commits/user_uses_quick_actions_spec.rb diff --git a/spec/features/explore/new_menu_spec.rb b/spec/features/explore/new_menu_spec.rb index 0a88988ea09..11f05b6d220 100644 --- a/spec/features/explore/new_menu_spec.rb +++ b/spec/features/explore/new_menu_spec.rb @@ -20,7 +20,7 @@ describe 'Top Plus Menu', :js do click_topmenuitem("New project") - expect(page).to have_content('Project path') + expect(page).to have_content('Project URL') expect(page).to have_content('Project name') end @@ -92,7 +92,7 @@ describe 'Top Plus Menu', :js do find('.header-new-group-project a').click end - expect(page).to have_content('Project path') + expect(page).to have_content('Project URL') expect(page).to have_content('Project name') end end diff --git a/spec/features/instance_statistics/cohorts_spec.rb b/spec/features/instance_statistics/cohorts_spec.rb index 81fc5eff980..40e65515ceb 100644 --- a/spec/features/instance_statistics/cohorts_spec.rb +++ b/spec/features/instance_statistics/cohorts_spec.rb @@ -3,6 +3,8 @@ require 'rails_helper' describe 'Cohorts page' do before do sign_in(create(:admin)) + + stub_application_setting(usage_ping_enabled: true) end it 'See users count per month' do diff --git a/spec/features/issues/user_uses_slash_commands_spec.rb b/spec/features/issues/user_uses_quick_actions_spec.rb index 5926e442f24..5926e442f24 100644 --- a/spec/features/issues/user_uses_slash_commands_spec.rb +++ b/spec/features/issues/user_uses_quick_actions_spec.rb diff --git a/spec/features/merge_request/user_posts_diff_notes_spec.rb b/spec/features/merge_request/user_posts_diff_notes_spec.rb index 77261f9375c..b6ed3686de2 100644 --- a/spec/features/merge_request/user_posts_diff_notes_spec.rb +++ b/spec/features/merge_request/user_posts_diff_notes_spec.rb @@ -186,11 +186,8 @@ describe 'Merge request > User posts diff notes', :js do describe 'posting a note' do it 'adds as discussion' do - expect(page).to have_css('.js-temp-notes-holder', count: 2) - should_allow_commenting(find('[id="6eb14e00385d2fb284765eb1cd8d420d33d63fc9_22_22"]'), asset_form_reset: false) expect(page).to have_css('.notes_holder .note.note-discussion', count: 1) - expect(page).to have_css('.js-temp-notes-holder', count: 1) expect(page).to have_button('Reply...') end end @@ -267,7 +264,7 @@ describe 'Merge request > User posts diff notes', :js do def assert_comment_persistence(line_holder, asset_form_reset:) notes_holder_saved = line_holder.find(:xpath, notes_holder_input_xpath) - expect(notes_holder_saved[:class]).not_to include(notes_holder_input_class) + expect(notes_holder_saved[:class]).not_to include('note-edit-form') expect(notes_holder_saved).to have_content test_note_comment assert_form_is_reset if asset_form_reset @@ -281,6 +278,6 @@ describe 'Merge request > User posts diff notes', :js do end def assert_form_is_reset - expect(page).to have_no_css('.js-temp-notes-holder') + expect(page).to have_no_css('.note-edit-form') end end diff --git a/spec/features/merge_request/user_uses_slash_commands_spec.rb b/spec/features/merge_request/user_uses_quick_actions_spec.rb index b81478a481f..b81478a481f 100644 --- a/spec/features/merge_request/user_uses_slash_commands_spec.rb +++ b/spec/features/merge_request/user_uses_quick_actions_spec.rb diff --git a/spec/features/projects/import_export/import_file_spec.rb b/spec/features/projects/import_export/import_file_spec.rb index 2936482a1f7..6cd5810325f 100644 --- a/spec/features/projects/import_export/import_file_spec.rb +++ b/spec/features/projects/import_export/import_file_spec.rb @@ -20,6 +20,7 @@ describe 'Import/Export - project import integration test', :js do context 'when selecting the namespace' do let(:user) { create(:admin) } let!(:namespace) { user.namespace } + let(:project_name) { 'Test Project Name' + SecureRandom.hex } let(:project_path) { 'test-project-path' + SecureRandom.hex } context 'prefilled the path' do @@ -27,12 +28,13 @@ describe 'Import/Export - project import integration test', :js do visit new_project_path select2(namespace.id, from: '#project_namespace_id') + fill_in :project_name, with: project_name, visible: true fill_in :project_path, with: project_path, visible: true click_import_project_tab click_link 'GitLab export' expect(page).to have_content('Import an exported GitLab project') - expect(URI.parse(current_url).query).to eq("namespace_id=#{namespace.id}&path=#{project_path}") + expect(URI.parse(current_url).query).to eq("namespace_id=#{namespace.id}&name=#{ERB::Util.url_encode(project_name)}&path=#{project_path}") attach_file('file', file) click_on 'Import project' @@ -56,6 +58,7 @@ describe 'Import/Export - project import integration test', :js do click_import_project_tab click_link 'GitLab export' + fill_in :name, with: 'Test Project Name', visible: true fill_in :path, with: 'test-project-path', visible: true attach_file('file', file) @@ -74,7 +77,8 @@ describe 'Import/Export - project import integration test', :js do visit new_project_path select2(user.namespace.id, from: '#project_namespace_id') - fill_in :project_path, with: project.name, visible: true + fill_in :project_name, with: project.name, visible: true + fill_in :project_path, with: project.path, visible: true click_import_project_tab click_link 'GitLab export' attach_file('file', file) diff --git a/spec/features/projects/members/invite_group_spec.rb b/spec/features/projects/members/invite_group_spec.rb index 1ea4934cff1..0fb3eb20b5b 100644 --- a/spec/features/projects/members/invite_group_spec.rb +++ b/spec/features/projects/members/invite_group_spec.rb @@ -17,7 +17,6 @@ describe 'Project > Members > Invite group', :js do shared_examples 'the project cannot be shared with groups' do it 'the "Invite group" tab does not exist' do visit project_settings_members_path(project) - expect(page).to have_selector('#invite-member-tab') expect(page).not_to have_selector('#invite-group-tab') end end @@ -31,7 +30,7 @@ describe 'Project > Members > Invite group', :js do sign_in(maintainer) end - context 'when the group has "Invite group lock" disabled' do + context 'when the group has "Share with group lock" disabled' do it_behaves_like 'the project can be shared with groups' it 'the project can be shared with another group' do @@ -49,7 +48,7 @@ describe 'Project > Members > Invite group', :js do end end - context 'when the group has "Invite group lock" enabled' do + context 'when the group has "Share with group lock" enabled' do before do project.namespace.update_column(:share_with_group_lock, true) end @@ -69,12 +68,12 @@ describe 'Project > Members > Invite group', :js do sign_in(maintainer) end - context 'when the root_group has "Invite group lock" disabled' do - context 'when the subgroup has "Invite group lock" disabled' do + context 'when the root_group has "Share with group lock" disabled' do + context 'when the subgroup has "Share with group lock" disabled' do it_behaves_like 'the project can be shared with groups' end - context 'when the subgroup has "Invite group lock" enabled' do + context 'when the subgroup has "Share with group lock" enabled' do before do subgroup.update_column(:share_with_group_lock, true) end @@ -83,16 +82,16 @@ describe 'Project > Members > Invite group', :js do end end - context 'when the root_group has "Invite group lock" enabled' do + context 'when the root_group has "Share with group lock" enabled' do before do root_group.update_column(:share_with_group_lock, true) end - context 'when the subgroup has "Invite group lock" disabled (parent overridden)' do + context 'when the subgroup has "Share with group lock" disabled (parent overridden)' do it_behaves_like 'the project can be shared with groups' end - context 'when the subgroup has "Invite group lock" enabled' do + context 'when the subgroup has "Share with group lock" enabled' do before do subgroup.update_column(:share_with_group_lock, true) end diff --git a/spec/features/projects/new_project_spec.rb b/spec/features/projects/new_project_spec.rb index bbe08ff83ff..0acd5059385 100644 --- a/spec/features/projects/new_project_spec.rb +++ b/spec/features/projects/new_project_spec.rb @@ -12,8 +12,9 @@ describe 'New project' do it 'shows "New project" page', :js do visit new_project_path - expect(page).to have_content('Project path') expect(page).to have_content('Project name') + expect(page).to have_content('Project URL') + expect(page).to have_content('Project slug') find('#import-project-tab').click @@ -187,7 +188,7 @@ describe 'New project' do collision_project = create(:project, name: 'test-name-collision', namespace: user.namespace) fill_in 'project_import_url', with: collision_project.http_url_to_repo - fill_in 'project_path', with: collision_project.path + fill_in 'project_name', with: collision_project.name click_on 'Create project' diff --git a/spec/features/projects/user_creates_project_spec.rb b/spec/features/projects/user_creates_project_spec.rb index 83d18996f4e..8d7e2883b2a 100644 --- a/spec/features/projects/user_creates_project_spec.rb +++ b/spec/features/projects/user_creates_project_spec.rb @@ -11,7 +11,7 @@ describe 'User creates a project', :js do it 'creates a new project' do visit(new_project_path) - fill_in(:project_path, with: 'Empty') + fill_in(:project_name, with: 'Empty') page.within('#content-body') do click_button('Create project') @@ -37,6 +37,7 @@ describe 'User creates a project', :js do it 'creates a new project' do visit(new_project_path) + fill_in :project_name, with: 'A Subgroup Project' fill_in :project_path, with: 'a-subgroup-project' page.find('.js-select-namespace').click @@ -46,7 +47,7 @@ describe 'User creates a project', :js do click_button('Create project') end - expect(page).to have_content("Project 'a-subgroup-project' was successfully created") + expect(page).to have_content("Project 'A Subgroup Project' was successfully created") project = Project.last diff --git a/spec/features/projects/wiki/user_deletes_wiki_page_spec.rb b/spec/features/projects/wiki/user_deletes_wiki_page_spec.rb index 5007794cd77..18ccd31f3d0 100644 --- a/spec/features/projects/wiki/user_deletes_wiki_page_spec.rb +++ b/spec/features/projects/wiki/user_deletes_wiki_page_spec.rb @@ -13,7 +13,7 @@ describe 'User deletes wiki page', :js do it 'deletes a page' do click_on('Edit') click_on('Delete') - find('.js-modal-primary-action').click + find('.modal-footer .btn-danger').click expect(page).to have_content('Page was successfully deleted') end diff --git a/spec/features/projects_spec.rb b/spec/features/projects_spec.rb index 22e3a99072f..8e310f38a8c 100644 --- a/spec/features/projects_spec.rb +++ b/spec/features/projects_spec.rb @@ -16,7 +16,7 @@ describe 'Project' do it "allows creation from templates", :js do find('#create-from-template-tab').click find("label[for=#{template.name}]").click - fill_in("project_path", with: template.name) + fill_in("project_name", with: template.name) page.within '#content-body' do click_button "Create project" diff --git a/spec/helpers/issuables_helper_spec.rb b/spec/helpers/issuables_helper_spec.rb index f76ed4bfda4..4af98bc3678 100644 --- a/spec/helpers/issuables_helper_spec.rb +++ b/spec/helpers/issuables_helper_spec.rb @@ -184,7 +184,7 @@ describe IssuablesHelper do issuableRef: "##{issue.iid}", markdownPreviewPath: "/#{@project.full_path}/preview_markdown", markdownDocsPath: '/help/user/markdown', - markdownVersion: 11, + markdownVersion: CacheMarkdownField::CACHE_COMMONMARK_VERSION, issuableTemplates: [], projectPath: @project.path, projectNamespace: @project.namespace.path, diff --git a/spec/javascripts/diffs/components/diff_file_spec.js b/spec/javascripts/diffs/components/diff_file_spec.js index 44a38f7ca82..845fef23db6 100644 --- a/spec/javascripts/diffs/components/diff_file_spec.js +++ b/spec/javascripts/diffs/components/diff_file_spec.js @@ -51,7 +51,9 @@ describe('DiffFile', () => { }); it('should have collapsed text and link', done => { - vm.file.collapsed = true; + vm.file.renderIt = true; + vm.file.collapsed = false; + vm.file.highlightedDiffLines = null; vm.$nextTick(() => { expect(vm.$el.innerText).toContain('This diff is collapsed'); diff --git a/spec/javascripts/diffs/components/diff_line_gutter_content_spec.js b/spec/javascripts/diffs/components/diff_line_gutter_content_spec.js index a1a37b342b7..663c0680845 100644 --- a/spec/javascripts/diffs/components/diff_line_gutter_content_spec.js +++ b/spec/javascripts/diffs/components/diff_line_gutter_content_spec.js @@ -6,61 +6,61 @@ import discussionsMockData from '../mock_data/diff_discussions'; import diffFileMockData from '../mock_data/diff_file'; describe('DiffLineGutterContent', () => { - const getDiscussionsMockData = () => [Object.assign({}, discussionsMockData)]; const getDiffFileMock = () => Object.assign({}, diffFileMockData); const createComponent = (options = {}) => { const cmp = Vue.extend(DiffLineGutterContent); const props = Object.assign({}, options); + props.line = { + lineCode: 'LC_42', + type: 'new', + oldLine: null, + newLine: 1, + discussions: [], + text: '+<span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n', + richText: '+<span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n', + metaData: null, + }; props.fileHash = getDiffFileMock().fileHash; props.contextLinesPath = '/context/lines/path'; return createComponentWithStore(cmp, store, props).$mount(); }; - const setDiscussions = component => { - component.$store.dispatch('setInitialNotes', getDiscussionsMockData()); - }; - - const resetDiscussions = component => { - component.$store.dispatch('setInitialNotes', []); - }; describe('computed', () => { describe('lineHref', () => { it('should prepend # to lineCode', () => { const lineCode = 'LC_42'; - const component = createComponent({ lineCode }); + const component = createComponent(); expect(component.lineHref).toEqual(`#${lineCode}`); }); it('should return # if there is no lineCode', () => { - const component = createComponent({ lineCode: null }); + const component = createComponent(); + component.line.lineCode = ''; expect(component.lineHref).toEqual('#'); }); }); describe('discussions, hasDiscussions, shouldShowAvatarsOnGutter', () => { it('should return empty array when there is no discussion', () => { - const component = createComponent({ lineCode: 'LC_42' }); - expect(component.discussions).toEqual([]); + const component = createComponent(); expect(component.hasDiscussions).toEqual(false); expect(component.shouldShowAvatarsOnGutter).toEqual(false); }); it('should return discussions for the given lineCode', () => { - const { lineCode } = getDiffFileMock().highlightedDiffLines[1]; - const component = createComponent({ - lineCode, + const cmp = Vue.extend(DiffLineGutterContent); + const props = { + line: getDiffFileMock().highlightedDiffLines[1], + fileHash: getDiffFileMock().fileHash, showCommentButton: true, - discussions: getDiscussionsMockData(), - }); + contextLinesPath: '/context/lines/path', + }; + props.line.discussions = [Object.assign({}, discussionsMockData)]; + const component = createComponentWithStore(cmp, store, props).$mount(); - setDiscussions(component); - - expect(component.discussions).toEqual(getDiscussionsMockData()); expect(component.hasDiscussions).toEqual(true); expect(component.shouldShowAvatarsOnGutter).toEqual(true); - - resetDiscussions(component); }); }); }); @@ -104,9 +104,7 @@ describe('DiffLineGutterContent', () => { lineCode: getDiffFileMock().highlightedDiffLines[1].lineCode, }); - setDiscussions(component); expect(component.$el.querySelector('.diff-comment-avatar-holders')).toBeDefined(); - resetDiscussions(component); }); }); }); diff --git a/spec/javascripts/diffs/components/parallel_diff_view_spec.js b/spec/javascripts/diffs/components/parallel_diff_view_spec.js index 165e4b69b6c..091e01868d3 100644 --- a/spec/javascripts/diffs/components/parallel_diff_view_spec.js +++ b/spec/javascripts/diffs/components/parallel_diff_view_spec.js @@ -18,11 +18,11 @@ describe('ParallelDiffView', () => { }).$mount(); }); - describe('computed', () => { - describe('parallelDiffLines', () => { + describe('assigned', () => { + describe('diffLines', () => { it('should normalize lines for empty cells', () => { - expect(component.parallelDiffLines[0].left.type).toEqual(constants.EMPTY_CELL_TYPE); - expect(component.parallelDiffLines[1].left.type).toEqual(constants.EMPTY_CELL_TYPE); + expect(component.diffLines[0].left.type).toEqual(constants.EMPTY_CELL_TYPE); + expect(component.diffLines[1].left.type).toEqual(constants.EMPTY_CELL_TYPE); }); }); }); diff --git a/spec/javascripts/diffs/mock_data/diff_file.js b/spec/javascripts/diffs/mock_data/diff_file.js index cce36ecc91f..372b8f066cf 100644 --- a/spec/javascripts/diffs/mock_data/diff_file.js +++ b/spec/javascripts/diffs/mock_data/diff_file.js @@ -49,6 +49,7 @@ export default { type: 'new', oldLine: null, newLine: 1, + discussions: [], text: '+<span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n', richText: '+<span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n', metaData: null, @@ -58,6 +59,7 @@ export default { type: 'new', oldLine: null, newLine: 2, + discussions: [], text: '+<span id="LC2" class="line" lang="plaintext"></span>\n', richText: '+<span id="LC2" class="line" lang="plaintext"></span>\n', metaData: null, @@ -67,6 +69,7 @@ export default { type: null, oldLine: 1, newLine: 3, + discussions: [], text: ' <span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n', richText: ' <span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n', metaData: null, @@ -76,6 +79,7 @@ export default { type: null, oldLine: 2, newLine: 4, + discussions: [], text: ' <span id="LC4" class="line" lang="plaintext"></span>\n', richText: ' <span id="LC4" class="line" lang="plaintext"></span>\n', metaData: null, @@ -85,6 +89,7 @@ export default { type: null, oldLine: 3, newLine: 5, + discussions: [], text: ' <span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n', richText: ' <span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n', metaData: null, @@ -94,6 +99,7 @@ export default { type: 'match', oldLine: null, newLine: null, + discussions: [], text: '', richText: '', metaData: { @@ -112,6 +118,7 @@ export default { type: 'new', oldLine: null, newLine: 1, + discussions: [], text: '+<span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n', richText: '<span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n', metaData: null, @@ -126,6 +133,7 @@ export default { type: 'new', oldLine: null, newLine: 2, + discussions: [], text: '+<span id="LC2" class="line" lang="plaintext"></span>\n', richText: '<span id="LC2" class="line" lang="plaintext"></span>\n', metaData: null, @@ -137,6 +145,7 @@ export default { type: null, oldLine: 1, newLine: 3, + discussions: [], text: ' <span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n', richText: '<span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n', metaData: null, @@ -146,6 +155,7 @@ export default { type: null, oldLine: 1, newLine: 3, + discussions: [], text: ' <span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n', richText: '<span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n', metaData: null, @@ -157,6 +167,7 @@ export default { type: null, oldLine: 2, newLine: 4, + discussions: [], text: ' <span id="LC4" class="line" lang="plaintext"></span>\n', richText: '<span id="LC4" class="line" lang="plaintext"></span>\n', metaData: null, @@ -166,6 +177,7 @@ export default { type: null, oldLine: 2, newLine: 4, + discussions: [], text: ' <span id="LC4" class="line" lang="plaintext"></span>\n', richText: '<span id="LC4" class="line" lang="plaintext"></span>\n', metaData: null, @@ -177,6 +189,7 @@ export default { type: null, oldLine: 3, newLine: 5, + discussions: [], text: ' <span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n', richText: '<span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n', metaData: null, @@ -186,6 +199,7 @@ export default { type: null, oldLine: 3, newLine: 5, + discussions: [], text: ' <span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n', richText: '<span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n', metaData: null, @@ -197,6 +211,7 @@ export default { type: 'match', oldLine: null, newLine: null, + discussions: [], text: '', richText: '', metaData: { @@ -209,6 +224,7 @@ export default { type: 'match', oldLine: null, newLine: null, + discussions: [], text: '', richText: '', metaData: { diff --git a/spec/javascripts/diffs/store/actions_spec.js b/spec/javascripts/diffs/store/actions_spec.js index c1560dac1a0..cfb8f862598 100644 --- a/spec/javascripts/diffs/store/actions_spec.js +++ b/spec/javascripts/diffs/store/actions_spec.js @@ -7,10 +7,30 @@ import { } from '~/diffs/constants'; import * as actions from '~/diffs/store/actions'; import * as types from '~/diffs/store/mutation_types'; +import { reduceDiscussionsToLineCodes } from '~/notes/stores/utils'; import axios from '~/lib/utils/axios_utils'; import testAction from '../../helpers/vuex_action_helper'; describe('DiffsStoreActions', () => { + const originalMethods = { + requestAnimationFrame: global.requestAnimationFrame, + requestIdleCallback: global.requestIdleCallback, + }; + + beforeEach(() => { + ['requestAnimationFrame', 'requestIdleCallback'].forEach(method => { + global[method] = cb => { + cb(); + }; + }); + }); + + afterEach(() => { + ['requestAnimationFrame', 'requestIdleCallback'].forEach(method => { + global[method] = originalMethods[method]; + }); + }); + describe('setBaseConfig', () => { it('should set given endpoint and project path', done => { const endpoint = '/diffs/set/endpoint'; @@ -53,6 +73,198 @@ describe('DiffsStoreActions', () => { }); }); + describe('assignDiscussionsToDiff', () => { + it('should merge discussions into diffs', done => { + const state = { + diffFiles: [ + { + fileHash: 'ABC', + parallelDiffLines: [ + { + left: { + lineCode: 'ABC_1_1', + discussions: [], + }, + right: { + lineCode: 'ABC_1_1', + discussions: [], + }, + }, + ], + highlightedDiffLines: [ + { + lineCode: 'ABC_1_1', + discussions: [], + oldLine: 5, + newLine: null, + }, + ], + diffRefs: { + baseSha: 'abc', + headSha: 'def', + startSha: 'ghi', + }, + newPath: 'file1', + oldPath: 'file2', + }, + ], + }; + + const diffPosition = { + baseSha: 'abc', + headSha: 'def', + startSha: 'ghi', + newLine: null, + newPath: 'file1', + oldLine: 5, + oldPath: 'file2', + }; + + const singleDiscussion = { + line_code: 'ABC_1_1', + diff_discussion: {}, + diff_file: { + file_hash: 'ABC', + }, + fileHash: 'ABC', + resolvable: true, + position: { + formatter: diffPosition, + }, + original_position: { + formatter: diffPosition, + }, + }; + + const discussions = reduceDiscussionsToLineCodes([singleDiscussion]); + + testAction( + actions.assignDiscussionsToDiff, + discussions, + state, + [ + { + type: types.SET_LINE_DISCUSSIONS_FOR_FILE, + payload: { + fileHash: 'ABC', + discussions: [singleDiscussion], + diffPositionByLineCode: { + ABC_1_1: { + baseSha: 'abc', + headSha: 'def', + startSha: 'ghi', + newLine: null, + newPath: 'file1', + oldLine: 5, + oldPath: 'file2', + }, + }, + }, + }, + ], + [], + () => { + done(); + }, + ); + }); + }); + + describe('removeDiscussionsFromDiff', () => { + it('should remove discussions from diffs', done => { + const state = { + diffFiles: [ + { + fileHash: 'ABC', + parallelDiffLines: [ + { + left: { + lineCode: 'ABC_1_1', + discussions: [ + { + id: 1, + }, + ], + }, + right: { + lineCode: 'ABC_1_1', + discussions: [], + }, + }, + ], + highlightedDiffLines: [ + { + lineCode: 'ABC_1_1', + discussions: [], + }, + ], + }, + ], + }; + const singleDiscussion = { + fileHash: 'ABC', + line_code: 'ABC_1_1', + }; + + testAction( + actions.removeDiscussionsFromDiff, + singleDiscussion, + state, + [ + { + type: types.REMOVE_LINE_DISCUSSIONS_FOR_FILE, + payload: { + fileHash: 'ABC', + lineCode: 'ABC_1_1', + }, + }, + ], + [], + () => { + done(); + }, + ); + }); + }); + + describe('startRenderDiffsQueue', () => { + it('should set all files to RENDER_FILE', done => { + const state = { + diffFiles: [ + { + id: 1, + renderIt: false, + collapsed: false, + }, + { + id: 2, + renderIt: false, + collapsed: false, + }, + ], + }; + + const pseudoCommit = (commitType, file) => { + expect(commitType).toBe(types.RENDER_FILE); + Object.assign(file, { + renderIt: true, + }); + }; + + actions + .startRenderDiffsQueue({ state, commit: pseudoCommit }) + .then(() => { + expect(state.diffFiles[0].renderIt).toBeTruthy(); + expect(state.diffFiles[1].renderIt).toBeTruthy(); + + done(); + }) + .catch(() => { + done.fail(); + }); + }); + }); + describe('setInlineDiffViewType', () => { it('should set diff view type to inline and also set the cookie properly', done => { testAction( @@ -204,7 +416,11 @@ describe('DiffsStoreActions', () => { actions.toggleFileDiscussions({ getters, dispatch }); - expect(dispatch).toHaveBeenCalledWith('collapseDiscussion', { discussionId: 1 }, { root: true }); + expect(dispatch).toHaveBeenCalledWith( + 'collapseDiscussion', + { discussionId: 1 }, + { root: true }, + ); }); it('should dispatch expandDiscussion when all discussions are collapsed', () => { @@ -218,7 +434,11 @@ describe('DiffsStoreActions', () => { actions.toggleFileDiscussions({ getters, dispatch }); - expect(dispatch).toHaveBeenCalledWith('expandDiscussion', { discussionId: 1 }, { root: true }); + expect(dispatch).toHaveBeenCalledWith( + 'expandDiscussion', + { discussionId: 1 }, + { root: true }, + ); }); it('should dispatch expandDiscussion when some discussions are collapsed and others are expanded for the collapsed discussion', () => { @@ -232,7 +452,11 @@ describe('DiffsStoreActions', () => { actions.toggleFileDiscussions({ getters, dispatch }); - expect(dispatch).toHaveBeenCalledWith('expandDiscussion', { discussionId: 1 }, { root: true }); + expect(dispatch).toHaveBeenCalledWith( + 'expandDiscussion', + { discussionId: 1 }, + { root: true }, + ); }); }); }); diff --git a/spec/javascripts/diffs/store/getters_spec.js b/spec/javascripts/diffs/store/getters_spec.js index a59b26b2634..4747e437c4e 100644 --- a/spec/javascripts/diffs/store/getters_spec.js +++ b/spec/javascripts/diffs/store/getters_spec.js @@ -184,101 +184,73 @@ describe('Diffs Module Getters', () => { }); }); - describe('singleDiscussionByLineCode', () => { - it('returns found discussion per line Code', () => { - const discussionsMock = {}; - discussionsMock.ABC = discussionMock; - - expect( - getters.singleDiscussionByLineCode(localState, {}, null, { - discussionsByLineCode: () => discussionsMock, - })('DEF'), - ).toEqual([]); - }); - - it('returns empty array when no discussions match', () => { - expect( - getters.singleDiscussionByLineCode(localState, {}, null, { - discussionsByLineCode: () => {}, - })('DEF'), - ).toEqual([]); - }); - }); - describe('shouldRenderParallelCommentRow', () => { let line; beforeEach(() => { line = {}; + discussionMock.expanded = true; + line.left = { lineCode: 'ABC', + discussions: [discussionMock], }; line.right = { lineCode: 'DEF', + discussions: [discussionMock1], }; }); it('returns true when discussion is expanded', () => { - discussionMock.expanded = true; - - expect( - getters.shouldRenderParallelCommentRow(localState, { - singleDiscussionByLineCode: () => [discussionMock], - })(line), - ).toEqual(true); + expect(getters.shouldRenderParallelCommentRow(localState)(line)).toEqual(true); }); it('returns false when no discussion was found', () => { + line.left.discussions = []; + line.right.discussions = []; + localState.diffLineCommentForms.ABC = false; localState.diffLineCommentForms.DEF = false; - expect( - getters.shouldRenderParallelCommentRow(localState, { - singleDiscussionByLineCode: () => [], - })(line), - ).toEqual(false); + expect(getters.shouldRenderParallelCommentRow(localState)(line)).toEqual(false); }); it('returns true when discussionForm was found', () => { localState.diffLineCommentForms.ABC = {}; - expect( - getters.shouldRenderParallelCommentRow(localState, { - singleDiscussionByLineCode: () => [discussionMock], - })(line), - ).toEqual(true); + expect(getters.shouldRenderParallelCommentRow(localState)(line)).toEqual(true); }); }); describe('shouldRenderInlineCommentRow', () => { + let line; + + beforeEach(() => { + discussionMock.expanded = true; + + line = { + lineCode: 'ABC', + discussions: [discussionMock], + }; + }); + it('returns true when diffLineCommentForms has form', () => { localState.diffLineCommentForms.ABC = {}; - expect( - getters.shouldRenderInlineCommentRow(localState)({ - lineCode: 'ABC', - }), - ).toEqual(true); + expect(getters.shouldRenderInlineCommentRow(localState)(line)).toEqual(true); }); it('returns false when no line discussions were found', () => { - expect( - getters.shouldRenderInlineCommentRow(localState, { - singleDiscussionByLineCode: () => [], - })('DEF'), - ).toEqual(false); + line.discussions = []; + expect(getters.shouldRenderInlineCommentRow(localState)(line)).toEqual(false); }); it('returns true if all found discussions are expanded', () => { discussionMock.expanded = true; - expect( - getters.shouldRenderInlineCommentRow(localState, { - singleDiscussionByLineCode: () => [discussionMock], - })('ABC'), - ).toEqual(true); + expect(getters.shouldRenderInlineCommentRow(localState)(line)).toEqual(true); }); }); diff --git a/spec/javascripts/diffs/store/mutations_spec.js b/spec/javascripts/diffs/store/mutations_spec.js index 8f89984c6e5..7eeca6712cc 100644 --- a/spec/javascripts/diffs/store/mutations_spec.js +++ b/spec/javascripts/diffs/store/mutations_spec.js @@ -138,10 +138,9 @@ describe('DiffsStoreMutations', () => { const fileHash = 123; const state = { diffFiles: [{}, { fileHash, existingField: 0 }] }; - const file = { fileHash }; const data = { diff_files: [{ file_hash: fileHash, extra_field: 1, existingField: 1 }] }; - mutations[types.ADD_COLLAPSED_DIFFS](state, { file, data }); + mutations[types.ADD_COLLAPSED_DIFFS](state, { file: state.diffFiles[1], data }); expect(spy).toHaveBeenCalledWith(data, { deep: true }); expect(state.diffFiles[1].fileHash).toEqual(fileHash); @@ -149,4 +148,141 @@ describe('DiffsStoreMutations', () => { expect(state.diffFiles[1].extraField).toEqual(1); }); }); + + describe('SET_LINE_DISCUSSIONS_FOR_FILE', () => { + it('should add discussions to the given line', () => { + const diffPosition = { + baseSha: 'ed13df29948c41ba367caa757ab3ec4892509910', + headSha: 'b921914f9a834ac47e6fd9420f78db0f83559130', + newLine: null, + newPath: '500-lines-4.txt', + oldLine: 5, + oldPath: '500-lines-4.txt', + startSha: 'ed13df29948c41ba367caa757ab3ec4892509910', + }; + + const state = { + diffFiles: [ + { + fileHash: 'ABC', + parallelDiffLines: [ + { + left: { + lineCode: 'ABC_1', + discussions: [], + }, + right: { + lineCode: 'ABC_1', + discussions: [], + }, + }, + ], + highlightedDiffLines: [ + { + lineCode: 'ABC_1', + discussions: [], + }, + ], + }, + ], + }; + const discussions = [ + { + id: 1, + line_code: 'ABC_1', + diff_discussion: true, + resolvable: true, + original_position: { + formatter: diffPosition, + }, + position: { + formatter: diffPosition, + }, + }, + { + id: 2, + line_code: 'ABC_1', + diff_discussion: true, + resolvable: true, + original_position: { + formatter: diffPosition, + }, + position: { + formatter: diffPosition, + }, + }, + ]; + + const diffPositionByLineCode = { + ABC_1: diffPosition, + }; + + mutations[types.SET_LINE_DISCUSSIONS_FOR_FILE](state, { + fileHash: 'ABC', + discussions, + diffPositionByLineCode, + }); + + expect(state.diffFiles[0].parallelDiffLines[0].left.discussions.length).toEqual(2); + expect(state.diffFiles[0].parallelDiffLines[0].left.discussions[1].id).toEqual(2); + + expect(state.diffFiles[0].highlightedDiffLines[0].discussions.length).toEqual(2); + expect(state.diffFiles[0].highlightedDiffLines[0].discussions[1].id).toEqual(2); + }); + }); + + describe('REMOVE_LINE_DISCUSSIONS', () => { + it('should remove the existing discussions on the given line', () => { + const state = { + diffFiles: [ + { + fileHash: 'ABC', + parallelDiffLines: [ + { + left: { + lineCode: 'ABC_1', + discussions: [ + { + id: 1, + line_code: 'ABC_1', + }, + { + id: 2, + line_code: 'ABC_1', + }, + ], + }, + right: { + lineCode: 'ABC_1', + discussions: [], + }, + }, + ], + highlightedDiffLines: [ + { + lineCode: 'ABC_1', + discussions: [ + { + id: 1, + line_code: 'ABC_1', + }, + { + id: 2, + line_code: 'ABC_1', + }, + ], + }, + ], + }, + ], + }; + + mutations[types.REMOVE_LINE_DISCUSSIONS_FOR_FILE](state, { + fileHash: 'ABC', + lineCode: 'ABC_1', + }); + expect(state.diffFiles[0].parallelDiffLines[0].left.discussions.length).toEqual(0); + expect(state.diffFiles[0].highlightedDiffLines[0].discussions.length).toEqual(0); + }); + }); }); diff --git a/spec/javascripts/diffs/store/utils_spec.js b/spec/javascripts/diffs/store/utils_spec.js index 32136d9ebff..4b5cf450c68 100644 --- a/spec/javascripts/diffs/store/utils_spec.js +++ b/spec/javascripts/diffs/store/utils_spec.js @@ -179,32 +179,126 @@ describe('DiffsStoreUtils', () => { describe('trimFirstCharOfLineContent', () => { it('trims the line when it starts with a space', () => { - expect(utils.trimFirstCharOfLineContent({ richText: ' diff' })).toEqual({ richText: 'diff' }); + expect(utils.trimFirstCharOfLineContent({ richText: ' diff' })).toEqual({ + discussions: [], + richText: 'diff', + }); }); it('trims the line when it starts with a +', () => { - expect(utils.trimFirstCharOfLineContent({ richText: '+diff' })).toEqual({ richText: 'diff' }); + expect(utils.trimFirstCharOfLineContent({ richText: '+diff' })).toEqual({ + discussions: [], + richText: 'diff', + }); }); it('trims the line when it starts with a -', () => { - expect(utils.trimFirstCharOfLineContent({ richText: '-diff' })).toEqual({ richText: 'diff' }); + expect(utils.trimFirstCharOfLineContent({ richText: '-diff' })).toEqual({ + discussions: [], + richText: 'diff', + }); }); it('does not trims the line when it starts with a letter', () => { - expect(utils.trimFirstCharOfLineContent({ richText: 'diff' })).toEqual({ richText: 'diff' }); + expect(utils.trimFirstCharOfLineContent({ richText: 'diff' })).toEqual({ + discussions: [], + richText: 'diff', + }); }); it('does not modify the provided object', () => { const lineObj = { + discussions: [], richText: ' diff', }; utils.trimFirstCharOfLineContent(lineObj); - expect(lineObj).toEqual({ richText: ' diff' }); + expect(lineObj).toEqual({ discussions: [], richText: ' diff' }); }); it('handles a undefined or null parameter', () => { - expect(utils.trimFirstCharOfLineContent()).toEqual({}); + expect(utils.trimFirstCharOfLineContent()).toEqual({ discussions: [] }); + }); + }); + + describe('prepareDiffData', () => { + it('sets the renderIt and collapsed attribute on files', () => { + const preparedDiff = { diffFiles: [getDiffFileMock()] }; + utils.prepareDiffData(preparedDiff); + + const firstParallelDiffLine = preparedDiff.diffFiles[0].parallelDiffLines[2]; + expect(firstParallelDiffLine.left.discussions.length).toBe(0); + expect(firstParallelDiffLine.left).not.toHaveAttr('text'); + expect(firstParallelDiffLine.right.discussions.length).toBe(0); + expect(firstParallelDiffLine.right).not.toHaveAttr('text'); + const firstParallelChar = firstParallelDiffLine.right.richText.charAt(0); + expect(firstParallelChar).not.toBe(' '); + expect(firstParallelChar).not.toBe('+'); + expect(firstParallelChar).not.toBe('-'); + + const checkLine = preparedDiff.diffFiles[0].highlightedDiffLines[0]; + expect(checkLine.discussions.length).toBe(0); + expect(checkLine).not.toHaveAttr('text'); + const firstChar = checkLine.richText.charAt(0); + expect(firstChar).not.toBe(' '); + expect(firstChar).not.toBe('+'); + expect(firstChar).not.toBe('-'); + + expect(preparedDiff.diffFiles[0].renderIt).toBeTruthy(); + expect(preparedDiff.diffFiles[0].collapsed).toBeFalsy(); + }); + }); + + describe('isDiscussionApplicableToLine', () => { + const diffPosition = { + baseSha: 'ed13df29948c41ba367caa757ab3ec4892509910', + headSha: 'b921914f9a834ac47e6fd9420f78db0f83559130', + newLine: null, + newPath: '500-lines-4.txt', + oldLine: 5, + oldPath: '500-lines-4.txt', + startSha: 'ed13df29948c41ba367caa757ab3ec4892509910', + }; + + const wrongDiffPosition = { + baseSha: 'wrong', + headSha: 'wrong', + newLine: null, + newPath: '500-lines-4.txt', + oldLine: 5, + oldPath: '500-lines-4.txt', + startSha: 'wrong', + }; + + const discussions = { + upToDateDiscussion1: { + original_position: { + formatter: diffPosition, + }, + position: { + formatter: wrongDiffPosition, + }, + }, + outDatedDiscussion1: { + original_position: { + formatter: wrongDiffPosition, + }, + position: { + formatter: wrongDiffPosition, + }, + }, + }; + + it('returns true when the discussion is up to date', () => { + expect( + utils.isDiscussionApplicableToLine(discussions.upToDateDiscussion1, diffPosition), + ).toBe(true); + }); + + it('returns false when the discussion is not up to date', () => { + expect( + utils.isDiscussionApplicableToLine(discussions.outDatedDiscussion1, diffPosition), + ).toBe(false); }); }); }); diff --git a/spec/javascripts/lazy_loader_spec.js b/spec/javascripts/lazy_loader_spec.js index 1d81e4e2d1a..c177d79b9e0 100644 --- a/spec/javascripts/lazy_loader_spec.js +++ b/spec/javascripts/lazy_loader_spec.js @@ -2,10 +2,10 @@ import LazyLoader from '~/lazy_loader'; let lazyLoader = null; -describe('LazyLoader', function () { +describe('LazyLoader', function() { preloadFixtures('issues/issue_with_comment.html.raw'); - beforeEach(function () { + beforeEach(function() { loadFixtures('issues/issue_with_comment.html.raw'); lazyLoader = new LazyLoader({ observerNode: 'body', @@ -13,8 +13,8 @@ describe('LazyLoader', function () { // Doing everything that happens normally in onload lazyLoader.loadCheck(); }); - describe('behavior', function () { - it('should copy value from data-src to src for img 1', function (done) { + describe('behavior', function() { + it('should copy value from data-src to src for img 1', function(done) { const img = document.querySelectorAll('img[data-src]')[0]; const originalDataSrc = img.getAttribute('data-src'); img.scrollIntoView(); @@ -26,7 +26,7 @@ describe('LazyLoader', function () { }, 100); }); - it('should lazy load dynamically added data-src images', function (done) { + it('should lazy load dynamically added data-src images', function(done) { const newImg = document.createElement('img'); const testPath = '/img/testimg.png'; newImg.className = 'lazy'; @@ -41,7 +41,7 @@ describe('LazyLoader', function () { }, 100); }); - it('should not alter normal images', function (done) { + it('should not alter normal images', function(done) { const newImg = document.createElement('img'); const testPath = '/img/testimg.png'; newImg.setAttribute('src', testPath); diff --git a/spec/javascripts/lib/utils/mock_data.js b/spec/javascripts/lib/utils/mock_data.js index fd0d62b751f..93d0d6259b9 100644 --- a/spec/javascripts/lib/utils/mock_data.js +++ b/spec/javascripts/lib/utils/mock_data.js @@ -2,4 +2,4 @@ export const faviconDataUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACA export const overlayDataUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAA85JREFUWAntVllIVGEUPv/9b46O41KplYN7PeRkti8TjQlhCUGh3MmeQugpIsGKAi2soIcIooiohxYKK2daqDAlIpIiWwxtQaJcaHE0d5tMrbn37z9XRqfR0TvVW56Hudf//uec72zfEWBCJjIwkYGJDPzvGSD/KgExN3Oi2Q+2DJgSDYQEMwItVGH1iZGmJw/Si1y+/PwVAMYYib22MYc/8hVQFgKDEfYoId0KYzagAQebsos/ewMZoeB9wdffcTYpQSaCTWHKoqSQaDk7zkIt0+aCUR8BelEHrf3dUNv9AcqbnsHtT5UKB/hTASh0SLYjnjb/CIDRJi0XiFAaJOpCD8zLpdb4NB66b1OfelthX815dtdRRfiti2aAXLvVLiMQ6olGyztGDkSo4JGGXk8/QFdGpYzpHG2GBQTDhtgVhPEaVbbVpvI6GJz22rv4TcAfrYI1x7Rj5MWWAppomKFVVb2302SFzUkZHAbkG+0b1+Gh77yNYjrmqnWTrLBLRxdvBWv8qlFujH/kYjJYyvLkj71t78zAUvzMAMnHhpN4zf9UREJhd8omyssxu1IgazQDwDnHUcNuH6vhPIE1fmuBzHt74Hn7W89jWGtcAjoaIDOFrdcMYJBkgOCoaRF0Lj0oglddDbCj6tRvKjphEpgjkzEQs2YAKsNxMzjn3nKurhzK+Ly7xe28ua8TwgMMcHJZnvvT0BPtEEKM4tDJ+C8GvIIk4ylINIXVZ0EUKJxYuh3mhCeokbudl6TtVc88dfBdLwbyaWB6zQCYQJpBYSrDGQxBQ/ZWRM2B+VNmQnVnHWx7elyNuL2/R336co7KyJR8CL9oLgEuFlREevWUkEl6uGwpVEG4FBm0OEf9N10NMgPlvWYAuNVwsWDKvcUNYsHUWTCZ13ysyFEXe6TO6aC8CUr9IiK+A05TQrc8yjwmxARHeeMAPlfQJw+AQRwu0YhL/GDXi9NwufG+S8dYkuYMqIb4SsWthotlNMOUCOM6r+G9cqXxPmd1dqrBav/o1zJy2l5/NUjJA/VORwYuFnOUaTQcPs9wMqwV++Xv8oADxKAcZ8nLPr8AoGW+xR6HSqYk3GodAz2QNj0V+Gr26dT9ASNH5239Pf0gktVNWZca8ZvfAFBprWS6hSu1pqt++Y0PD+WIwDAhIWQGtzvSHDbcodfFUFB9hg1Gjs5LXqIdFL+acFBl+FddqYwdxsWC3I70OvgfUaA65zhq2O2c8VxYcyIGFTVlXegYtvCXANCQZJMobjVcLMjtSK/IcEgyOOe8Ve5w7ryKDefp2P3+C/5ohv8HZmVLAAAAAElFTkSuQmCC'; -export const faviconWithOverlayDataUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAGt0lEQVRYR8WWf3DT5R3H35/vN0lDiCztSuiPAEnTFhSOUamIzFGokwMH55g0E845yjbP6+4qIoiHY6JjnHLeRI6h9jgQpQcD3ImH2u00eHBwjGthKLI1TSm26S8oKYVS0vT7/X52z7ckTUhqC/yx55/kks/zeb+ez6/nIWYm/B8XJQB4SGq6lL+CJA47vvRtvWs2D0nNl/Kf0qBZxx6u23arv0QAAIHivK8BynB4ffa7BgDQXJx/ngGnw+uThgTwP5ZnMocoJAxVxZDVZ+0L5n5WF75TkMafjLdJxpSg2E+gqW1X7zk3rbpaifhLiEBgTv4mEFbpBoTyu01DoDj/dQAv9rvjtdnp/k3Yx9rgAMV5QYCsAAwAgg6vL/1OTy/2BYrzzwLIBWACuNHhrXPG+otGoKaw0JA58kqGJtOFfgPS8yWT4sz88nzj7UIIfz+wd0mRdEZPLMnp2V/8R0+JrhLbBYFHJvwWzBUxYgqYNzhG+zfEhm24MIE5ectBtP0W+y0Or29FcoDifHFSRxwAcMrh9c0YrmisXaA4r0V0U8xvopgDDq9PpCQ+Ag0/zbEbNUNbMiG9fTwkDTsKHpJa2t1Zmiw1AqLg+tMZ+R6WVVtnZ2qP6Ib+FIjh05G3lsDrB4xjUIbRDeM+WZLJYZ4B1rKMzKPm/fdyzs9qg6WT225IMnPcuYjxbPZhn57qaA00zc4/QYT7b1b/wAZmDYSLjsN1WcmiM+6jXz7JTCs1aNPASBjrtrCGOXVBLK9ph72772bc0REZcsQlkEVoOxblhaFBH0Bxi6GBWFNC8gpV0XqYSe/hI85R9o1zxr/QaZbdbmuW9oRzljRrzBRkW9JhMaTgYugKzl35DlXNJ/Fp43FImoZnz7T0ln7bLihM0g85N627vkWPgLrbvYyCvAP1+rRIWETA5QsyQlcJYOCbMRasWpALtljwSsFyeJxFYsoNWqdN1y/ildM78Y/WGjxx8TL+ol3oluy8VupKe7cfoNLdCJkdqEUPOmBJ5ksJoae91mBps5lQ6pkIm20MPiz6A3KsmcNukDe/3Ye3zh3A77Q2XqcGjslLz88i/nB8pkpSoL8nAFSTBpUN4qSxS5KB5jOGUOniCebmzFQcevSN2xKP+Fp7ajt21f8TOxU/5i45JZFS6XwcTB9HxZgUnGTRNgk31x5jet+aGU7jWw+UweOcPeyTxxoqrGL25+UwdjehSvnmOVIqcz4C8y8GAABcQwjnYI5NheikhQWT+EZmDh2ev/l7cz4U2cGmYyg78TYqVH87Kbtd1wFY4hsVQAt14zu2RiDaTUZMf/BHWD35STx37wDv94k1dLeh7MRmvDZ1GR5Inxg17dX6MPnjZfh5X6tGSqXrV2B8ACIx98UNGOlV4CxCuA6zqIeq9FQ8c68bhx7ZiIK06CQdVF+Il3y1Hq03gnDfk4Uj8zbH2T51dCPOtlW39Q+iPTl2VSMfwKPiKw8aTuhgpl1Zdqxzj8PphRWwm21xZjv9VcgYkYb52dP132PFbSYr/la0DpNtrrg9a2oqsKfB2zlwG+4nSe1z7QDjaQBi2Eh6J4QRwimYt43LwOsuB2oX7YLVMCLqTAya3xx/EwZJxtYHy3WhyMkHExebXz3zAbbXfdo7AFBRaMAz1Ypa6XoaoPejKRGteZm6D3SlWVdOcOHo/Lfj2u9aXw+WHNmA00G/DiFEO0Jd+meyk0fIf/+vLfik6Xhj4qN0v7i5HCY1bBQPk+ij9GSzNbzYNdH03kMrscARfzvHQgiBocSFTVHVCrW+u+WrpK9iCIgS1rRK93oG/1GkRJVIup8KMNs1Sw/1rUtALD36ZzRca8XeJDmPtRc18vDn5SCJViYHENY3IZTK3JkE7RAYtpdkp3bAaJeOzN+CsSMTX+wqa7ih9sbVSLI2WV3znihAJYXZPThA7M6KQoM2MniyhUxTioxTpKLMadjx8Jqh5k3S//8d9GOh92XWmP/aXLKvfHgA0ZTklL0jj9m6UR6L5+9bjFWTPLcFIWbCY1+8pHb0drWybJ4aWLQrODyAWJndzoyylNyGg0hL+bV7Ll4rKIWB5CFBxMlLj21SL4W6QjDQjwOL9n4tNt0+AADPfo+UqgXPHJLSJrkso7F6ylLMy56OFMmYACIKblvtQext8Iqp0swyLYiI3zEAbs6Ml3cXv/p3Y+ryq5KcnSKb1Jmj75P7X0Rm/UV0tvO86r/WIhORwszvkmHEehH2WMo7ikDUQUWhoaIG+NNc96Os8eMEmklE2Qy2ANTO0OrA+CwFOFBfsq8pWZ7+B25aDBxvPp+QAAAAAElFTkSuQmCC'; +export const faviconWithOverlayDataUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAGtElEQVRYR8WXf3CT9R3H35/nSdIQIktrCf0RStI0FYRjVBAccxTq5MDBKUoz4ZyjbPO87q4yBsPDMdExTjlvIsdQexyI0oMBeuKhdjsNHhwcMgpjIlublLIm/UlJKZSSJs/z/e6+T5v0CQ22wB/7/pPck8/383l9fj6fEOec8H88NAjAS1LwknsFSVLU8WXd1rtm85LUeKnwGQKzjj3s33azvsEAAEIlnn8ByHL4/Pa7BgAQLCm8QOBOh88vDQkQeMxjMkcQEYKqYsyJWWPhgs/80TsFafzROJtkNIXFfYI0pfXqPeennjqlxPUNikBoTuEmEF+lCRBV3G0aQiWFrwH8d30AWJubGdiEfZzdGqDEEwbICnADQGGHry7zTr0X94IlnnMACggwAWh0+PxOvb5EBGqmTTNkj7ySxWS62C+g5Usm1Zn95YXG24UQ+r5n75Li6Ux4LBkyc7/4t5YSLSr6Lgg9UvBLcKocMEYKON/gGB3YoA/bcGFCczzLQdieLE9bHL66FakBSjzCU0cSAHDa4at7aLhG9XLBEk8zAVnxZxyIEhBy+PwFgwAafpxvNzK5NZUhrX28JA07Cl6SmtvcOUwm4ZAouHj7ad+jMrN1dqb3iG7oS4EYPh2etQS+XiesC8TQ3ZD3yZJsHuUPgbMcI+ej5v3ncv5PasNlk1p7JJnzJL+I0/O5h+u0VCdqIDi78AQRHuirft3hYJzQPvawPydVdPI+/OnTnNNKBjYVXHRa8rFFGeb4w1he0wZ7d/84IXTEhxzxUsgitB2LPFGwvgGUfLSeZUpEXqEqrIdz0nr4iHOUfeOccb/tNMtutzWHPeWcJc0aMxm5lkxYDGloj1zB+Sv/RXXTSXzaeBwSY3j+bHNv2bdtMYCbpHtRkNFd36xFQN3tXkZhvgP1fdPi5kMEXL4oIXKVAA58M8aCVQs84BYLXi5aDq+zGJTqYr+i4PV2vHxmJ/7WUoOn2i/jz6yhW7JjrdSV8U4fQFV+I2Q4UIsedMCSSlcsgp72WtnSajOhzDsBNtsYfFD8e+Rbs4fdIG98uw9vnj+AX7FWvk4NHZOXXphF/INx2SpJIU2L8L4GDAoMwlP9kWSg6awcKVs83tyUnY5Dj75+W8bjutae3o5d9X/HTiWAuUtOS6RUOR8Hp48TxjgU/AMSeKJ1Ej/tMWXG1sxwGt98sBxe5+xhe64XVLiK2Z9XwNgdRLXyzQsC4ENwelIHAFxDBOdh1qdCdNLCoon8RnY+HZ6/+TtzPhTZweAxlJ94C5VqoI2U3a7rACzJjQqgBd24CGscos1kxPQZ38fqSU/jhQkDvN9lrKG7FeUnNuPVKcvwYOb4hGgvi2HSx8vwRKyJkVLl+hk43gdBAcfADBD1cA4RXIdZ1EN1Zjqem+DGoUc2oigjMUlvaV8YL/1qPVpuhOG+JwdH5m1Okn3m6Eacaz3V2jeI9uTbVYY6AKOSKw8MX0MBg2lXjh3r3Hk4s7ASdrMtSWxnoBpZIzIwP3e69lxv3Gay4q/F6zDJ5kq6s6amEnsafJ0Db8P9JKkx1w5wPJuY36IToojgNMzb8rLwmsuB2kW7YDWMSCgTg+YXx9+AQZKxdUaFZiju+a2Mi8uvnH0f2/2f9g4AVE4z4LlTilrlehag9xIpEam4jO4DXfdaV97nwtH5byW137VYD5Yc2YAz4YAGIYx2RLq0z1Sex8l//fUWfBI83jh4Kd1PEuAwqVGjWEwSS+nJJmt0sWu86d0frMQCR/LbWQ8hDAxlXMgUV69Q67ubv0q5FUNAlHKmVLnXE/gfREpUiaQHqAizXbO0UN98BMTSo39Cw7UW7E2Rc728qJGHP68ASbQyNYCQTkAUzCSwQ+CwvSjnsQPGLOnI/C0YO3Lwxq5yhhtqb1KNpGqT1TXvigJU0jh33xpAf7NymoGNDJ9sJtPkYuNkqTh7KnY8vGaoeZPy93+GA1joe4kzzv/SVLqvYngA/dFgVfnlb8tjtm6Ux+I39y/Gqone24IQM+GxL15UO3q7WrhsnhJatCs8PAC9md3OrPK0goaDyEj7uXsuXi0qg4HkIUGE52XHNqmXIl0RGOiHoUV7xb+v5K14SC39At79Ximdhc8ekjImuiyjsXryUszLnY40yThIhSi4bbUHsbfBJ6ZKE5dpQdz4HQOgf2a8tLvklY+M6cuvSnJummxSZ46+X+7biMzaRnSu84IauNYsE5HCOX+HDCPWi7DrKW8/BTcVZ2UN8Me57kc5448TaCYR5XJwC0BtHMwPjs/SgAP1pfuCqSL8Pxhr/wunLWAOAAAAAElFTkSuQmCC'; diff --git a/spec/javascripts/lib/utils/text_utility_spec.js b/spec/javascripts/lib/utils/text_utility_spec.js index d60485b1308..ac3270baef5 100644 --- a/spec/javascripts/lib/utils/text_utility_spec.js +++ b/spec/javascripts/lib/utils/text_utility_spec.js @@ -63,6 +63,12 @@ describe('text_utility', () => { }); }); + describe('slugifyWithHyphens', () => { + it('should replaces whitespaces with hyphens and convert to lower case', () => { + expect(textUtils.slugifyWithHyphens('My Input String')).toEqual('my-input-string'); + }); + }); + describe('stripHtml', () => { it('replaces html tag with the default replacement', () => { expect(textUtils.stripHtml('This is a text with <p>html</p>.')).toEqual( diff --git a/spec/javascripts/projects/project_new_spec.js b/spec/javascripts/projects/project_new_spec.js index 84515d2bf97..dace834a3c8 100644 --- a/spec/javascripts/projects/project_new_spec.js +++ b/spec/javascripts/projects/project_new_spec.js @@ -4,12 +4,14 @@ import projectNew from '~/projects/project_new'; describe('New Project', () => { let $projectImportUrl; let $projectPath; + let $projectName; beforeEach(() => { setFixtures(` <div class='toggle-import-form'> <div class='import-url-data'> <input id="project_import_url" /> + <input id="project_name" /> <input id="project_path" /> </div> </div> @@ -17,6 +19,7 @@ describe('New Project', () => { $projectImportUrl = $('#project_import_url'); $projectPath = $('#project_path'); + $projectName = $('#project_name'); }); describe('deriveProjectPathFromUrl', () => { @@ -129,4 +132,31 @@ describe('New Project', () => { }); }); }); + + describe('deriveSlugFromProjectName', () => { + beforeEach(() => { + projectNew.bindEvents(); + $projectName.val('').keyup(); + }); + + it('converts project name to lower case and dash-limited slug', () => { + const dummyProjectName = 'My Awesome Project'; + + $projectName.val(dummyProjectName); + + projectNew.onProjectNameChange($projectName, $projectPath); + + expect($projectPath.val()).toEqual('my-awesome-project'); + }); + + it('does not add additional dashes in the slug if the project name already contains dashes', () => { + const dummyProjectName = 'My-Dash-Delimited Awesome Project'; + + $projectName.val(dummyProjectName); + + projectNew.onProjectNameChange($projectName, $projectPath); + + expect($projectPath.val()).toEqual('my-dash-delimited-awesome-project'); + }); + }); }); diff --git a/spec/lib/banzai/pipeline/gfm_pipeline_spec.rb b/spec/lib/banzai/pipeline/gfm_pipeline_spec.rb index 75413596431..df24cef0b8b 100644 --- a/spec/lib/banzai/pipeline/gfm_pipeline_spec.rb +++ b/spec/lib/banzai/pipeline/gfm_pipeline_spec.rb @@ -87,4 +87,22 @@ describe Banzai::Pipeline::GfmPipeline do end end end + + describe 'markdown link or image urls having spaces' do + let(:project) { create(:project, :public) } + + it 'rewrites links with spaces in url' do + markdown = "[Link to Page](page slug)" + output = described_class.to_html(markdown, project: project) + + expect(output).to include("href=\"page%20slug\"") + end + + it 'rewrites images with spaces in url' do + markdown = "![My Image](test image.png)" + output = described_class.to_html(markdown, project: project) + + expect(output).to include("src=\"test%20image.png\"") + end + end end diff --git a/spec/lib/gitlab/import_export/model_configuration_spec.rb b/spec/lib/gitlab/import_export/model_configuration_spec.rb index 5cb8f2589c8..2e28f978c3a 100644 --- a/spec/lib/gitlab/import_export/model_configuration_spec.rb +++ b/spec/lib/gitlab/import_export/model_configuration_spec.rb @@ -16,14 +16,30 @@ describe 'Import/Export model configuration' do # - User, Author... Models we do not care about for checking models names.flatten.uniq - %w(milestones labels user author) + ['project'] end + let(:ce_models_yml) { 'spec/lib/gitlab/import_export/all_models.yml' } + let(:ce_models_hash) { YAML.load_file(ce_models_yml) } + + let(:ee_models_yml) { 'ee/spec/lib/gitlab/import_export/all_models.yml' } + let(:ee_models_hash) { File.exist?(ee_models_yml) ? YAML.load_file(ee_models_yml) : {} } - let(:all_models_yml) { 'spec/lib/gitlab/import_export/all_models.yml' } - let(:all_models) { YAML.load_file(all_models_yml) } let(:current_models) { setup_models } + let(:all_models_hash) do + all_models_hash = ce_models_hash.dup + + all_models_hash.each do |model, associations| + associations.concat(ee_models_hash[model] || []) + end + + ee_models_hash.each do |model, associations| + all_models_hash[model] ||= associations + end + + all_models_hash + end it 'has no new models' do model_names.each do |model_name| - new_models = Array(current_models[model_name]) - Array(all_models[model_name]) + new_models = Array(current_models[model_name]) - Array(all_models_hash[model_name]) expect(new_models).to be_empty, failure_message(model_name.classify, new_models) end end @@ -31,27 +47,21 @@ describe 'Import/Export model configuration' do # List of current models between models, in the format of # {model: [model_2, model3], ...} def setup_models - all_models_hash = {} - - model_names.each do |model_name| - model_class = relation_class_for_name(model_name) - - all_models_hash[model_name] = associations_for(model_class) - ['project'] + model_names.each_with_object({}) do |model_name, hash| + hash[model_name] = associations_for(relation_class_for_name(model_name)) - ['project'] end - - all_models_hash end def failure_message(parent_model_name, new_models) - <<-MSG + <<~MSG New model(s) <#{new_models.join(',')}> have been added, related to #{parent_model_name}, which is exported by the Import/Export feature. - If you think this model should be included in the export, please add it to IMPORT_EXPORT_CONFIG. - Definitely add it to MODELS_JSON to signal that you've handled this error and to prevent it from showing up in the future. + If you think this model should be included in the export, please add it to `#{Gitlab::ImportExport.config_file}`. - MODELS_JSON: #{File.expand_path(all_models_yml)} - IMPORT_EXPORT_CONFIG: #{Gitlab::ImportExport.config_file} + Definitely add it to `#{File.expand_path(ce_models_yml)}` + #{"or `#{File.expand_path(ee_models_yml)}` if the model/associations are EE-specific\n" if ee_models_hash.any?} + to signal that you've handled this error and to prevent it from showing up in the future. MSG end end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index cb844cd2102..dfe2de71a76 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -3983,6 +3983,40 @@ describe Project do end end + describe '#update_root_ref' do + let(:project) { create(:project, :repository) } + + it 'updates the default branch when HEAD has changed' do + stub_find_remote_root_ref(project, ref: 'feature') + + expect { project.update_root_ref('origin') } + .to change { project.default_branch } + .from('master') + .to('feature') + end + + it 'does not update the default branch when HEAD does not change' do + stub_find_remote_root_ref(project, ref: 'master') + + expect { project.update_root_ref('origin') } + .not_to change { project.default_branch } + end + + it 'does not update the default branch when HEAD does not exist' do + stub_find_remote_root_ref(project, ref: 'foo') + + expect { project.update_root_ref('origin') } + .not_to change { project.default_branch } + end + + def stub_find_remote_root_ref(project, ref:) + allow(project.repository) + .to receive(:find_remote_root_ref) + .with('origin') + .and_return(ref) + end + end + def rugged_config Gitlab::GitalyClient::StorageSettings.allow_disk_access do project.repository.rugged.config diff --git a/spec/services/projects/container_repository/destroy_service_spec.rb b/spec/services/projects/container_repository/destroy_service_spec.rb new file mode 100644 index 00000000000..307ccc88865 --- /dev/null +++ b/spec/services/projects/container_repository/destroy_service_spec.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Projects::ContainerRepository::DestroyService do + set(:user) { create(:user) } + set(:project) { create(:project, :private) } + + subject { described_class.new(project, user) } + + before do + stub_container_registry_config(enabled: true) + end + + context 'when user does not have access to registry' do + let!(:repository) { create(:container_repository, :root, project: project) } + + it 'does not delete a repository' do + expect { subject.execute(repository) }.not_to change { ContainerRepository.all.count } + end + end + + context 'when user has access to registry' do + before do + project.add_developer(user) + end + + context 'when root container repository exists' do + let!(:repository) { create(:container_repository, :root, project: project) } + + before do + stub_container_registry_tags(repository: :any, tags: []) + end + + it 'deletes the repository' do + expect { described_class.new(project, user).execute(repository) }.to change { ContainerRepository.all.count }.by(-1) + end + end + end +end diff --git a/spec/services/projects/update_remote_mirror_service_spec.rb b/spec/services/projects/update_remote_mirror_service_spec.rb index 96e8a80b334..56a36432462 100644 --- a/spec/services/projects/update_remote_mirror_service_spec.rb +++ b/spec/services/projects/update_remote_mirror_service_spec.rb @@ -1,107 +1,118 @@ require 'spec_helper' describe Projects::UpdateRemoteMirrorService do - set(:project) { create(:project, :repository) } - let(:owner) { project.owner } + let(:project) { create(:project, :repository) } let(:remote_project) { create(:forked_project_with_submodules) } - let(:repository) { project.repository } - let(:raw_repository) { repository.raw } let(:remote_mirror) { project.remote_mirrors.create!(url: remote_project.http_url_to_repo, enabled: true, only_protected_branches: false) } + let(:remote_name) { remote_mirror.remote_name } - subject { described_class.new(project, project.creator) } + subject(:service) { described_class.new(project, project.creator) } describe "#execute" do before do - repository.add_branch(owner, 'existing-branch', 'master') + project.repository.add_branch(project.owner, 'existing-branch', 'master') allow(remote_mirror).to receive(:update_repository).and_return(true) end + it "ensures the remote exists" do + stub_fetch_remote(project, remote_name: remote_name) + stub_find_remote_root_ref(project, remote_name: remote_name) + + expect(remote_mirror).to receive(:ensure_remote!) + + service.execute(remote_mirror) + end + it "fetches the remote repository" do - expect(remote_mirror).to receive(:ensure_remote!).and_call_original - expect(repository).to receive(:fetch_remote).with(remote_mirror.remote_name, no_tags: true) do - sync_remote(repository, remote_mirror.remote_name, local_branch_names) - end + stub_find_remote_root_ref(project, remote_name: remote_name) + + expect(project.repository) + .to receive(:fetch_remote) + .with(remote_mirror.remote_name, no_tags: true) + + service.execute(remote_mirror) + end + + it "updates the default branch when HEAD has changed" do + stub_fetch_remote(project, remote_name: remote_name) + stub_find_remote_root_ref(project, remote_name: remote_name, ref: "existing-branch") - subject.execute(remote_mirror) + expect { service.execute(remote_mirror) } + .to change { project.default_branch } + .from("master") + .to("existing-branch") end - it "succeeds" do - allow(repository).to receive(:fetch_remote) { sync_remote(repository, remote_mirror.remote_name, local_branch_names) } + it "does not update the default branch when HEAD does not change" do + stub_fetch_remote(project, remote_name: remote_name) + stub_find_remote_root_ref(project, remote_name: remote_name, ref: "master") + + expect { service.execute(remote_mirror) }.not_to change { project.default_branch } + end - result = subject.execute(remote_mirror) + it "returns success when updated succeeds" do + stub_fetch_remote(project, remote_name: remote_name) + stub_find_remote_root_ref(project, remote_name: remote_name) + + result = service.execute(remote_mirror) expect(result[:status]).to eq(:success) end context 'when syncing all branches' do it "push all the branches the first time" do - allow(repository).to receive(:fetch_remote) + stub_fetch_remote(project, remote_name: remote_name) + stub_find_remote_root_ref(project, remote_name: remote_name) expect(remote_mirror).to receive(:update_repository).with({}) - subject.execute(remote_mirror) + service.execute(remote_mirror) end end context 'when only syncing protected branches' do - let(:unprotected_branch_name) { 'existing-branch' } - let(:protected_branch_name) do - project.repository.branch_names.find { |n| n != unprotected_branch_name } - end - let!(:protected_branch) do - create(:protected_branch, project: project, name: protected_branch_name) - end - - before do - project.reload + it "sync updated protected branches" do + stub_fetch_remote(project, remote_name: remote_name) + stub_find_remote_root_ref(project, remote_name: remote_name) + protected_branch = create_protected_branch(project) remote_mirror.only_protected_branches = true - end - it "sync updated protected branches" do - allow(repository).to receive(:fetch_remote) - expect(remote_mirror).to receive(:update_repository).with(only_branches_matching: [protected_branch_name]) + expect(remote_mirror) + .to receive(:update_repository) + .with(only_branches_matching: [protected_branch.name]) - subject.execute(remote_mirror) + service.execute(remote_mirror) end - end - end - def sync_remote(repository, remote_name, local_branch_names) - local_branch_names.each do |branch| - commit = repository.commit(branch) - repository.write_ref("refs/remotes/#{remote_name}/#{branch}", commit.id) if commit + def create_protected_branch(project) + branch_name = project.repository.branch_names.find { |n| n != 'existing-branch' } + create(:protected_branch, project: project, name: branch_name) + end end end - def update_remote_branch(repository, remote_name, branch) - masterrev = repository.commit('master').id - - repository.write_ref("refs/remotes/#{remote_name}/#{branch}", masterrev, force: true) - repository.expire_branches_cache + def stub_find_remote_root_ref(project, ref: 'master', remote_name:) + allow(project.repository) + .to receive(:find_remote_root_ref) + .with(remote_name) + .and_return(ref) end - def update_branch(repository, branch) - masterrev = repository.commit('master').id - - repository.write_ref("refs/heads/#{branch}", masterrev, force: true) - repository.expire_branches_cache + def stub_fetch_remote(project, remote_name:) + allow(project.repository) + .to receive(:fetch_remote) + .with(remote_name, no_tags: true) { fetch_remote(project.repository, remote_name) } end - def generate_tags(repository, *tag_names) - tag_names.each_with_object([]) do |name, tags| - tag = repository.find_tag(name) - target = tag.try(:target) - target_commit = tag.try(:dereferenced_target) - tags << Gitlab::Git::Tag.new(repository.raw_repository, { - name: name, - target: target, - target_commit: target_commit - }) + def fetch_remote(repository, remote_name) + local_branch_names(repository).each do |branch| + commit = repository.commit(branch) + repository.write_ref("refs/remotes/#{remote_name}/#{branch}", commit.id) if commit end end - def local_branch_names + def local_branch_names(repository) branch_names = repository.branches.map(&:name) # we want the protected branch to be pushed first branch_names.unshift(branch_names.delete('master')) diff --git a/spec/services/quick_actions/interpret_service_spec.rb b/spec/services/quick_actions/interpret_service_spec.rb index bf1c157c4a2..06cad9c00d2 100644 --- a/spec/services/quick_actions/interpret_service_spec.rb +++ b/spec/services/quick_actions/interpret_service_spec.rb @@ -272,6 +272,28 @@ describe QuickActions::InterpretService do end end + shared_examples 'lock command' do + let(:issue) { create(:issue, project: project, discussion_locked: false) } + let(:merge_request) { create(:merge_request, source_project: project, discussion_locked: false) } + + it 'returns discussion_locked: true if content contains /lock' do + _, updates = service.execute(content, issuable) + + expect(updates).to eq(discussion_locked: true) + end + end + + shared_examples 'unlock command' do + let(:issue) { create(:issue, project: project, discussion_locked: true) } + let(:merge_request) { create(:merge_request, source_project: project, discussion_locked: true) } + + it 'returns discussion_locked: true if content contains /unlock' do + _, updates = service.execute(content, issuable) + + expect(updates).to eq(discussion_locked: false) + end + end + shared_examples 'empty command' do it 'populates {} if content contains an unsupported command' do _, updates = service.execute(content, issuable) @@ -786,6 +808,26 @@ describe QuickActions::InterpretService do let(:issuable) { issue } end + it_behaves_like 'lock command' do + let(:content) { '/lock' } + let(:issuable) { issue } + end + + it_behaves_like 'lock command' do + let(:content) { '/lock' } + let(:issuable) { merge_request } + end + + it_behaves_like 'unlock command' do + let(:content) { '/unlock' } + let(:issuable) { issue } + end + + it_behaves_like 'unlock command' do + let(:content) { '/unlock' } + let(:issuable) { merge_request } + end + context '/todo' do let(:content) { '/todo' } @@ -961,6 +1003,16 @@ describe QuickActions::InterpretService do let(:content) { '/duplicate #{issue.to_reference}' } let(:issuable) { issue } end + + it_behaves_like 'empty command' do + let(:content) { '/lock' } + let(:issuable) { issue } + end + + it_behaves_like 'empty command' do + let(:content) { '/unlock' } + let(:issuable) { issue } + end end context '/award command' do diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb index d5d750e182b..f4b7cb8c90a 100644 --- a/spec/services/system_note_service_spec.rb +++ b/spec/services/system_note_service_spec.rb @@ -249,6 +249,30 @@ describe SystemNoteService do end end + describe '.change_due_date' do + subject { described_class.change_due_date(noteable, project, author, due_date) } + + let(:due_date) { Date.today } + + it_behaves_like 'a system note' do + let(:action) { 'due_date' } + end + + context 'when due date added' do + it 'sets the note text' do + expect(subject.note).to eq "changed due date to #{Date.today.to_s(:long)}" + end + end + + context 'when due date removed' do + let(:due_date) { nil } + + it 'sets the note text' do + expect(subject.note).to eq 'removed due date' + end + end + end + describe '.change_status' do subject { described_class.change_status(noteable, project, author, status, source) } diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index c4bb1c13f2e..d1337325973 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -135,6 +135,10 @@ RSpec.configure do |config| Fog.unmock! if Fog.mock? end + config.after(:example) do + Gitlab::CurrentSettings.clear_in_memory_application_settings! + end + config.before(:example, :mailer) do reset_delivered_emails! end diff --git a/spec/support/features/issuable_slash_commands_shared_examples.rb b/spec/support/features/issuable_quick_actions_shared_examples.rb index 9b44c532ff6..846e697eb96 100644 --- a/spec/support/features/issuable_slash_commands_shared_examples.rb +++ b/spec/support/features/issuable_quick_actions_shared_examples.rb @@ -55,7 +55,7 @@ shared_examples 'issuable record that supports quick actions in its description describe "note on #{issuable_type}", :js do before do - visit public_send("namespace_project_#{issuable_type}_path", project.namespace, project, issuable) + visit public_send("project_#{issuable_type}_path", project, issuable) end context 'with a note containing commands' do @@ -121,7 +121,7 @@ shared_examples 'issuable record that supports quick actions in its description gitlab_sign_out gitlab_sign_in(guest) - visit public_send("namespace_project_#{issuable_type}_path", project.namespace, project, issuable) + visit public_send("project_#{issuable_type}_path", project, issuable) end it "does not close the #{issuable_type}" do @@ -158,7 +158,7 @@ shared_examples 'issuable record that supports quick actions in its description gitlab_sign_out gitlab_sign_in(guest) - visit public_send("namespace_project_#{issuable_type}_path", project.namespace, project, issuable) + visit public_send("project_#{issuable_type}_path", project, issuable) end it "does not reopen the #{issuable_type}" do @@ -190,7 +190,7 @@ shared_examples 'issuable record that supports quick actions in its description gitlab_sign_out gitlab_sign_in(guest) - visit public_send("namespace_project_#{issuable_type}_path", project.namespace, project, issuable) + visit public_send("project_#{issuable_type}_path", project, issuable) end it "does not change the #{issuable_type} title" do @@ -285,13 +285,87 @@ shared_examples 'issuable record that supports quick actions in its description expect(issuable.reload.assignees).to eq [maintainer] end end + + context "with a note locking the #{issuable_type} discussion" do + before do + issuable.update(discussion_locked: false) + expect(issuable).not_to be_discussion_locked + end + + context "when current user can lock #{issuable_type} discussion" do + it "locks the #{issuable_type} discussion" do + add_note("/lock") + + expect(page).not_to have_content '/lock' + expect(page).to have_content 'Commands applied' + + expect(issuable.reload).to be_discussion_locked + end + end + + context "when current user cannot lock #{issuable_type}" do + before do + guest = create(:user) + project.add_guest(guest) + + gitlab_sign_out + sign_in(guest) + visit public_send("project_#{issuable_type}_path", project, issuable) + end + + it "does not lock the #{issuable_type} discussion" do + add_note("/lock") + + expect(page).not_to have_content 'Commands applied' + + expect(issuable).not_to be_discussion_locked + end + end + end + + context "with a note unlocking the #{issuable_type} discussion" do + before do + issuable.update(discussion_locked: true) + expect(issuable).to be_discussion_locked + end + + context "when current user can unlock #{issuable_type} discussion" do + it "unlocks the #{issuable_type} discussion" do + add_note("/unlock") + + expect(page).not_to have_content '/unlock' + expect(page).to have_content 'Commands applied' + + expect(issuable.reload).not_to be_discussion_locked + end + end + + context "when current user cannot unlock #{issuable_type}" do + before do + guest = create(:user) + project.add_guest(guest) + + gitlab_sign_out + sign_in(guest) + visit public_send("project_#{issuable_type}_path", project, issuable) + end + + it "does not unlock the #{issuable_type} discussion" do + add_note("/unlock") + + expect(page).not_to have_content 'Commands applied' + + expect(issuable).to be_discussion_locked + end + end + end end describe "preview of note on #{issuable_type}", :js do it 'removes quick actions from note and explains them' do create(:user, username: 'bob') - visit public_send("namespace_project_#{issuable_type}_path", project.namespace, project, issuable) + visit public_send("project_#{issuable_type}_path", project, issuable) page.within('.js-main-target-form') do fill_in 'note[note]', with: "Awesome!\n/assign @bob " diff --git a/spec/support/shared_examples/instance_statistics_controllers_shared_examples.rb b/spec/support/shared_examples/instance_statistics_controllers_shared_examples.rb index 5334af841e1..8ea307c7c61 100644 --- a/spec/support/shared_examples/instance_statistics_controllers_shared_examples.rb +++ b/spec/support/shared_examples/instance_statistics_controllers_shared_examples.rb @@ -5,6 +5,8 @@ shared_examples 'instance statistics availability' do before do sign_in(user) + + stub_application_setting(usage_ping_enabled: true) end describe 'GET #index' do diff --git a/spec/support/sidekiq.rb b/spec/support/sidekiq.rb index d143014692d..6c4e11910d3 100644 --- a/spec/support/sidekiq.rb +++ b/spec/support/sidekiq.rb @@ -1,7 +1,27 @@ require 'sidekiq/testing/inline' +# If Sidekiq::Testing.inline! is used, SQL transactions done inside +# Sidekiq worker are included in the SQL query limit (in a real +# deployment sidekiq worker is executed separately). To avoid +# increasing SQL limit counter, the request is marked as whitelisted +# during Sidekiq block +class DisableQueryLimit + def call(worker_instance, msg, queue) + transaction = Gitlab::QueryLimiting::Transaction.current + + if !transaction.respond_to?(:whitelisted) || transaction.whitelisted + yield + else + transaction.whitelisted = true + yield + transaction.whitelisted = false + end + end +end + Sidekiq::Testing.server_middleware do |chain| chain.add Gitlab::SidekiqStatus::ServerMiddleware + chain.add DisableQueryLimit end RSpec.configure do |config| diff --git a/spec/workers/delete_container_repository_worker_spec.rb b/spec/workers/delete_container_repository_worker_spec.rb new file mode 100644 index 00000000000..8c40611a959 --- /dev/null +++ b/spec/workers/delete_container_repository_worker_spec.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe DeleteContainerRepositoryWorker do + let(:registry) { create(:container_repository) } + let(:project) { registry.project } + let(:user) { project.owner } + + subject { described_class.new } + + describe '#perform' do + it 'executes the destroy service' do + service = instance_double(Projects::ContainerRepository::DestroyService) + expect(service).to receive(:execute) + expect(Projects::ContainerRepository::DestroyService).to receive(:new).with(project, user).and_return(service) + + subject.perform(user.id, registry.id) + end + + it 'does not raise error when user could not be found' do + expect do + subject.perform(-1, registry.id) + end.not_to raise_error + end + + it 'does not raise error when registry could not be found' do + expect do + subject.perform(user.id, -1) + end.not_to raise_error + end + end +end diff --git a/vendor/Dockerfile/Node-alpine.Dockerfile b/vendor/Dockerfile/Node-alpine.Dockerfile index 5b9b495644a..24f92dd92cd 100644 --- a/vendor/Dockerfile/Node-alpine.Dockerfile +++ b/vendor/Dockerfile/Node-alpine.Dockerfile @@ -1,15 +1,17 @@ -FROM node:8.11-alpine +FROM node:10.6-alpine -WORKDIR /usr/src/app +# Uncomment if use of `process.dlopen` is necessary +# apk add --no-cache libc6-compat + +ENV PORT 8080 +EXPOSE 8080 # replace this with your application's default port, if necessary -ARG NODE_ENV +ARG NODE_ENV=production ENV NODE_ENV $NODE_ENV -COPY package.json /usr/src/app/ +WORKDIR /usr/src/app +COPY package.json . RUN npm install +COPY . . -COPY . /usr/src/app - -# replace this with your application's default port -EXPOSE 8888 CMD [ "npm", "start" ] diff --git a/vendor/Dockerfile/OpenJDK.Dockerfile b/vendor/Dockerfile/OpenJDK.Dockerfile index 8a2ae62d93b..c68420b453a 100644 --- a/vendor/Dockerfile/OpenJDK.Dockerfile +++ b/vendor/Dockerfile/OpenJDK.Dockerfile @@ -1,8 +1,12 @@ -FROM openjdk:9 +FROM maven:3.5-jdk-11 as BUILD -COPY . /usr/src/myapp -WORKDIR /usr/src/myapp +COPY . /usr/src/app +RUN mvn --batch-mode -f /usr/src/app/pom.xml clean package -RUN javac Main.java +FROM openjdk:11-jdk +ENV PORT 4567 +EXPOSE 4567 +COPY --from=BUILD /usr/src/app/target /opt/target +WORKDIR /opt/target -CMD ["java", "Main"] +CMD ["/bin/bash", "-c", "find -type f -name '*-with-dependencies.jar' | xargs java -jar"] diff --git a/vendor/Dockerfile/Ruby-alpine.Dockerfile b/vendor/Dockerfile/Ruby-alpine.Dockerfile index dffe9a65116..0f748d84b5d 100644 --- a/vendor/Dockerfile/Ruby-alpine.Dockerfile +++ b/vendor/Dockerfile/Ruby-alpine.Dockerfile @@ -7,21 +7,21 @@ RUN apk --no-cache add nodejs postgresql-client tzdata # throw errors if Gemfile has been modified since Gemfile.lock RUN bundle config --global frozen 1 -RUN mkdir -p /usr/src/app WORKDIR /usr/src/app -COPY Gemfile Gemfile.lock /usr/src/app/ +COPY Gemfile Gemfile.lock . # Install build dependencies - required for gems with native dependencies RUN apk add --no-cache --virtual build-deps build-base postgresql-dev && \ bundle install && \ apk del build-deps -COPY . /usr/src/app +COPY . . # For Sinatra #EXPOSE 4567 #CMD ["ruby", "./config.rb"] # For Rails +ENV PORT 3000 EXPOSE 3000 CMD ["bundle", "exec", "rails", "server"] diff --git a/vendor/gitignore/Global/Diff.gitignore b/vendor/gitignore/Global/Diff.gitignore new file mode 100644 index 00000000000..59491b4440c --- /dev/null +++ b/vendor/gitignore/Global/Diff.gitignore @@ -0,0 +1,2 @@ +*.patch +*.diff diff --git a/vendor/gitignore/Global/JetBrains.gitignore b/vendor/gitignore/Global/JetBrains.gitignore index 0d95b087f19..343be1a3b8e 100644 --- a/vendor/gitignore/Global/JetBrains.gitignore +++ b/vendor/gitignore/Global/JetBrains.gitignore @@ -8,6 +8,9 @@ .idea/**/dictionaries .idea/**/shelf +# Generated files +.idea/**/contentModel.xml + # Sensitive or high-churn files .idea/**/dataSources/ .idea/**/dataSources.ids diff --git a/vendor/gitignore/Global/MicrosoftOffice.gitignore b/vendor/gitignore/Global/MicrosoftOffice.gitignore index 0c203662d39..ddcc9cf6e38 100644 --- a/vendor/gitignore/Global/MicrosoftOffice.gitignore +++ b/vendor/gitignore/Global/MicrosoftOffice.gitignore @@ -3,6 +3,9 @@ # Word temporary ~$*.doc* +# Word Auto Backup File +Backup of *.doc* + # Excel temporary ~$*.xls* diff --git a/vendor/gitignore/KiCad.gitignore b/vendor/gitignore/KiCad.gitignore index 198392e551e..15fdf72ed48 100644 --- a/vendor/gitignore/KiCad.gitignore +++ b/vendor/gitignore/KiCad.gitignore @@ -9,7 +9,6 @@ *~ _autosave-* *.tmp -*-cache.lib *-rescue.lib *-save.pro *-save.kicad_pcb diff --git a/vendor/gitignore/Processing.gitignore b/vendor/gitignore/Processing.gitignore index 85f269a89f6..333c0e0890a 100644 --- a/vendor/gitignore/Processing.gitignore +++ b/vendor/gitignore/Processing.gitignore @@ -1,5 +1,7 @@ .DS_Store applet +application.linux-arm64 +application.linux-armv6hf application.linux32 application.linux64 application.windows32 diff --git a/vendor/gitignore/Python.gitignore b/vendor/gitignore/Python.gitignore index 894a44cc066..6f7a6d9c3d7 100644 --- a/vendor/gitignore/Python.gitignore +++ b/vendor/gitignore/Python.gitignore @@ -38,6 +38,7 @@ pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ +.nox/ .coverage .coverage.* .cache @@ -72,6 +73,10 @@ target/ # Jupyter Notebook .ipynb_checkpoints +# IPython +profile_default/ +ipython_config.py + # pyenv .python-version @@ -102,3 +107,5 @@ venv.bak/ # mypy .mypy_cache/ +.dmypy.json +dmypy.json diff --git a/vendor/gitignore/Rails.gitignore b/vendor/gitignore/Rails.gitignore index e62f78e17bc..78eb74fdc26 100644 --- a/vendor/gitignore/Rails.gitignore +++ b/vendor/gitignore/Rails.gitignore @@ -47,3 +47,15 @@ bower.json # Ignore node_modules node_modules/ +# Ignore precompiled javascript packs +/public/packs +/public/packs-test + +# Ignore yarn files +/yarn-error.log +yarn-debug.log* +.yarn-integrity + +# Ignore uploaded files in development +/storage/* +!/storage/.keep
\ No newline at end of file diff --git a/vendor/gitignore/Swift.gitignore b/vendor/gitignore/Swift.gitignore index b8e04d98e33..7b0d62bc23a 100644 --- a/vendor/gitignore/Swift.gitignore +++ b/vendor/gitignore/Swift.gitignore @@ -69,3 +69,10 @@ fastlane/report.xml fastlane/Preview.html fastlane/screenshots/**/*.png fastlane/test_output + +# Code Injection +# +# After new code Injection tools there's a generated folder /iOSInjectionProject +# https://github.com/johnno1962/injectionforxcode + +iOSInjectionProject/ diff --git a/vendor/gitignore/Symfony.gitignore b/vendor/gitignore/Symfony.gitignore index d098259ffb0..3dab634c188 100644 --- a/vendor/gitignore/Symfony.gitignore +++ b/vendor/gitignore/Symfony.gitignore @@ -15,6 +15,10 @@ !var/logs/.gitkeep !var/sessions/.gitkeep +# Logs (Symfony4) +/var/log/* +!var/log/.gitkeep + # Parameters /app/config/parameters.yml /app/config/parameters.ini diff --git a/vendor/gitignore/TeX.gitignore b/vendor/gitignore/TeX.gitignore index 79a66f9ebfa..ff87d483645 100644 --- a/vendor/gitignore/TeX.gitignore +++ b/vendor/gitignore/TeX.gitignore @@ -188,6 +188,9 @@ sympy-plots-for-*.tex/ *.pytxcode pythontex-files-*/ +# tcolorbox +*.listing + # thmtools *.loe diff --git a/vendor/gitignore/Terraform.gitignore b/vendor/gitignore/Terraform.gitignore index d9397e2d7d9..a8935803468 100644 --- a/vendor/gitignore/Terraform.gitignore +++ b/vendor/gitignore/Terraform.gitignore @@ -13,3 +13,14 @@ crash.log # version control. # # example.tfvars + +# Ignore override files as they are usually used to override resources locally and so +# are not checked in +override.tf +override.tf.json +*_override.tf +*_override.tf.json + +# Include override files you do wish to add to version control using negated pattern +# +# !example_override.tf diff --git a/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml b/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml index 893ab9efa2a..0b362fa0bee 100644 --- a/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml +++ b/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml @@ -51,6 +51,8 @@ variables: KUBERNETES_VERSION: 1.8.6 HELM_VERSION: 2.6.1 + DOCKER_DRIVER: overlay2 + stages: - build - test @@ -67,8 +69,6 @@ build: image: docker:stable-git services: - docker:stable-dind - variables: - DOCKER_DRIVER: overlay2 script: - setup_docker - build @@ -95,8 +95,6 @@ test: code_quality: stage: test image: docker:stable - variables: - DOCKER_DRIVER: overlay2 allow_failure: true services: - docker:stable-dind @@ -114,8 +112,6 @@ code_quality: license_management: stage: test image: docker:stable - variables: - DOCKER_DRIVER: overlay2 allow_failure: true services: - docker:stable-dind @@ -133,8 +129,6 @@ license_management: performance: stage: performance image: docker:stable - variables: - DOCKER_DRIVER: overlay2 allow_failure: true services: - docker:stable-dind @@ -156,8 +150,6 @@ performance: sast: stage: test image: docker:stable - variables: - DOCKER_DRIVER: overlay2 allow_failure: true services: - docker:stable-dind @@ -175,8 +167,6 @@ sast: dependency_scanning: stage: test image: docker:stable - variables: - DOCKER_DRIVER: overlay2 allow_failure: true services: - docker:stable-dind @@ -194,8 +184,6 @@ dependency_scanning: container_scanning: stage: test image: docker:stable - variables: - DOCKER_DRIVER: overlay2 allow_failure: true services: - docker:stable-dind diff --git a/vendor/gitlab-ci-yml/Maven.gitlab-ci.yml b/vendor/gitlab-ci-yml/Maven.gitlab-ci.yml index 5f9c9b2c965..d61ff239e13 100644 --- a/vendor/gitlab-ci-yml/Maven.gitlab-ci.yml +++ b/vendor/gitlab-ci-yml/Maven.gitlab-ci.yml @@ -17,7 +17,7 @@ variables: # This will supress any download for dependencies and plugins or upload messages which would clutter the console log. # `showDateTime` will show the passed time in milliseconds. You need to specify `--batch-mode` to make this work. - MAVEN_OPTS: "-Dhttps.protocols=TLSv1.2 -Dmaven.repo.local=.m2/repository -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=WARN -Dorg.slf4j.simpleLogger.showDateTime=true -Djava.awt.headless=true" + MAVEN_OPTS: "-Dhttps.protocols=TLSv1.2 -Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=WARN -Dorg.slf4j.simpleLogger.showDateTime=true -Djava.awt.headless=true" # As of Maven 3.3.0 instead of this you may define these options in `.mvn/maven.config` so the same config is used # when running from the command line. # `installAtEnd` and `deployAtEnd` are only effective with recent version of the corresponding plugins. diff --git a/vendor/gitlab-ci-yml/Pages/Middleman.gitlab-ci.yml b/vendor/gitlab-ci-yml/Pages/Middleman.gitlab-ci.yml index 983d7b5250e..9f4cc0574d6 100644 --- a/vendor/gitlab-ci-yml/Pages/Middleman.gitlab-ci.yml +++ b/vendor/gitlab-ci-yml/Pages/Middleman.gitlab-ci.yml @@ -1,25 +1,24 @@ # Full project: https://gitlab.com/pages/middleman -image: ruby:2.4 -variables: - LANG: "C.UTF-8" +image: ruby:2.3 cache: paths: - vendor -before_script: +test: + script: - apt-get update -yqqq - apt-get install -y nodejs - bundle install --path vendor - -test: - script: - bundle exec middleman build except: - master pages: script: + - apt-get update -yqqq + - apt-get install -y nodejs + - bundle install --path vendor - bundle exec middleman build artifacts: paths: diff --git a/vendor/gitlab-ci-yml/Swift.gitlab-ci.yml b/vendor/gitlab-ci-yml/Swift.gitlab-ci.yml index 10d0b05d9f8..ba8a802ba4f 100644 --- a/vendor/gitlab-ci-yml/Swift.gitlab-ci.yml +++ b/vendor/gitlab-ci-yml/Swift.gitlab-ci.yml @@ -1,5 +1,5 @@ # Lifted from: https://about.gitlab.com/2016/03/10/setting-up-gitlab-ci-for-ios-projects/ -# This file assumes an own GitLab CI runner, setup on an macOS system. +# This file assumes an own GitLab CI runner, setup on a macOS system. stages: - build - archive diff --git a/vendor/licenses.csv b/vendor/licenses.csv index 0079f1e38e8..85b7d16db54 100644 --- a/vendor/licenses.csv +++ b/vendor/licenses.csv @@ -1,22 +1,7 @@ -@babel/code-frame,7.0.0-beta.44,MIT -@babel/generator,7.0.0-beta.44,MIT -@babel/helper-function-name,7.0.0-beta.44,MIT -@babel/helper-get-function-arity,7.0.0-beta.44,MIT -@babel/helper-split-export-declaration,7.0.0-beta.44,MIT -@babel/highlight,7.0.0-beta.44,MIT -@babel/template,7.0.0-beta.44,MIT -@babel/traverse,7.0.0-beta.44,MIT -@babel/types,7.0.0-beta.44,MIT -@gitlab-org/gitlab-svgs,1.27.0,MIT -@gitlab-org/gitlab-svgs,1.28.0,MIT -@gitlab-org/gitlab-ui,1.0.5,MIT +@gitlab-org/gitlab-svgs,1.29.0,MIT +@gitlab-org/gitlab-ui,1.1.0,MIT @sindresorhus/is,0.7.0,MIT -@types/events,1.2.0,MIT -@types/glob,5.0.35,MIT @types/jquery,2.0.48,MIT -@types/minimatch,3.0.3,MIT -@types/node,10.5.2,MIT -@types/parse5,5.0.0,MIT @vue/component-compiler-utils,1.2.1,MIT @webassemblyjs/ast,1.5.13,MIT @webassemblyjs/floating-point-hex-parser,1.5.13,MIT @@ -37,15 +22,11 @@ @webassemblyjs/wast-parser,1.5.13,MIT @webassemblyjs/wast-printer,1.5.13,MIT RedCloth,4.3.2,MIT -abbrev,1.0.9,ISC abbrev,1.1.1,ISC accepts,1.3.4,MIT ace-rails-ap,4.1.2,MIT -acorn,3.3.0,MIT -acorn,5.6.2,MIT acorn,5.7.1,MIT acorn-dynamic-import,3.0.0,MIT -acorn-jsx,3.0.1,MIT actionmailer,4.2.10,MIT actionpack,4.2.10,MIT actionview,4.2.10,MIT @@ -55,79 +36,44 @@ activerecord,4.2.10,MIT activesupport,4.2.10,MIT acts-as-taggable-on,5.0.0,MIT addressable,2.5.2,Apache 2.0 -addressparser,1.0.1,MIT aes_key_wrap,1.0.1,MIT -after,0.8.2,MIT -agent-base,4.2.1,MIT -ajv,5.5.2,MIT ajv,6.1.1,MIT -ajv-keywords,2.1.1,MIT ajv-keywords,3.1.0,MIT akismet,2.0.0,MIT -align-text,0.1.4,MIT -amdefine,1.0.1,BSD-3-Clause OR MIT -amqplib,0.5.2,MIT -ansi-align,2.0.0,ISC ansi-escapes,1.4.0,MIT ansi-escapes,3.0.0,MIT -ansi-html,0.0.7,Apache 2.0 ansi-regex,2.1.1,MIT ansi-regex,3.0.0,MIT ansi-styles,2.2.1,MIT ansi-styles,3.2.1,MIT anymatch,2.0.0,ISC -append-transform,0.4.0,MIT aproba,1.2.0,ISC are-we-there-yet,1.1.4,ISC arel,6.0.4,MIT -argparse,1.0.9,MIT arr-diff,4.0.0,MIT arr-flatten,1.1.0,MIT arr-union,3.1.0,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-includes,3.0.3,MIT -array-slice,0.2.3,MIT -array-union,1.0.2,MIT array-uniq,1.0.3,MIT -array-unique,0.2.1,MIT array-unique,0.3.2,MIT -arraybuffer.slice,0.0.7,MIT -arrify,1.0.1,MIT asana,0.6.0,MIT asciidoctor,1.5.6.2,MIT asciidoctor-plantuml,0.0.8,MIT -asn1,0.2.3,MIT asn1.js,4.10.1,MIT assert,1.4.1,MIT -assert-plus,0.2.0,MIT -assert-plus,1.0.0,MIT asset_sync,2.4.0,MIT assign-symbols,1.0.0,MIT -ast-types,0.11.3,MIT -async,1.5.2,MIT -async,2.6.0,MIT -async,2.6.1,MIT async-each,1.0.1,MIT async-limiter,1.0.0,MIT -asynckit,0.4.0,MIT atob,2.0.3,(MIT OR Apache-2.0) atomic,1.1.99,Apache 2.0 attr_encrypted,3.1.0,MIT attr_required,1.0.0,MIT autosize,4.0.0,MIT -aws-sign2,0.6.0,Apache 2.0 -aws-sign2,0.7.0,Apache 2.0 -aws4,1.6.0,MIT axiom-types,0.1.1,MIT -axios,0.15.3,MIT axios,0.17.1,MIT -axios-mock-adapter,1.15.0,MIT babel-code-frame,6.26.0,MIT babel-core,6.26.3,MIT -babel-eslint,8.2.3,MIT babel-generator,6.26.0,MIT babel-helper-bindify-decorators,6.24.1,MIT babel-helper-builder-binary-assignment-operator-visitor,6.24.1,MIT @@ -146,8 +92,6 @@ babel-helpers,6.24.1,MIT babel-loader,7.1.5,MIT babel-messages,6.23.0,MIT babel-plugin-check-es2015-constants,6.22.0,MIT -babel-plugin-istanbul,4.1.6,New BSD -babel-plugin-rewire,1.1.0,ISC babel-plugin-syntax-async-functions,6.13.0,MIT babel-plugin-syntax-async-generators,6.13.0,MIT babel-plugin-syntax-class-properties,6.13.0,MIT @@ -201,46 +145,29 @@ babel-traverse,6.26.0,MIT babel-types,6.26.0,MIT babosa,1.0.2,MIT babylon,6.18.0,MIT -babylon,7.0.0-beta.44,MIT -backo2,1.0.2,MIT balanced-match,1.0.0,MIT base,0.11.2,MIT base32,0.3.2,MIT -base64-arraybuffer,0.1.5,MIT base64-js,1.2.3,MIT -base64id,1.0.0,MIT -batch,0.6.1,MIT batch-loader,1.2.1,MIT bcrypt,3.1.12,MIT -bcrypt-pbkdf,1.0.1,New BSD bcrypt_pbkdf,1.0.0,MIT -better-assert,1.0.2,MIT bfj-node4,5.2.1,MIT big.js,3.1.3,MIT binary-extensions,1.11.0,MIT binaryextensions,2.1.1,MIT bindata,2.4.3,ruby -bitsyntax,0.0.4,MIT -bl,1.1.2,MIT blackst0ne-mermaid,7.1.0-fixed,MIT -blob,0.0.4,MIT* bluebird,3.5.1,MIT bn.js,4.11.8,MIT body-parser,1.18.2,MIT -bonjour,3.5.0,MIT -boom,2.10.1,New BSD -boom,4.3.1,New BSD -boom,5.2.0,New BSD -bootstrap,4.1.1,MIT bootstrap,4.1.2,MIT bootstrap-vue,2.0.0-rc.11,MIT bootstrap_form,2.7.0,MIT -boxen,1.3.0,MIT brace-expansion,1.1.11,MIT -braces,0.1.5,MIT braces,2.3.1,MIT brorand,1.1.0,MIT -browser,2.2.0,MIT +browser,2.5.3,MIT browserify-aes,1.1.1,MIT browserify-cipher,1.0.0,MIT browserify-des,1.0.0,MIT @@ -249,32 +176,17 @@ browserify-sign,4.0.4,ISC browserify-zlib,0.2.0,MIT buffer,4.9.1,MIT buffer-from,1.0.0,MIT -buffer-indexof,1.1.0,MIT -buffer-more-ints,0.0.2,MIT buffer-xor,1.0.3,MIT builder,3.2.3,MIT -buildmail,4.0.1,MIT -builtin-modules,1.1.1,MIT builtin-status-codes,3.0.0,MIT -bytes,2.5.0,MIT bytes,3.0.0,MIT cacache,10.0.4,ISC cache-base,1.0.1,MIT cache-loader,1.2.2,MIT cacheable-request,2.1.4,MIT -caller-path,0.1.0,MIT -callsite,1.0.0,MIT* -callsites,0.2.0,MIT -camelcase,1.2.1,MIT -camelcase,2.1.1,MIT camelcase,4.1.0,MIT -camelcase-keys,2.1.0,MIT -capture-stack-trace,1.0.0,MIT carrierwave,1.2.3,MIT -caseless,0.11.0,Apache 2.0 -caseless,0.12.0,Apache 2.0 cause,0.1,MIT -center-align,0.1.3,MIT chalk,1.1.3,MIT chalk,2.4.1,MIT chardet,0.4.2,MIT @@ -283,7 +195,6 @@ charenc,0.0.2,New BSD charlock_holmes,0.7.6,MIT chart.js,1.0.2,MIT check-types,7.3.0,MIT -chokidar,2.0.2,MIT chokidar,2.0.4,MIT chownr,1.0.1,ISC chrome-trace-event,1.0.0,MIT @@ -291,19 +202,14 @@ chronic,0.10.2,MIT chronic_duration,0.10.6,MIT chunky_png,1.3.5,MIT cipher-base,1.0.4,MIT -circular-json,0.3.3,MIT -circular-json,0.5.5,MIT citrus,3.0.2,MIT class-utils,0.3.6,MIT classlist-polyfill,1.2.0,Unlicense -cli-boxes,1.0.0,MIT cli-cursor,2.1.0,MIT cli-width,2.1.0,ISC clipboard,1.7.1,MIT -cliui,2.1.0,ISC cliui,4.0.0,ISC clone-response,1.0.2,MIT -co,4.6.0,MIT code-point-at,1.1.0,MIT codesandbox-api,0.0.18,MIT codesandbox-import-util-types,1.2.11,LGPL @@ -312,31 +218,20 @@ coercible,1.0.0,MIT collection-visit,1.0.0,MIT color-convert,1.9.1,MIT color-name,1.1.2,MIT -colors,1.1.2,MIT -combine-lists,1.0.1,MIT -combined-stream,1.0.6,MIT commander,2.13.0,MIT commander,2.15.1,MIT commondir,1.0.1,MIT commonmarker,0.17.8,MIT -component-bind,1.0.0,MIT* component-emitter,1.2.1,MIT -component-inherit,0.0.3,MIT* -compressible,2.0.11,MIT -compression,1.7.0,MIT compression-webpack-plugin,1.1.11,MIT concat-map,0.0.1,MIT concat-stream,1.6.2,MIT concurrent-ruby-ext,1.0.5,MIT -configstore,3.1.1,Simplified BSD -connect,3.6.6,MIT -connect-history-api-fallback,1.3.0,MIT connection_pool,2.2.1,MIT console-browserify,1.1.0,MIT console-control-strings,1.1.0,ISC consolidate,0.15.1,MIT constants-browserify,1.0.0,MIT -contains-path,0.1.0,MIT content-disposition,0.5.2,MIT content-type,1.0.4,MIT convert-source-map,1.5.1,MIT @@ -350,7 +245,6 @@ core-util-is,1.0.2,MIT crack,0.4.3,MIT crass,1.0.4,MIT create-ecdh,4.0.0,MIT -create-error-class,3.0.2,MIT create-hash,1.1.3,MIT create-hmac,1.1.6,MIT creole,0.5.0,ruby @@ -358,17 +252,11 @@ cropper,2.3.0,MIT cross-spawn,5.1.0,MIT cross-spawn,6.0.5,MIT crypt,0.0.2,New BSD -cryptiles,2.0.5,New BSD -cryptiles,3.1.2,New BSD crypto-browserify,3.12.0,MIT -crypto-random-string,1.0.0,MIT css-loader,1.0.0,MIT -css-selector-parser,1.3.0,MIT css-selector-tokenizer,0.7.0,MIT css_parser,1.5.0,MIT cssesc,0.1.0,MIT -currently-unhandled,0.4.1,MIT -custom-event,1.0.1,MIT cyclist,0.2.2,MIT* d3,3.5.17,New BSD d3,4.12.2,New BSD @@ -404,13 +292,9 @@ d3-voronoi,1.1.2,New BSD d3-zoom,1.7.1,New BSD dagre-d3-renderer,0.4.24,MIT dagre-layout,0.8.0,MIT -dashdash,1.14.1,MIT -data-uri-to-buffer,1.2.0,MIT -date-format,1.2.0,MIT date-now,0.1.4,MIT dateformat,3.0.3,MIT de-indent,1.0.2,MIT -debug,2.6.8,MIT debug,2.6.9,MIT debug,3.1.0,MIT debugger-ruby_core_source,1.3.8,MIT @@ -420,44 +304,27 @@ declarative,0.0.10,MIT declarative-option,0.1.0,MIT decode-uri-component,0.2.0,MIT decompress-response,3.3.0,MIT -deep-equal,1.0.1,MIT deep-extend,0.4.2,MIT -deep-is,0.1.3,MIT -default-require-extensions,1.0.0,MIT default_value_for,3.0.2,MIT -define-properties,1.1.2,MIT define-property,0.2.5,MIT define-property,1.0.0,MIT define-property,2.0.2,MIT -degenerator,1.0.4,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.1,MIT -depd,1.1.2,MIT des.js,1.0.0,MIT descendants_tracker,0.0.4,MIT destroy,1.0.4,MIT detect-indent,4.0.0,MIT detect-libc,1.0.3,Apache 2.0 -detect-node,2.0.3,ISC device_detector,1.0.0,LGPL devise,4.4.3,MIT devise-two-factor,3.0.0,MIT -di,0.0.1,MIT diff,3.5.0,New BSD diff-lcs,1.3,"MIT,Artistic-2.0,GPL-2.0+" diffie-hellman,5.0.2,MIT 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,Simplified BSD -doctrine,2.1.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.20180417,"Simplified BSD,New BSD,Mozilla Public License 2.0" @@ -468,13 +335,11 @@ domutils,1.6.2,Simplified BSD doorkeeper,4.3.2,MIT doorkeeper-openid_connect,1.5.0,MIT dot-prop,4.2.0,MIT -double-ended-queue,2.1.0-0,MIT dropzone,4.2.0,MIT dropzonejs-rails,0.7.2,MIT duplexer,0.1.1,MIT duplexer3,0.1.4,New BSD duplexify,3.5.3,MIT -ecc-jsbn,0.1.1,MIT ed25519,1.2.4,MIT editions,1.3.4,MIT ee-first,1.1.1,MIT @@ -487,102 +352,52 @@ encodeurl,1.0.2,MIT encoding,0.1.12,MIT encryptor,3.0.0,MIT end-of-stream,1.4.1,MIT -engine.io,3.1.5,MIT -engine.io-client,3.1.5,MIT -engine.io-parser,2.1.2,MIT -enhanced-resolve,0.9.1,MIT -enhanced-resolve,4.0.0,MIT enhanced-resolve,4.1.0,MIT -ent,2.2.0,MIT entities,1.1.1,Simplified BSD equalizer,0.0.11,MIT -errno,0.1.4,MIT errno,0.1.7,MIT -error-ex,1.3.0,MIT erubis,2.7.0,MIT -es-abstract,1.10.0,MIT -es-to-primitive,1.1.1,MIT es6-promise,3.0.2,MIT -es6-promise,4.2.4,MIT -es6-promisify,5.0.0,MIT escape-html,1.0.3,MIT escape-string-regexp,1.0.5,MIT escape_utils,1.1.1,MIT -escodegen,1.8.1,Simplified BSD -escodegen,1.9.0,Simplified BSD -eslint,4.12.1,MIT -eslint-config-airbnb-base,12.1.0,MIT -eslint-import-resolver-node,0.3.2,MIT -eslint-import-resolver-webpack,0.10.0,MIT -eslint-module-utils,2.2.0,MIT -eslint-plugin-filenames,1.2.0,MIT -eslint-plugin-html,4.0.3,ISC -eslint-plugin-import,2.12.0,MIT -eslint-plugin-jasmine,2.2.0,MIT -eslint-plugin-promise,3.8.0,ISC -eslint-plugin-vue,4.5.0,MIT -eslint-restricted-globals,0.1.1,MIT eslint-scope,3.7.1,Simplified BSD -eslint-visitor-keys,1.0.0,Apache 2.0 -espree,3.5.4,Simplified BSD -esprima,2.7.3,Simplified BSD -esprima,3.1.3,Simplified BSD -esprima,4.0.0,Simplified BSD -esquery,1.0.1,New BSD esrecurse,4.2.1,Simplified BSD -estraverse,1.9.3,Simplified BSD estraverse,4.2.0,Simplified BSD esutils,2.0.2,Simplified BSD et-orbi,1.0.3,MIT etag,1.8.1,MIT eve-raphael,0.5.0,Apache 2.0 -event-stream,3.3.4,MIT -eventemitter3,1.2.0,MIT events,1.1.1,MIT -eventsource,0.1.6,MIT evp_bytestokey,1.0.3,MIT excon,0.62.0,MIT execa,0.7.0,MIT execjs,2.6.0,MIT -expand-braces,0.1.2,MIT expand-brackets,2.1.4,MIT -expand-range,0.1.1,MIT exports-loader,0.7.0,MIT express,4.16.2,MIT expression_parser,0.9.0,MIT -extend,3.0.1,MIT extend-shallow,2.0.1,MIT extend-shallow,3.0.2,MIT external-editor,2.2.0,MIT external-editor,3.0.0,MIT extglob,2.0.4,MIT -extsprintf,1.3.0,MIT -extsprintf,1.4.0,MIT faraday,0.12.2,MIT faraday_middleware,0.12.2,MIT faraday_middleware-multi_json,0.0.6,MIT fast-deep-equal,1.0.0,MIT fast-json-stable-stringify,2.0.0,MIT -fast-levenshtein,2.0.6,MIT fast_blank,1.0.0,MIT fast_gettext,1.6.0,"MIT,ruby" fastparse,1.1.1,MIT -faye-websocket,0.10.0,MIT -faye-websocket,0.11.1,MIT -ffi,1.9.18,New BSD +ffi,1.9.25,New BSD figures,2.0.0,MIT -file-entry-cache,2.0.0,MIT file-loader,1.1.11,MIT -file-uri-to-path,1.0.0,MIT -fileset,2.0.3,MIT filesize,3.6.0,New BSD fill-range,4.0.0,MIT finalhandler,1.1.0,MIT find-cache-dir,1.0.0,MIT -find-root,1.1.0,MIT -find-up,1.1.2,MIT find-up,2.1.0,MIT -flat-cache,1.2.2,MIT flipper,0.13.0,MIT flipper-active_record,0.13.0,MIT flipper-active_support_cache_store,0.13.0,MIT @@ -597,46 +412,29 @@ fog-local,0.3.1,MIT fog-openstack,0.1.21,MIT fog-rackspace,0.1.1,MIT fog-xml,0.1.3,MIT -follow-redirects,1.0.0,MIT follow-redirects,1.2.6,MIT font-awesome-rails,4.7.0.1,"MIT,SIL Open Font License" for-in,1.0.2,MIT -foreach,2.0.5,MIT -forever-agent,0.6.1,Apache 2.0 -form-data,2.0.0,MIT -form-data,2.3.2,MIT formatador,0.2.5,MIT formdata-polyfill,3.0.11,MIT forwarded,0.1.2,MIT fragment-cache,0.2.1,MIT fresh,0.5.2,MIT -from,0.1.7,MIT from2,2.3.0,MIT -fs-access,1.0.1,MIT fs-minipass,1.2.5,ISC fs-write-stream-atomic,1.0.10,ISC fs.realpath,1.0.0,ISC fsevents,1.2.4,MIT -ftp,0.3.10,MIT -function-bind,1.1.1,MIT -functional-red-black-tree,1.0.1,MIT fuzzaldrin-plus,0.5.0,MIT gauge,2.7.4,ISC gemojione,3.3.0,MIT -generate-function,2.0.0,MIT -generate-object-property,1.2.0,MIT get-caller-file,1.0.2,ISC -get-stdin,4.0.1,MIT get-stream,3.0.0,MIT -get-uri,2.0.2,MIT get-value,2.0.6,MIT get_process_mem,0.2.0,MIT -getpass,0.1.7,MIT -gettext-extractor,3.3.2,MIT -gettext-extractor-vue,4.0.1,MIT gettext_i18n_rails,1.8.0,MIT gettext_i18n_rails_js,1.3.0,MIT -gitaly-proto,0.113.0,MIT +gitaly-proto,0.117.0,MIT github-linguist,5.3.3,MIT github-markup,1.7.0,MIT gitlab-flowdock-git-hook,1.0.1,MIT @@ -645,16 +443,11 @@ gitlab-gollum-rugged_adapter,0.4.4.1,MIT gitlab-grit,2.8.2,MIT gitlab-markup,1.6.4,MIT gitlab_omniauth-ldap,2.0.4,MIT -glob,5.0.15,ISC glob,7.1.2,ISC glob-parent,3.1.0,ISC -global-dirs,0.1.1,MIT global-modules-path,2.1.0,Apache 2.0 globalid,0.4.1,MIT -globals,11.5.0,MIT globals,9.18.0,MIT -globby,5.0.0,MIT -globby,6.1.0,MIT gollum-grit_adapter,1.0.1,MIT gon,6.2.0,MIT good-listener,1.2.2,MIT @@ -662,7 +455,6 @@ google-api-client,0.23.4,Apache 2.0 google-protobuf,3.5.1,New BSD googleapis-common-protos-types,1.0.1,Apache 2.0 googleauth,0.6.2,Apache 2.0 -got,6.7.1,MIT got,8.3.0,MIT gpgme,2.0.13,LGPL-2.1+ graceful-fs,4.1.11,ISC @@ -676,17 +468,8 @@ graphql,1.8.1,MIT grpc,1.11.0,Apache 2.0 gzip-size,4.1.0,MIT hamlit,2.8.8,MIT -handle-thing,1.2.5,MIT -handlebars,4.0.6,MIT hangouts-chat,0.0.5,MIT -har-schema,2.0.0,ISC -har-validator,2.0.6,ISC -har-validator,5.0.3,ISC -has,1.0.1,MIT has-ansi,2.0.0,MIT -has-binary2,1.0.2,MIT -has-cors,1.1.0,MIT -has-flag,1.0.0,MIT has-flag,3.0.0,MIT has-symbol-support-x,1.3.0,MIT has-to-string-tag-x,1.3.0,MIT @@ -701,19 +484,11 @@ hash-sum,1.0.2,MIT hash.js,1.1.3,MIT hashie,3.5.7,MIT hashie-forbidden_attributes,0.1.1,MIT -hawk,3.1.3,New BSD -hawk,6.0.2,New BSD he,1.1.1,MIT health_check,2.6.0,MIT hipchat,1.5.2,MIT -hipchat-notifier,1.1.0,MIT hmac-drbg,1.0.1,MIT -hoek,2.16.3,New BSD -hoek,4.2.1,New BSD home-or-tmp,2.0.0,MIT -hosted-git-info,2.2.0,ISC -hpack.js,2.1.6,MIT -html-entities,1.2.0,MIT html-pipeline,2.8.4,MIT html2text,0.2.0,MIT htmlentities,4.3.4,MIT @@ -721,71 +496,47 @@ htmlparser2,3.9.2,MIT http,2.2.2,MIT http-cache-semantics,3.8.1,Simplified BSD http-cookie,1.0.3,MIT -http-deceiver,1.2.7,MIT http-errors,1.6.2,MIT -http-errors,1.6.3,MIT http-form_data,1.0.3,MIT -http-proxy,1.16.2,MIT -http-proxy-agent,2.1.0,MIT -http-proxy-middleware,0.18.0,MIT -http-signature,1.1.1,MIT -http-signature,1.2.0,MIT http_parser.rb,0.6.0,MIT httparty,0.13.7,MIT httpclient,2.8.3,ruby -httpntlm,1.6.1,MIT -httpreq,0.4.24,MIT https-browserify,1.0.0,MIT -https-proxy-agent,2.2.1,MIT i18n,0.9.5,MIT icalendar,2.4.1,ruby ice_nine,0.11.2,MIT -iconv-lite,0.4.15,MIT iconv-lite,0.4.19,MIT iconv-lite,0.4.23,MIT icss-replace-symbols,1.1.0,ISC icss-utils,2.1.0,ISC ieee754,1.1.11,New BSD iferr,0.1.5,MIT -ignore,3.3.8,MIT -ignore-by-default,1.0.1,ISC ignore-walk,3.0.1,ISC immediate,3.0.6,MIT -import-lazy,2.1.0,MIT import-local,1.0.0,MIT imports-loader,0.8.0,MIT imurmurhash,0.1.4,MIT -indent-string,2.1.0,MIT indexes-of,1.0.1,MIT indexof,0.0.1,MIT* -inflection,1.12.0,MIT -inflection,1.3.8,MIT inflight,1.0.6,ISC influxdb,0.2.3,MIT inherits,2.0.1,ISC inherits,2.0.3,ISC ini,1.3.5,ISC inquirer,3.0.6,MIT -inquirer,3.3.0,MIT inquirer,6.0.0,MIT -internal-ip,1.2.0,MIT interpret,1.1.0,MIT into-stream,3.1.0,MIT invariant,2.2.2,New BSD invert-kv,1.0.0,MIT -ip,1.1.5,MIT ipaddr.js,1.6.0,MIT ipaddress,0.8.3,MIT is-accessor-descriptor,0.1.6,MIT is-accessor-descriptor,1.0.0,MIT -is-arrayish,0.2.1,MIT is-binary-path,1.0.1,MIT is-buffer,1.1.6,MIT -is-builtin-module,1.0.0,MIT -is-callable,1.1.3,MIT is-data-descriptor,0.1.4,MIT is-data-descriptor,1.0.0,MIT -is-date-object,1.0.1,MIT is-descriptor,0.1.6,MIT is-descriptor,1.0.2,MIT is-extendable,0.1.1,MIT @@ -796,55 +547,23 @@ is-fullwidth-code-point,1.0.0,MIT is-fullwidth-code-point,2.0.0,MIT is-glob,3.1.0,MIT is-glob,4.0.0,MIT -is-installed-globally,0.1.0,MIT -is-my-ip-valid,1.0.0,MIT -is-my-json-valid,2.17.2,MIT -is-npm,1.0.0,MIT -is-number,0.1.1,MIT is-number,3.0.0,MIT is-number,4.0.0,MIT is-obj,1.0.1,MIT is-object,1.0.1,MIT is-odd,2.0.0,MIT -is-path-cwd,1.0.0,MIT -is-path-in-cwd,1.0.0,MIT -is-path-inside,1.0.0,MIT is-plain-obj,1.1.0,MIT is-plain-object,2.0.4,MIT is-promise,2.1.0,MIT -is-property,1.0.2,MIT -is-redirect,1.0.0,MIT -is-regex,1.0.4,MIT -is-resolvable,1.0.0,MIT is-retry-allowed,1.1.0,MIT is-stream,1.1.0,MIT -is-symbol,1.0.1,MIT -is-typedarray,1.0.0,MIT -is-utf8,0.2.1,MIT is-windows,1.0.2,MIT -is-wsl,1.1.0,MIT -isarray,0.0.1,MIT isarray,1.0.0,MIT -isarray,2.0.1,MIT -isbinaryfile,3.0.2,MIT isexe,2.0.0,ISC isobject,2.1.0,MIT isobject,3.0.1,MIT -isstream,0.1.2,MIT -istanbul,0.4.5,New BSD -istanbul-api,1.2.1,New BSD -istanbul-lib-coverage,1.1.1,New BSD -istanbul-lib-coverage,1.2.0,New BSD -istanbul-lib-hook,1.1.0,New BSD -istanbul-lib-instrument,1.10.1,New BSD -istanbul-lib-report,1.1.2,New BSD -istanbul-lib-source-maps,1.2.2,New BSD -istanbul-reports,1.1.3,New BSD istextorbinary,2.2.1,MIT isurl,1.0.0,MIT -jasmine-core,2.9.0,MIT -jasmine-diff,0.1.3,MIT -jasmine-jquery,2.1.1,MIT jed,1.1.1,MIT jira-ruby,1.4.1,MIT jquery,3.3.1,MIT @@ -853,24 +572,15 @@ jquery-ujs,1.2.2,MIT jquery.waitforimages,2.2.0,MIT js-cookie,2.1.3,MIT js-tokens,3.0.2,MIT -js-yaml,3.11.0,MIT js_regex,2.2.1,MIT -jsbn,0.1.1,MIT jsesc,0.5.0,MIT jsesc,1.3.0,MIT -jsesc,2.5.1,MIT json,1.8.6,ruby json-buffer,3.0.0,MIT json-jwt,1.9.4,MIT json-parse-better-errors,1.0.2,MIT -json-schema,0.2.3,BSD json-schema-traverse,0.3.1,MIT -json-stable-stringify-without-jsonify,1.0.1,MIT -json-stringify-safe,5.0.1,ISC -json3,3.3.2,MIT json5,0.5.1,MIT -jsonpointer,4.0.1,MIT -jsprim,1.4.1,MIT jszip,3.1.3,(MIT OR GPL-3.0) jszip-utils,0.0.2,MIT or GPLv3 jwt,1.5.6,MIT @@ -878,35 +588,19 @@ kaminari,1.0.1,MIT kaminari-actionview,1.0.1,MIT kaminari-activerecord,1.0.1,MIT kaminari-core,1.0.1,MIT -karma,2.0.4,MIT -karma-chrome-launcher,2.2.0,MIT -karma-coverage-istanbul-reporter,1.4.2,MIT -karma-jasmine,1.1.2,MIT -karma-mocha-reporter,2.2.5,MIT -karma-sourcemap-loader,0.3.7,MIT -karma-webpack,4.0.0-beta.0,MIT katex,0.8.3,MIT keyv,3.0.0,MIT kgio,2.10.0,LGPL-2.1+ -killable,1.0.0,ISC kind-of,3.2.2,MIT kind-of,4.0.0,MIT kind-of,5.1.0,MIT kind-of,6.0.2,MIT kubeclient,3.1.0,MIT -latest-version,3.1.0,MIT -lazy-cache,1.0.4,MIT lazy-cache,2.0.2,MIT lcid,1.0.0,MIT -levn,0.3.0,MIT -libbase64,0.1.0,MIT -libmime,3.0.0,MIT -libqp,1.1.0,MIT licensee,8.9.2,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,1.1.0,MIT locale,2.1.2,"ruby,LGPLv3+" @@ -919,37 +613,22 @@ lodash.debounce,4.0.8,MIT lodash.escaperegexp,4.1.2,MIT lodash.get,4.4.2,MIT lodash.isequal,4.5.0,MIT -lodash.kebabcase,4.1.1,MIT lodash.mergewith,4.6.0,MIT -lodash.snakecase,4.1.1,MIT lodash.startcase,4.4.0,MIT -lodash.upperfirst,4.3.1,MIT -log-symbols,2.2.0,MIT -log4js,2.11.0,Apache 2.0 logging,2.2.2,MIT -loggly,1.1.1,MIT -loglevel,1.4.1,MIT -loglevelnext,1.0.3,MIT lograge,0.10.0,MIT long,3.2.0,Apache 2.0 long,4.0.0,Apache 2.0 -longest,1.0.1,MIT loofah,2.2.2,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,4.1.3,ISC lz-string,1.4.4,WTFPL mail,2.7.0,MIT mail_room,0.9.1,MIT -mailcomposer,4.0.1,MIT -mailgun-js,0.18.1,MIT make-dir,1.2.0,MIT mamacro,0.0.3,MIT map-cache,0.2.2,MIT -map-obj,1.0.1,MIT -map-stream,0.1.0,MIT map-visit,1.0.0,MIT marked,0.3.12,MIT match-at,0.1.1,MIT @@ -957,9 +636,7 @@ md5.js,1.3.4,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 merge-source-map,1.1.0,MIT method_source,0.9.0,MIT @@ -967,7 +644,6 @@ methods,1.1.2,MIT micromatch,3.1.10,MIT miller-rabin,4.0.1,MIT mime,1.4.1,MIT -mime,1.6.0,MIT mime,2.3.1,MIT mime-db,1.33.0,MIT mime-types,2.1.18,MIT @@ -982,7 +658,6 @@ mini_portile2,2.3.0,MIT minimalistic-assert,1.0.0,ISC minimalistic-crypto-utils,1.0.1,MIT minimatch,3.0.4,ISC -minimist,0.0.10,MIT minimist,0.0.8,MIT minimist,1.2.0,MIT minipass,2.3.3,ISC @@ -991,8 +666,8 @@ mississippi,2.0.0,Simplified BSD mixin-deep,1.3.1,MIT mkdirp,0.5.1,MIT moment,2.19.2,MIT -monaco-editor,0.13.1,MIT -monaco-editor-webpack-plugin,1.4.0,MIT +monaco-editor,0.14.3,MIT +monaco-editor-webpack-plugin,1.5.2,MIT mousetrap,1.4.6,Apache 2.0 mousetrap-rails,1.4.6,"MIT,Apache" move-concurrently,1.0.1,ISC @@ -1000,8 +675,6 @@ ms,2.0.0,MIT msgpack,1.2.4,Apache 2.0 multi_json,1.13.1,MIT multi_xml,0.6.0,MIT -multicast-dns,6.1.1,MIT -multicast-dns-service-types,1.1.0,MIT multipart-post,2.0.0,MIT mustermann,1.0.2,MIT mustermann-grape,1.0.0,MIT @@ -1009,53 +682,33 @@ mute-stream,0.0.7,ISC mysql2,0.4.10,MIT nan,2.10.0,MIT nanomatch,1.2.9,MIT -natural-compare,1.4.0,MIT needle,2.2.1,MIT negotiator,0.6.1,MIT neo-async,2.5.0,MIT net-ldap,0.16.0,MIT net-ssh,5.0.1,MIT -netmask,1.0.6,MIT netrc,0.11.0,MIT nice-try,1.0.4,MIT node-fetch,1.6.3,MIT -node-forge,0.6.33,New BSD node-libs-browser,2.1.0,MIT node-pre-gyp,0.10.0,New BSD -node-uuid,1.4.8,MIT -nodemailer,2.7.2,MIT -nodemailer-direct-transport,3.3.2,MIT -nodemailer-fetch,1.6.0,MIT -nodemailer-shared,1.1.0,MIT -nodemailer-smtp-pool,2.8.2,MIT -nodemailer-smtp-transport,2.7.2,MIT -nodemailer-wellknown,0.1.10,MIT -nodemon,1.18.2,MIT nokogiri,1.8.4,MIT nokogumbo,1.5.0,Apache 2.0 -nopt,1.0.10,MIT -nopt,3.0.6,ISC nopt,4.0.1,ISC -normalize-package-data,2.4.0,Simplified BSD normalize-path,2.1.1,MIT normalize-url,2.0.1,MIT npm-bundled,1.0.3,ISC npm-packlist,1.1.10,ISC npm-run-path,2.0.2,MIT npmlog,4.1.2,ISC -null-check,1.0.0,MIT number-is-nan,1.0.1,MIT numerizer,0.1.1,MIT oauth,0.5.4,MIT -oauth-sign,0.8.2,Apache 2.0 oauth2,1.4.0,MIT object-assign,4.1.1,MIT -object-component,0.0.3,MIT* object-copy,0.1.0,MIT -object-keys,1.0.11,MIT object-visit,1.0.1,MIT object.pick,1.3.0,MIT -obuf,1.1.1,MIT octokit,4.9.0,MIT omniauth,1.8.1,MIT omniauth-auth0,2.0.0,MIT @@ -1076,17 +729,12 @@ omniauth-shibboleth,1.3.0,MIT omniauth-twitter,1.4.0,MIT omniauth_crowd,2.2.3,MIT on-finished,2.3.0,MIT -on-headers,1.0.1,MIT once,1.4.0,ISC onetime,2.0.1,MIT opencollective,1.0.3,MIT opener,1.4.3,(WTFPL OR MIT) opn,4.0.2,MIT -opn,5.2.0,MIT -optimist,0.6.1,MIT -optionator,0.8.2,MIT org-ruby,0.9.12,MIT -original,1.0.0,MIT orm_adapter,0.5.0,MIT os,0.9.6,MIT os-browserify,0.3.0,MIT @@ -1099,34 +747,19 @@ p-finally,1.0.0,MIT p-is-promise,1.1.0,MIT p-limit,1.2.0,MIT p-locate,2.0.0,MIT -p-map,1.1.1,MIT p-timeout,2.0.1,MIT p-try,1.0.0,MIT -pac-proxy-agent,2.0.2,MIT -pac-resolver,3.0.0,MIT -package-json,4.0.1,MIT pako,1.0.6,(MIT AND Zlib) parallel-transform,1.1.0,MIT parse-asn1,5.1.0,ISC -parse-json,2.2.0,MIT -parse5,5.0.0,MIT -parseqs,0.0.5,MIT -parseuri,0.0.5,MIT parseurl,1.3.2,MIT pascalcase,0.1.1,MIT path-browserify,0.0.0,MIT path-dirname,1.0.2,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-proxy,1.0.0,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,Apache 2.0 pbkdf2,3.0.14,MIT peek,1.0.1,MIT peek-gc,0.0.2,MIT @@ -1135,23 +768,16 @@ 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,2.1.0,MIT pg,0.18.4,"BSD,ruby,GPL" -pify,2.3.0,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 -pluralize,7.0.0,MIT po_to_json,1.0.1,MIT -pofile,1.0.11,MIT popper.js,1.14.3,MIT -portfinder,1.0.13,MIT posix-character-classes,0.1.1,MIT posix-spawn,0.3.13,MIT -postcss,6.0.22,MIT postcss,6.0.23,MIT postcss-modules-extract-imports,1.2.0,ISC postcss-modules-local-by-default,1.2.0,MIT @@ -1159,10 +785,8 @@ postcss-modules-scope,1.1.0,ISC postcss-modules-values,1.3.0,ISC postcss-selector-parser,3.1.1,MIT postcss-value-parser,3.3.0,MIT -prelude-ls,1.1.2,MIT premailer,1.10.4,New BSD premailer-rails,1.9.7,MIT -prepend-http,1.0.4,MIT prepend-http,2.0.0,MIT prettier,1.12.1,MIT prismjs,1.6.0,MIT @@ -1170,18 +794,11 @@ private,0.1.8,MIT process,0.11.10,MIT process-nextick-args,1.0.7,MIT process-nextick-args,2.0.0,MIT -progress,2.0.0,MIT prometheus-client-mmap,0.9.4,Apache 2.0 promise-inflight,1.0.1,ISC -promisify-call,2.0.4,MIT proxy-addr,2.0.3,MIT -proxy-agent,3.0.1,MIT -proxy-from-env,1.0.0,MIT -prr,0.0.0,MIT prr,1.0.1,MIT -ps-tree,1.1.0,MIT pseudomap,1.0.2,ISC -pstree.remy,1.1.0,MIT public-encrypt,4.0.0,MIT public_suffix,3.0.2,MIT pump,2.0.1,MIT @@ -1189,14 +806,10 @@ pumpify,1.4.0,MIT punycode,1.3.2,MIT punycode,1.4.1,MIT pyu-ruby-sasl,0.0.3.3,MIT -qjobs,1.2.0,MIT -qs,6.2.3,New BSD qs,6.5.1,New BSD query-string,5.1.1,MIT querystring,0.2.0,MIT querystring-es3,0.2.1,MIT -querystringify,0.0.4,MIT -querystringify,1.0.0,MIT rack,1.6.10,MIT rack-accept,0.4.5,MIT rack-attack,4.4.1,MIT @@ -1220,7 +833,6 @@ range-parser,1.2.0,MIT raphael,2.2.7,MIT raven-js,3.22.1,Simplified BSD raw-body,2.3.2,MIT -raw-body,2.3.3,MIT raw-loader,0.5.1,MIT rb-fsevent,0.10.2,MIT rb-inotify,0.9.10,MIT @@ -1228,26 +840,16 @@ rbtrace,0.4.10,MIT rc,1.2.5,(BSD-2-Clause OR MIT OR Apache-2.0) rdoc,6.0.4,ruby re2,1.1.1,New BSD -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.1.14,MIT readable-stream,2.0.6,MIT -readable-stream,2.3.4,MIT readable-stream,2.3.6,MIT readdirp,2.1.0,MIT recaptcha,3.0.0,MIT recursive-open-struct,1.1.0,MIT redcarpet,3.4.0,MIT -redent,1.0.0,MIT -redis,2.8.0,MIT redis,3.3.5,MIT redis-actionpack,5.0.2,MIT redis-activesupport,5.0.4,MIT -redis-commands,1.3.1,MIT redis-namespace,1.6.0,MIT -redis-parser,2.6.0,MIT redis-rack,2.0.4,MIT redis-rails,5.0.2,MIT redis-store,1.4.1,MIT @@ -1259,28 +861,17 @@ regex-not,1.0.2,MIT regexp_parser,0.5.0,MIT regexpu-core,1.0.0,MIT regexpu-core,2.0.0,MIT -registry-auth-token,3.3.2,MIT -registry-url,3.1.0,MIT regjsgen,0.2.0,MIT regjsparser,0.1.5,Simplified 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,2.0.1,MIT representable,3.0.4,MIT -request,2.75.0,Apache 2.0 -request,2.83.0,Apache 2.0 request_store,1.3.1,MIT -requestretry,1.13.0,MIT require-directory,2.1.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.7.1,MIT resolve-cwd,2.0.0,MIT -resolve-from,1.0.1,MIT resolve-from,3.0.0,MIT resolve-url,0.2.1,MIT responders,2.4.0,MIT @@ -1289,7 +880,6 @@ rest-client,2.0.2,MIT restore-cursor,2.0.0,MIT ret,0.1.15,MIT retriable,3.1.2,MIT -right-align,0.1.3,MIT rimraf,2.6.2,ISC rinku,2.0.0,ISC ripemd160,2.0.1,MIT @@ -1311,8 +901,6 @@ run-async,2.3.0,MIT run-queue,1.0.3,ISC rw,1.3.3,New BSD rx,4.1.0,Apache 2.0 -rx-lite,4.0.8,Apache 2.0 -rx-lite-aggregates,4.0.8,Apache 2.0 rxjs,6.2.1,Apache 2.0 safe-buffer,5.1.1,MIT safe-buffer,5.1.2,MIT @@ -1329,16 +917,12 @@ sax,1.2.4,ISC schema-utils,0.4.5,MIT seed-fu,2.3.7,MIT select,1.1.2,MIT -select-hose,2.0.0,MIT select2,3.5.2-browserify,Apache* select2-rails,3.5.9.3,MIT -selfsigned,1.10.1,MIT semver,5.5.0,ISC -semver-diff,2.1.0,MIT send,0.16.1,MIT sentry-raven,2.7.2,Apache 2.0 serialize-javascript,1.4.0,New BSD -serve-index,1.9.0,MIT serve-static,1.13.1,MIT set-blocking,2.0.0,ISC set-getter,0.1.0,MIT @@ -1359,101 +943,58 @@ sidekiq-cron,0.6.0,MIT sidekiq-limit_fetch,3.4.0,MIT signal-exit,3.0.2,ISC signet,0.8.1,Apache 2.0 -slack-node,0.2.0,MIT slack-notifier,1.5.1,MIT slash,1.0.0,MIT -slice-ansi,1.0.0,MIT -smart-buffer,1.1.15,MIT -smart-buffer,4.0.1,MIT smooshpack,0.0.48,LGPL -smtp-connection,2.12.0,MIT snapdragon,0.8.1,MIT snapdragon-node,2.1.1,MIT snapdragon-util,3.0.1,MIT -sntp,1.0.9,BSD -sntp,2.1.0,BSD -socket.io,2.0.4,MIT -socket.io-adapter,1.1.1,MIT -socket.io-client,2.0.4,MIT -socket.io-parser,3.1.2,MIT -sockjs,0.3.19,MIT -sockjs-client,1.1.4,MIT -socks,1.1.10,MIT -socks,1.1.9,MIT -socks,2.2.1,MIT -socks-proxy-agent,3.0.1,MIT -socks-proxy-agent,4.0.1,MIT sort-keys,2.0.0,MIT sortablejs,1.7.0,MIT source-list-map,2.0.0,MIT -source-map,0.2.0,New BSD -source-map,0.4.4,New BSD source-map,0.5.0,New BSD -source-map,0.5.6,New BSD source-map,0.5.7,New BSD source-map,0.6.1,New BSD source-map-resolve,0.5.1,MIT source-map-support,0.4.18,MIT source-map-url,0.4.0,MIT -spdx-correct,1.0.2,Apache 2.0 -spdx-expression-parse,1.0.4,(MIT AND CC-BY-3.0) -spdx-license-ids,1.2.2,Unlicense -spdy,3.4.7,MIT -spdy-transport,2.0.20,MIT -split,0.3.3,MIT split-string,3.1.0,MIT -sprintf-js,1.0.3,New BSD sprockets,3.7.2,MIT sprockets-rails,3.2.1,MIT sql.js,0.4.0,MIT srcset,1.0.0,MIT sshkey,1.9.0,MIT -sshpk,1.13.1,MIT ssri,5.2.4,ISC state_machines,0.5.0,MIT state_machines-activemodel,0.5.1,MIT state_machines-activerecord,0.5.1,MIT static-extend,0.1.2,MIT statuses,1.3.1,MIT -statuses,1.4.0,MIT statuses,1.5.0,MIT stickyfilljs,2.0.5,MIT stream-browserify,2.0.1,MIT -stream-combiner,0.0.4,MIT stream-each,1.2.2,MIT stream-http,2.8.2,MIT stream-shift,1.0.0,MIT -streamroller,0.7.0,MIT strict-uri-encode,1.1.0,MIT string-width,1.0.2,MIT string-width,2.1.1,MIT string_decoder,0.10.31,MIT -string_decoder,1.0.3,MIT string_decoder,1.1.1,MIT stringex,2.8.4,MIT -stringstream,0.0.5,MIT strip-ansi,3.0.1,MIT strip-ansi,4.0.0,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 style-loader,0.21.0,MIT supports-color,2.0.0,MIT -supports-color,3.2.3,MIT supports-color,5.4.0,MIT svg4everybody,2.1.9,CC0-1.0 sys-filesystem,1.1.6,Artistic 2.0 -table,4.0.2,New BSD -tapable,0.1.10,MIT tapable,1.0.0,MIT tar,4.4.4,ISC temple,0.8.0,MIT -term-size,1.2.0,MIT -test-exclude,4.2.1,ISC text,1.3.1,MIT -text-table,0.2.0,MIT textextensions,2.2.0,MIT thor,0.19.4,MIT thread_safe,0.3.6,Apache 2.0 @@ -1462,54 +1003,35 @@ three-orbit-controls,82.1.0,MIT three-stl-loader,1.0.4,MIT through,2.3.8,MIT through2,2.0.3,MIT -thunkify,2.1.2,MIT -thunky,0.1.0,MIT* tilt,2.0.8,MIT timeago.js,3.0.2,MIT timed-out,4.0.1,MIT timers-browserify,2.0.10,MIT -timespan,2.3.0,MIT timfel-krb5-auth,0.8.3,LGPL tiny-emitter,2.0.2,MIT tmp,0.0.33,MIT -to-array,0.1.4,MIT to-arraybuffer,1.0.1,MIT to-fast-properties,1.0.3,MIT -to-fast-properties,2.0.0,MIT to-object-path,0.3.0,MIT to-regex,3.0.2,MIT to-regex-range,2.1.1,MIT toml-rb,1.0.0,MIT -touch,3.1.0,ISC -tough-cookie,2.3.3,New BSD traverse,0.6.6,MIT -trim-newlines,1.0.0,MIT trim-right,1.0.1,MIT trollop,2.1.3,MIT truncato,0.7.10,MIT tryer,1.0.0,MIT -tryit,1.0.3,MIT tslib,1.9.3,Apache 2.0 -tsscmp,1.0.5,MIT tty-browserify,0.0.0,MIT -tunnel-agent,0.4.3,Apache 2.0 -tunnel-agent,0.6.0,Apache 2.0 -tweetnacl,0.14.5,Unlicense -type-check,0.3.2,MIT type-is,1.6.16,MIT typedarray,0.0.6,MIT -typescript,2.9.2,Apache 2.0 tzinfo,1.2.5,MIT u2f,0.2.1,MIT uber,0.1.0,MIT uglifier,2.7.2,MIT uglify-es,3.3.9,Simplified BSD -uglify-js,2.8.29,Simplified BSD -uglify-to-browserify,1.0.2,MIT uglifyjs-webpack-plugin,1.2.5,MIT ultron,1.1.1,MIT -undefsafe,2.0.2,MIT -underscore,1.7.0,MIT underscore,1.9.0,MIT unf,0.1.4,BSD unf_ext,0.0.7.5,MIT @@ -1519,43 +1041,27 @@ union-value,1.0.0,MIT uniq,1.0.1,MIT unique-filename,1.1.0,ISC unique-slug,2.0.0,ISC -unique-string,1.0.0,MIT unpipe,1.0.0,MIT unset-value,1.0.0,MIT -unzip-response,2.0.1,MIT -upath,1.0.5,MIT upath,1.1.0,MIT -update-notifier,2.3.0,Simplified BSD urix,0.1.0,MIT url,0.11.0,MIT -url-join,4.0.0,MIT url-loader,1.0.1,MIT -url-parse,1.0.5,MIT -url-parse,1.1.9,MIT -url-parse-lax,1.0.0,MIT url-parse-lax,3.0.0,MIT url-to-options,1.0.1,MIT use,2.0.2,MIT -useragent,2.2.1,MIT util,0.10.3,MIT util-deprecate,1.0.2,MIT utils-merge,1.0.1,MIT -uuid,3.2.1,MIT -uws,9.14.0,Zlib v8-compile-cache,2.0.0,MIT -validate-npm-package-license,3.0.1,Apache 2.0 validates_hostname,1.0.6,MIT -vary,1.1.1,MIT vary,1.1.2,MIT -verror,1.10.0,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.5.16,MIT -vue-eslint-parser,2.0.3,MIT vue-functional-data-merge,2.0.6,MIT vue-hot-reload-api,2.3.0,MIT vue-loader,15.2.4,MIT @@ -1568,50 +1074,28 @@ vue-virtual-scroll-list,1.2.5,MIT vuex,3.0.1,MIT warden,1.2.7,MIT watchpack,1.5.0,MIT -wbuf,1.7.2,MIT webpack,4.16.0,MIT webpack-bundle-analyzer,2.13.1,MIT webpack-cli,3.0.8,MIT -webpack-dev-middleware,3.1.3,MIT -webpack-dev-server,3.1.4,MIT -webpack-log,1.2.0,MIT webpack-rails,0.9.10,MIT webpack-sources,1.1.0,MIT webpack-stats-plugin,0.2.1,MIT -websocket-driver,0.6.5,MIT -websocket-extensions,0.1.1,MIT -when,3.7.8,MIT which,1.3.0,ISC which-module,2.0.0,ISC wide-align,1.1.2,ISC -widest-line,2.0.0,MIT wikicloth,0.8.1,MIT -window-size,0.1.0,MIT -with-callback,1.0.2,MIT -wordwrap,0.0.2,MIT -wordwrap,0.0.3,MIT -wordwrap,1.0.0,MIT worker-farm,1.5.2,MIT worker-loader,2.0.0,MIT wrap-ansi,2.1.0,MIT wrappy,1.0.2,ISC -write,0.2.1,MIT -write-file-atomic,2.3.0,ISC -ws,3.3.3,MIT ws,4.0.0,MIT -xdg-basedir,3.0.0,MIT xml-simple,1.1.5,ruby xmlhttprequest,1.8.0,MIT -xmlhttprequest-ssl,1.5.5,MIT -xregexp,2.0.0,MIT xtend,4.0.1,MIT xterm,3.5.0,MIT y18n,3.2.1,ISC y18n,4.0.0,ISC yallist,2.1.2,ISC yallist,3.0.2,ISC -yargs,11.0.0,MIT yargs,11.1.0,MIT -yargs,3.10.0,MIT yargs-parser,9.0.2,ISC -yeast,0.1.2,MIT diff --git a/yarn.lock b/yarn.lock index 0778c5214aa..97aef77cb56 100644 --- a/yarn.lock +++ b/yarn.lock @@ -82,9 +82,9 @@ version "1.29.0" resolved "https://registry.yarnpkg.com/@gitlab-org/gitlab-svgs/-/gitlab-svgs-1.29.0.tgz#03b65b513f9099bbda6ecf94d673a2952f8c6c70" -"@gitlab-org/gitlab-ui@1.0.5": - version "1.0.5" - resolved "https://registry.yarnpkg.com/@gitlab-org/gitlab-ui/-/gitlab-ui-1.0.5.tgz#a64b402650494115c8b494a44b72c2d6fbf33fff" +"@gitlab-org/gitlab-ui@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@gitlab-org/gitlab-ui/-/gitlab-ui-1.2.0.tgz#1d9bf067c2ccf70bcc8e8150644dac475106f3c8" dependencies: "@gitlab-org/gitlab-svgs" "^1.23.0" bootstrap-vue "^2.0.0-rc.11" @@ -272,11 +272,7 @@ "@webassemblyjs/wast-parser" "1.5.13" long "^3.2.0" -abbrev@1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" - -abbrev@1.0.x: +abbrev@1, abbrev@1.0.x: version "1.0.9" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" @@ -307,20 +303,10 @@ acorn@^5.0.0, acorn@^5.3.0, acorn@^5.5.0, acorn@^5.6.2: version "5.7.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.1.tgz#f095829297706a7c9776958c0afc8930a9b9d9d8" -addressparser@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/addressparser/-/addressparser-1.0.1.tgz#47afbe1a2a9262191db6838e4fd1d39b40821746" - after@0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" -agent-base@4, agent-base@^4.1.0, agent-base@^4.2.0, agent-base@~4.2.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.1.tgz#d89e5999f797875674c07d87f260fc41e83e8ca9" - dependencies: - es6-promisify "^5.0.0" - ajv-keywords@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.1.tgz#617997fc5f60576894c435f940d819e135b80762" @@ -329,7 +315,7 @@ ajv-keywords@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.1.0.tgz#ac2b27939c543e95d2c06e7f7f5c27be4aa543be" -ajv@^5.1.0, ajv@^5.2.3, ajv@^5.3.0: +ajv@^5.2.3, ajv@^5.3.0: version "5.5.2" resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" dependencies: @@ -358,16 +344,6 @@ amdefine@>=0.0.4: version "1.0.1" resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" -amqplib@^0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/amqplib/-/amqplib-0.5.2.tgz#d2d7313c7ffaa4d10bcf1e6252de4591b6cc7b63" - dependencies: - bitsyntax "~0.0.4" - bluebird "^3.4.6" - buffer-more-ints "0.0.2" - readable-stream "1.x >=1.1.9" - safe-buffer "^5.0.1" - ansi-align@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-2.0.0.tgz#c36aeccba563b89ceb556f3690f0b1d9e3547f7f" @@ -507,18 +483,6 @@ asn1.js@^4.0.0: inherits "^2.0.1" minimalistic-assert "^1.0.0" -asn1@~0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" - -assert-plus@1.0.0, assert-plus@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" - -assert-plus@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" - assert@^1.1.1: version "1.4.1" resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91" @@ -529,10 +493,6 @@ assign-symbols@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" -ast-types@0.x.x: - version "0.11.3" - resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.11.3.tgz#c20757fe72ee71278ea0ff3d87e5c2ca30d9edf8" - async-each@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" @@ -545,16 +505,12 @@ async@1.x, async@^1.4.0, async@^1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" -async@^2.0.0, async@^2.1.4, async@~2.6.0: +async@^2.0.0, async@^2.1.4: version "2.6.1" resolved "https://registry.yarnpkg.com/async/-/async-2.6.1.tgz#b245a23ca71930044ec53fa46aa00a3e87c6a610" dependencies: lodash "^4.17.10" -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - atob@^2.0.0: version "2.0.3" resolved "https://registry.yarnpkg.com/atob/-/atob-2.0.3.tgz#19c7a760473774468f20b2d2d03372ad7d4cbf5d" @@ -563,30 +519,12 @@ autosize@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/autosize/-/autosize-4.0.0.tgz#7a0599b1ba84d73bd7589b0d9da3870152c69237" -aws-sign2@~0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" - -aws-sign2@~0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" - -aws4@^1.2.1, aws4@^1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" - axios-mock-adapter@^1.15.0: version "1.15.0" resolved "https://registry.yarnpkg.com/axios-mock-adapter/-/axios-mock-adapter-1.15.0.tgz#fbc06825d8302c95c3334d21023bba996255d45d" dependencies: deep-equal "^1.0.1" -axios@^0.15.3: - version "0.15.3" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.15.3.tgz#2c9d638b2e191a08ea1d6cc988eadd6ba5bdc053" - dependencies: - follow-redirects "1.0.0" - axios@^0.17.1: version "0.17.1" resolved "https://registry.yarnpkg.com/axios/-/axios-0.17.1.tgz#2d8e3e5d0bdbd7327f91bc814f5c57660f81824d" @@ -1244,12 +1182,6 @@ batch@0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16" -bcrypt-pbkdf@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" - dependencies: - tweetnacl "^0.14.3" - better-assert@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522" @@ -1276,18 +1208,6 @@ binaryextensions@2: version "2.1.1" resolved "https://registry.yarnpkg.com/binaryextensions/-/binaryextensions-2.1.1.tgz#3209a51ca4a4ad541a3b8d3d6a6d5b83a2485935" -bitsyntax@~0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/bitsyntax/-/bitsyntax-0.0.4.tgz#eb10cc6f82b8c490e3e85698f07e83d46e0cba82" - dependencies: - buffer-more-ints "0.0.2" - -bl@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/bl/-/bl-1.1.2.tgz#fdca871a99713aa00d19e3bbba41c44787a65398" - dependencies: - readable-stream "~2.0.5" - blackst0ne-mermaid@^7.1.0-fixed: version "7.1.0-fixed" resolved "https://registry.yarnpkg.com/blackst0ne-mermaid/-/blackst0ne-mermaid-7.1.0-fixed.tgz#3707b3a113d78610e3068e18a588f46b4688de49" @@ -1303,7 +1223,7 @@ blob@0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.4.tgz#bcf13052ca54463f30f9fc7e95b9a47630a94921" -bluebird@^3.1.1, bluebird@^3.3.0, bluebird@^3.4.6, bluebird@^3.5.1: +bluebird@^3.1.1, bluebird@^3.3.0, bluebird@^3.5.1: version "3.5.1" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" @@ -1337,24 +1257,6 @@ bonjour@^3.5.0: multicast-dns "^6.0.1" multicast-dns-service-types "^1.1.0" -boom@2.x.x: - version "2.10.1" - resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" - dependencies: - hoek "2.x.x" - -boom@4.x.x: - version "4.3.1" - resolved "https://registry.yarnpkg.com/boom/-/boom-4.3.1.tgz#4f8a3005cb4a7e3889f749030fd25b96e01d2e31" - dependencies: - hoek "4.x.x" - -boom@5.x.x: - version "5.2.0" - resolved "https://registry.yarnpkg.com/boom/-/boom-5.2.0.tgz#5dd9da6ee3a5f302077436290cb717d3f4a54e02" - dependencies: - hoek "4.x.x" - bootstrap-vue@^2.0.0-rc.11: version "2.0.0-rc.11" resolved "https://registry.yarnpkg.com/bootstrap-vue/-/bootstrap-vue-2.0.0-rc.11.tgz#47aaa6d2a8d390477de75e636d8ea652b1d03f59" @@ -1476,10 +1378,6 @@ buffer-indexof@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/buffer-indexof/-/buffer-indexof-1.1.0.tgz#f54f647c4f4e25228baa656a2e57e43d5f270982" -buffer-more-ints@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/buffer-more-ints/-/buffer-more-ints-0.0.2.tgz#26b3885d10fa13db7fc01aae3aab870199e0124c" - buffer-xor@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" @@ -1492,18 +1390,6 @@ buffer@^4.3.0: ieee754 "^1.1.4" isarray "^1.0.0" -buildmail@4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/buildmail/-/buildmail-4.0.1.tgz#877f7738b78729871c9a105e3b837d2be11a7a72" - dependencies: - addressparser "1.0.1" - libbase64 "0.1.0" - libmime "3.0.0" - libqp "1.1.0" - nodemailer-fetch "1.6.0" - nodemailer-shared "1.1.0" - punycode "1.4.1" - builtin-modules@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" @@ -1610,14 +1496,6 @@ capture-stack-trace@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz#4a6fa07399c26bba47f0b2496b4d0fb408c5550d" -caseless@~0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7" - -caseless@~0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" - center-align@^0.1.1: version "0.1.3" resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" @@ -1625,7 +1503,7 @@ center-align@^0.1.1: align-text "^0.1.3" lazy-cache "^1.0.3" -chalk@1.1.3, chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: +chalk@1.1.3, chalk@^1.0.0, chalk@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" dependencies: @@ -1703,7 +1581,7 @@ circular-json@^0.3.1: version "0.3.3" resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" -circular-json@^0.5.4: +circular-json@^0.5.5: version "0.5.5" resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.5.5.tgz#64182ef359042d37cd8e767fc9de878b1e9447d3" @@ -1815,13 +1693,7 @@ combine-lists@^1.0.0: dependencies: lodash "^4.5.0" -combined-stream@1.0.6, combined-stream@^1.0.5, combined-stream@~1.0.5: - version "1.0.6" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.6.tgz#723e7df6e801ac5613113a7e445a9b69cb632818" - dependencies: - delayed-stream "~1.0.0" - -commander@2, commander@^2.13.0, commander@^2.15.1, commander@^2.9.0: +commander@2, commander@^2.13.0, commander@^2.15.1: version "2.15.1" resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" @@ -1977,7 +1849,7 @@ core-js@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.3.0.tgz#fab83fbb0b2d8dc85fa636c4b9d34c75420c6d65" -core-util-is@1.0.2, core-util-is@~1.0.0: +core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" @@ -2042,18 +1914,6 @@ cross-spawn@^6.0.5: version "0.0.2" resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" -cryptiles@2.x.x: - version "2.0.5" - resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" - dependencies: - boom "2.x.x" - -cryptiles@3.x.x: - version "3.1.2" - resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-3.1.2.tgz#a89fbb220f5ce25ec56e8c4aa8a4fd7b5b0d29fe" - dependencies: - boom "5.x.x" - crypto-browserify@^3.11.0: version "3.12.0" resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" @@ -2351,16 +2211,6 @@ dagre-layout@^0.8.0: graphlib "^2.1.1" lodash "^4.17.4" -dashdash@^1.12.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" - dependencies: - assert-plus "^1.0.0" - -data-uri-to-buffer@1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-1.2.0.tgz#77163ea9c20d8641b4707e8f18abdf9a78f34835" - date-format@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/date-format/-/date-format-1.2.0.tgz#615e828e233dd1ab9bb9ae0950e0ceccfa6ecad8" @@ -2377,19 +2227,19 @@ de-indent@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/de-indent/-/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d" -debug@2, debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.6, debug@^2.6.8, debug@^2.6.9, debug@~2.6.4, debug@~2.6.6: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - dependencies: - ms "2.0.0" - debug@2.6.8: version "2.6.8" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.8.tgz#e731531ca2ede27d188222427da17821d68ff4fc" dependencies: ms "2.0.0" -debug@3.1.0, debug@^3.0.1, debug@^3.1.0, debug@~3.1.0: +debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.6, debug@^2.6.8, debug@^2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + dependencies: + ms "2.0.0" + +debug@^3.0.1, debug@^3.1.0, debug@~3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" dependencies: @@ -2457,14 +2307,6 @@ define-property@^2.0.2: is-descriptor "^1.0.2" isobject "^3.0.1" -degenerator@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/degenerator/-/degenerator-1.0.4.tgz#fcf490a37ece266464d9cc431ab98c5819ced095" - dependencies: - ast-types "0.x.x" - escodegen "1.x.x" - esprima "3.x.x" - del@^2.0.2: version "2.2.2" resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" @@ -2488,10 +2330,6 @@ del@^3.0.0: pify "^3.0.0" rimraf "^2.2.8" -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - delegate@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/delegate/-/delegate-3.1.2.tgz#1e1bc6f5cadda6cb6cbf7e6d05d0bcdd5712aebe" @@ -2504,10 +2342,6 @@ depd@1.1.1, depd@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359" -depd@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" - des.js@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc" @@ -2630,10 +2464,6 @@ dot-prop@^4.1.0, dot-prop@^4.1.1: dependencies: is-obj "^1.0.0" -double-ended-queue@^2.1.0-0: - version "2.1.0-0" - resolved "https://registry.yarnpkg.com/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz#103d3527fd31528f40188130c841efdd78264e5c" - dropzone@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/dropzone/-/dropzone-4.2.0.tgz#fbe7acbb9918e0706489072ef663effeef8a79f3" @@ -2655,12 +2485,6 @@ duplexify@^3.4.2, duplexify@^3.5.3: readable-stream "^2.0.0" stream-shift "^1.0.0" -ecc-jsbn@~0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" - dependencies: - jsbn "~0.1.0" - editions@^1.3.3: version "1.3.4" resolved "https://registry.yarnpkg.com/editions/-/editions-1.3.4.tgz#3662cb592347c3168eb8e498a0ff73271d67f50b" @@ -2709,9 +2533,9 @@ end-of-stream@^1.0.0, end-of-stream@^1.1.0: dependencies: once "^1.4.0" -engine.io-client@~3.1.0: - version "3.1.5" - resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-3.1.5.tgz#85de17666560327ef1817978f6e3f8101ded2c47" +engine.io-client@~3.2.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-3.2.1.tgz#6f54c0475de487158a1a7c77d10178708b6add36" dependencies: component-emitter "1.2.1" component-inherit "0.0.3" @@ -2735,9 +2559,9 @@ engine.io-parser@~2.1.0, engine.io-parser@~2.1.1: blob "0.0.4" has-binary2 "~1.0.2" -engine.io@~3.1.0: - version "3.1.5" - resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-3.1.5.tgz#0e7ef9d690eb0b35597f1d4ad02a26ca2dba3845" +engine.io@~3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-3.2.0.tgz#54332506f42f2edc71690d2f2a42349359f3bf7d" dependencies: accepts "~1.3.4" base64id "1.0.0" @@ -2745,8 +2569,6 @@ engine.io@~3.1.0: debug "~3.1.0" engine.io-parser "~2.1.0" ws "~3.3.1" - optionalDependencies: - uws "~9.14.0" enhanced-resolve@^4.0.0, enhanced-resolve@^4.1.0: version "4.1.0" @@ -2802,20 +2624,10 @@ es-to-primitive@^1.1.1: is-date-object "^1.0.1" is-symbol "^1.0.1" -es6-promise@^4.0.3: - version "4.2.4" - resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.4.tgz#dc4221c2b16518760bd8c39a52d8f356fc00ed29" - es6-promise@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.0.2.tgz#010d5858423a5f118979665f46486a95c6ee2bb6" -es6-promisify@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" - dependencies: - es6-promise "^4.0.3" - escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" @@ -2835,17 +2647,6 @@ escodegen@1.8.x: optionalDependencies: source-map "~0.2.0" -escodegen@1.x.x: - version "1.9.0" - resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.9.0.tgz#9811a2f265dc1cd3894420ee3717064b632b8852" - dependencies: - esprima "^3.1.3" - estraverse "^4.2.0" - esutils "^2.0.2" - optionator "^0.8.1" - optionalDependencies: - source-map "~0.5.6" - eslint-config-airbnb-base@^12.1.0: version "12.1.0" resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-12.1.0.tgz#386441e54a12ccd957b0a92564a4bafebd747944" @@ -2993,10 +2794,6 @@ esprima@2.7.x, esprima@^2.7.1: version "2.7.3" resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" -esprima@3.x.x, esprima@^3.1.3: - 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" @@ -3160,7 +2957,7 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2: assign-symbols "^1.0.0" is-extendable "^1.0.1" -extend@3, extend@^3.0.0, extend@~3.0.0, extend@~3.0.1: +extend@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" @@ -3193,14 +2990,6 @@ extglob@^2.0.4: snapdragon "^0.8.1" to-regex "^3.0.1" -extsprintf@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" - -extsprintf@^1.2.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" - fast-deep-equal@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz#96256a3bc975595eb36d82e9929d060d893439ff" @@ -3249,10 +3038,6 @@ file-loader@^1.1.11: loader-utils "^1.0.2" schema-utils "^0.4.5" -file-uri-to-path@1: - version "1.0.0" - resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" - fileset@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/fileset/-/fileset-2.0.3.tgz#8e7548a96d3cc2327ee5e674168723a333bba2a0" @@ -3326,12 +3111,6 @@ flush-write-stream@^1.0.0: inherits "^2.0.1" readable-stream "^2.0.4" -follow-redirects@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.0.0.tgz#8e34298cbd2e176f254effec75a1c78cc849fd37" - dependencies: - debug "^2.2.0" - follow-redirects@^1.2.5: version "1.2.6" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.2.6.tgz#4dcdc7e4ab3dd6765a97ff89c3b4c258117c79bf" @@ -3346,26 +3125,6 @@ foreach@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" -forever-agent@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" - -form-data@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.0.0.tgz#6f0aebadcc5da16c13e1ecc11137d85f9b883b25" - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.5" - mime-types "^2.1.11" - -form-data@~2.3.0, form-data@~2.3.1: - version "2.3.2" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.2.tgz#4970498be604c20c005d4f5c23aecd21d6b49099" - dependencies: - asynckit "^0.4.0" - combined-stream "1.0.6" - mime-types "^2.1.12" - formdata-polyfill@^3.0.11: version "3.0.11" resolved "https://registry.yarnpkg.com/formdata-polyfill/-/formdata-polyfill-3.0.11.tgz#c82b4b4bea3356c0a6752219e54ce1edb2a7fb5b" @@ -3427,13 +3186,6 @@ fsevents@^1.2.2: nan "^2.9.2" node-pre-gyp "^0.10.0" -ftp@~0.3.10: - version "0.3.10" - resolved "https://registry.yarnpkg.com/ftp/-/ftp-0.3.10.tgz#9197d861ad8142f3e63d5a83bfe4c59f7330885d" - dependencies: - readable-stream "1.1.x" - xregexp "2.0.0" - function-bind@^1.0.2, function-bind@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" @@ -3459,16 +3211,6 @@ gauge@~2.7.3: strip-ansi "^3.0.1" wide-align "^1.1.0" -generate-function@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74" - -generate-object-property@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" - dependencies: - is-property "^1.0.0" - get-caller-file@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" @@ -3481,27 +3223,10 @@ get-stream@3.0.0, get-stream@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" -get-uri@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/get-uri/-/get-uri-2.0.2.tgz#5c795e71326f6ca1286f2fc82575cd2bab2af578" - dependencies: - data-uri-to-buffer "1" - debug "2" - extend "3" - file-uri-to-path "1" - ftp "~0.3.10" - readable-stream "2" - get-value@^2.0.3, get-value@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" -getpass@^0.1.1: - version "0.1.7" - resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" - dependencies: - assert-plus "^1.0.0" - gettext-extractor-vue@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/gettext-extractor-vue/-/gettext-extractor-vue-4.0.1.tgz#69d2737eb8f1938803ffcf9317133ed59fb2372f" @@ -3664,26 +3389,6 @@ handlebars@^4.0.1, handlebars@^4.0.3: optionalDependencies: uglify-js "^2.6" -har-schema@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" - -har-validator@~2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-2.0.6.tgz#cdcbc08188265ad119b6a5a7c8ab70eecfb5d27d" - dependencies: - chalk "^1.1.1" - commander "^2.9.0" - is-my-json-valid "^2.12.4" - pinkie-promise "^2.0.0" - -har-validator@~5.0.3: - version "5.0.3" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.0.3.tgz#ba402c266194f15956ef15e0fcf242993f6a7dfd" - dependencies: - ajv "^5.1.0" - har-schema "^2.0.0" - has-ansi@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" @@ -3779,35 +3484,10 @@ hash.js@^1.0.0, hash.js@^1.0.3: inherits "^2.0.3" minimalistic-assert "^1.0.0" -hawk@~3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" - dependencies: - boom "2.x.x" - cryptiles "2.x.x" - hoek "2.x.x" - sntp "1.x.x" - -hawk@~6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/hawk/-/hawk-6.0.2.tgz#af4d914eb065f9b5ce4d9d11c1cb2126eecc3038" - dependencies: - boom "4.x.x" - cryptiles "3.x.x" - hoek "4.x.x" - sntp "2.x.x" - he@^1.1.0, he@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" -hipchat-notifier@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/hipchat-notifier/-/hipchat-notifier-1.1.0.tgz#b6d249755437c191082367799d3ba9a0f23b231e" - dependencies: - lodash "^4.0.0" - request "^2.0.0" - hmac-drbg@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" @@ -3816,14 +3496,6 @@ hmac-drbg@^1.0.0: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" -hoek@2.x.x: - version "2.16.3" - resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" - -hoek@4.x.x: - version "4.2.1" - resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.2.1.tgz#9634502aa12c445dd5a7c5734b572bb8738aacbb" - home-or-tmp@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" @@ -3876,22 +3548,6 @@ http-errors@1.6.2, http-errors@~1.6.1, http-errors@~1.6.2: setprototypeof "1.0.3" statuses ">= 1.3.1 < 2" -http-errors@1.6.3: - version "1.6.3" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" - dependencies: - depd "~1.1.2" - inherits "2.0.3" - setprototypeof "1.1.0" - statuses ">= 1.4.0 < 2" - -http-proxy-agent@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz#e4821beef5b2142a2026bd73926fe537631c5405" - dependencies: - agent-base "4" - debug "3.1.0" - http-proxy-middleware@~0.18.0: version "0.18.0" resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-0.18.0.tgz#0987e6bb5a5606e5a69168d8f967a87f15dd8aab" @@ -3908,55 +3564,17 @@ http-proxy@^1.13.0, http-proxy@^1.16.2: eventemitter3 "1.x.x" requires-port "1.x.x" -http-signature@~1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" - dependencies: - assert-plus "^0.2.0" - jsprim "^1.2.2" - sshpk "^1.7.0" - -http-signature@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" - dependencies: - assert-plus "^1.0.0" - jsprim "^1.2.2" - sshpk "^1.7.0" - -httpntlm@1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/httpntlm/-/httpntlm-1.6.1.tgz#ad01527143a2e8773cfae6a96f58656bb52a34b2" - dependencies: - httpreq ">=0.4.22" - underscore "~1.7.0" - -httpreq@>=0.4.22: - version "0.4.24" - resolved "https://registry.yarnpkg.com/httpreq/-/httpreq-0.4.24.tgz#4335ffd82cd969668a39465c929ac61d6393627f" - https-browserify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" -https-proxy-agent@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz#51552970fa04d723e04c56d04178c3f92592bbc0" - dependencies: - agent-base "^4.1.0" - debug "^3.1.0" - -iconv-lite@0.4, iconv-lite@0.4.23, iconv-lite@^0.4.22, iconv-lite@^0.4.4, iconv-lite@~0.4.13: +iconv-lite@0.4, iconv-lite@^0.4.17, iconv-lite@^0.4.22, iconv-lite@^0.4.4, iconv-lite@~0.4.13: version "0.4.23" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" dependencies: safer-buffer ">= 2.1.2 < 3" -iconv-lite@0.4.15: - version "0.4.15" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb" - -iconv-lite@0.4.19, iconv-lite@^0.4.17: +iconv-lite@0.4.19: version "0.4.19" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" @@ -4032,14 +3650,6 @@ indexof@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" -inflection@~1.12.0: - version "1.12.0" - resolved "https://registry.yarnpkg.com/inflection/-/inflection-1.12.0.tgz#a200935656d6f5f6bc4dc7502e1aecb703228416" - -inflection@~1.3.0: - version "1.3.8" - resolved "https://registry.yarnpkg.com/inflection/-/inflection-1.3.8.tgz#cbd160da9f75b14c3cc63578d4f396784bf3014e" - inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" @@ -4141,7 +3751,7 @@ invert-kv@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" -ip@^1.1.0, ip@^1.1.2, ip@^1.1.4, ip@^1.1.5: +ip@^1.1.0, ip@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" @@ -4266,20 +3876,6 @@ is-installed-globally@^0.1.0: global-dirs "^0.1.0" is-path-inside "^1.0.0" -is-my-ip-valid@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz#7b351b8e8edd4d3995d4d066680e664d94696824" - -is-my-json-valid@^2.12.4: - version "2.17.2" - resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.17.2.tgz#6b2103a288e94ef3de5cf15d29dd85fc4b78d65c" - dependencies: - generate-function "^2.0.0" - generate-object-property "^1.1.0" - is-my-ip-valid "^1.0.0" - jsonpointer "^4.0.0" - xtend "^4.0.0" - is-npm@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-1.0.0.tgz#f2fb63a65e4905b406c86072765a1a4dc793b9f4" @@ -4342,10 +3938,6 @@ is-promise@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" -is-property@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" - is-redirect@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24" @@ -4374,10 +3966,6 @@ is-symbol@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.1.tgz#3cc59f00025194b6ab2e38dbae6689256b660572" -is-typedarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - is-utf8@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" @@ -4390,10 +3978,6 @@ is-wsl@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" -isarray@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" - isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" @@ -4420,10 +4004,6 @@ isobject@^3.0.0, isobject@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" -isstream@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" - istanbul-api@^1.1.14: version "1.2.1" resolved "https://registry.yarnpkg.com/istanbul-api/-/istanbul-api-1.2.1.tgz#0c60a0515eb11c7d65c6b50bba2c6e999acd8620" @@ -4568,10 +4148,6 @@ js-yaml@3.x, js-yaml@^3.7.0, js-yaml@^3.9.1: argparse "^1.0.7" esprima "^4.0.0" -jsbn@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" - jsesc@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" @@ -4596,18 +4172,10 @@ json-schema-traverse@^0.3.0: version "0.3.1" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" -json-schema@0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" - json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" -json-stringify-safe@5.0.x, json-stringify-safe@~5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" - json3@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" @@ -4616,19 +4184,6 @@ json5@^0.5.0, json5@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" -jsonpointer@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" - -jsprim@^1.2.2: - version "1.4.1" - resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" - dependencies: - assert-plus "1.0.0" - extsprintf "1.3.0" - json-schema "0.2.3" - verror "1.10.0" - jszip-utils@^0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/jszip-utils/-/jszip-utils-0.0.2.tgz#457d5cbca60a1c2e0706e9da2b544e8e7bc50bf8" @@ -4686,9 +4241,9 @@ karma-webpack@^4.0.0-beta.0: source-map "^0.5.6" webpack-dev-middleware "^3.0.1" -karma@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/karma/-/karma-2.0.4.tgz#b399785f57e9bab1d3c4384db33fef4dec8ae349" +karma@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/karma/-/karma-3.0.0.tgz#6da83461a8a28d8224575c3b5b874e271b4730c3" dependencies: bluebird "^3.3.0" body-parser "^1.16.1" @@ -4705,24 +4260,24 @@ karma@^2.0.4: http-proxy "^1.13.0" isbinaryfile "^3.0.0" lodash "^4.17.4" - log4js "^2.5.3" - mime "^1.3.4" + log4js "^3.0.0" + mime "^2.3.1" minimatch "^3.0.2" optimist "^0.6.1" qjobs "^1.1.4" range-parser "^1.2.0" rimraf "^2.6.0" safe-buffer "^5.0.1" - socket.io "2.0.4" + socket.io "2.1.1" source-map "^0.6.1" tmp "0.0.33" useragent "2.2.1" -katex@^0.8.3: - version "0.8.3" - resolved "https://registry.yarnpkg.com/katex/-/katex-0.8.3.tgz#909d99864baf964c3ccae39c4a99a8e0fb9a1bd0" +katex@^0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/katex/-/katex-0.9.0.tgz#26a7d082c21d53725422d2d71da9b2d8455fbd4a" dependencies: - match-at "^0.1.0" + match-at "^0.1.1" keyv@3.0.0: version "3.0.0" @@ -4783,22 +4338,6 @@ levn@^0.3.0, levn@~0.3.0: prelude-ls "~1.1.2" type-check "~0.3.2" -libbase64@0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/libbase64/-/libbase64-0.1.0.tgz#62351a839563ac5ff5bd26f12f60e9830bb751e6" - -libmime@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/libmime/-/libmime-3.0.0.tgz#51a1a9e7448ecbd32cda54421675bb21bc093da6" - dependencies: - iconv-lite "0.4.15" - libbase64 "0.1.0" - libqp "1.1.0" - -libqp@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/libqp/-/libqp-1.1.0.tgz#f5e6e06ad74b794fb5b5b66988bf728ef1dedbe8" - lie@~3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/lie/-/lie-3.1.1.tgz#9a436b2cc7746ca59de7a41fa469b3efb76bd87e" @@ -4891,7 +4430,7 @@ lodash@4.17.4: version "4.17.4" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" -lodash@^4.0.0, lodash@^4.11.1, lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.0, lodash@^4.3.0, lodash@^4.5.0: +lodash@^4.0.0, lodash@^4.11.1, lodash@^4.17.10, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.0, lodash@^4.3.0, lodash@^4.5.0: version "4.17.10" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" @@ -4901,32 +4440,15 @@ log-symbols@^2.1.0: dependencies: chalk "^2.0.1" -log4js@^2.5.3: - version "2.11.0" - resolved "https://registry.yarnpkg.com/log4js/-/log4js-2.11.0.tgz#bf3902eff65c6923d9ce9cfbd2db54160e34005a" +log4js@^3.0.0: + version "3.0.5" + resolved "https://registry.yarnpkg.com/log4js/-/log4js-3.0.5.tgz#b80146bfebad68b430d4f3569556d8a6edfef303" dependencies: - circular-json "^0.5.4" + circular-json "^0.5.5" date-format "^1.2.0" debug "^3.1.0" - semver "^5.5.0" + rfdc "^1.1.2" streamroller "0.7.0" - optionalDependencies: - amqplib "^0.5.2" - axios "^0.15.3" - hipchat-notifier "^1.1.0" - loggly "^1.1.0" - mailgun-js "^0.18.0" - nodemailer "^2.5.0" - redis "^2.7.1" - slack-node "~0.2.0" - -loggly@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/loggly/-/loggly-1.1.1.tgz#0a0fc1d3fa3a5ec44fdc7b897beba2a4695cebee" - dependencies: - json-stringify-safe "5.0.x" - request "2.75.x" - timespan "2.3.x" loglevel@^1.4.1: version "1.4.1" @@ -4980,27 +4502,6 @@ lz-string@^1.4.4: version "1.4.4" resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.4.4.tgz#c0d8eaf36059f705796e1e344811cf4c498d3a26" -mailcomposer@4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/mailcomposer/-/mailcomposer-4.0.1.tgz#0e1c44b2a07cf740ee17dc149ba009f19cadfeb4" - dependencies: - buildmail "4.0.1" - libmime "3.0.0" - -mailgun-js@^0.18.0: - version "0.18.1" - resolved "https://registry.yarnpkg.com/mailgun-js/-/mailgun-js-0.18.1.tgz#ee39aa18d7bb598a5ce9ede84afb681defc8a6b0" - dependencies: - async "~2.6.0" - debug "~3.1.0" - form-data "~2.3.0" - inflection "~1.12.0" - is-stream "^1.1.0" - path-proxy "~1.0.0" - promisify-call "^2.0.2" - proxy-agent "~3.0.0" - tsscmp "~1.0.0" - make-dir@^1.0.0: version "1.2.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.2.0.tgz#6d6a49eead4aae296c53bbf3a1a008bd6c89469b" @@ -5033,7 +4534,7 @@ marked@^0.3.12: version "0.3.12" resolved "https://registry.yarnpkg.com/marked/-/marked-0.3.12.tgz#7cf25ff2252632f3fe2406bde258e94eee927519" -match-at@^0.1.0: +match-at@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/match-at/-/match-at-0.1.1.tgz#25d040d291777704d5e6556bbb79230ec2de0540" @@ -5123,7 +4624,7 @@ miller-rabin@^4.0.0: version "1.33.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db" -mime-types@^2.1.11, mime-types@^2.1.12, mime-types@~2.1.15, mime-types@~2.1.16, mime-types@~2.1.17, mime-types@~2.1.18, mime-types@~2.1.7: +mime-types@~2.1.15, mime-types@~2.1.16, mime-types@~2.1.18: version "2.1.18" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8" dependencies: @@ -5133,11 +4634,7 @@ mime@1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" -mime@^1.3.4: - version "1.6.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" - -mime@^2.0.3, mime@^2.1.0: +mime@^2.0.3, mime@^2.1.0, mime@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/mime/-/mime-2.3.1.tgz#b1621c54d63b97c47d3cfe7f7215f7d64517c369" @@ -5303,10 +4800,6 @@ neo-async@^2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.5.0.tgz#76b1c823130cca26acfbaccc8fbaf0a2fa33b18f" -netmask@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/netmask/-/netmask-1.0.6.tgz#20297e89d86f6f6400f250d9f4f6b4c1945fcd35" - nice-try@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.4.tgz#d93962f6c52f2c1558c0fbda6d512819f1efe1c4" @@ -5365,59 +4858,6 @@ node-pre-gyp@^0.10.0: semver "^5.3.0" tar "^4" -node-uuid@~1.4.7: - version "1.4.8" - resolved "https://registry.yarnpkg.com/node-uuid/-/node-uuid-1.4.8.tgz#b040eb0923968afabf8d32fb1f17f1167fdab907" - -nodemailer-direct-transport@3.3.2: - version "3.3.2" - resolved "https://registry.yarnpkg.com/nodemailer-direct-transport/-/nodemailer-direct-transport-3.3.2.tgz#e96fafb90358560947e569017d97e60738a50a86" - dependencies: - nodemailer-shared "1.1.0" - smtp-connection "2.12.0" - -nodemailer-fetch@1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/nodemailer-fetch/-/nodemailer-fetch-1.6.0.tgz#79c4908a1c0f5f375b73fe888da9828f6dc963a4" - -nodemailer-shared@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/nodemailer-shared/-/nodemailer-shared-1.1.0.tgz#cf5994e2fd268d00f5cf0fa767a08169edb07ec0" - dependencies: - nodemailer-fetch "1.6.0" - -nodemailer-smtp-pool@2.8.2: - version "2.8.2" - resolved "https://registry.yarnpkg.com/nodemailer-smtp-pool/-/nodemailer-smtp-pool-2.8.2.tgz#2eb94d6cf85780b1b4725ce853b9cbd5e8da8c72" - dependencies: - nodemailer-shared "1.1.0" - nodemailer-wellknown "0.1.10" - smtp-connection "2.12.0" - -nodemailer-smtp-transport@2.7.2: - version "2.7.2" - resolved "https://registry.yarnpkg.com/nodemailer-smtp-transport/-/nodemailer-smtp-transport-2.7.2.tgz#03d71c76314f14ac7dbc7bf033a6a6d16d67fb77" - dependencies: - nodemailer-shared "1.1.0" - nodemailer-wellknown "0.1.10" - smtp-connection "2.12.0" - -nodemailer-wellknown@0.1.10: - version "0.1.10" - resolved "https://registry.yarnpkg.com/nodemailer-wellknown/-/nodemailer-wellknown-0.1.10.tgz#586db8101db30cb4438eb546737a41aad0cf13d5" - -nodemailer@^2.5.0: - version "2.7.2" - resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-2.7.2.tgz#f242e649aeeae39b6c7ed740ef7b061c404d30f9" - dependencies: - libmime "3.0.0" - mailcomposer "4.0.1" - nodemailer-direct-transport "3.3.2" - nodemailer-shared "1.1.0" - nodemailer-smtp-pool "2.8.2" - nodemailer-smtp-transport "2.7.2" - socks "1.1.9" - nodemon@^1.18.2: version "1.18.2" resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-1.18.2.tgz#36b89c790da70c4f270e2cc0718723131bc04abb" @@ -5509,10 +4949,6 @@ number-is-nan@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" -oauth-sign@~0.8.1, oauth-sign@~0.8.2: - version "0.8.2" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" - object-assign@^4.0.1, object-assign@^4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" @@ -5688,29 +5124,6 @@ p-try@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" -pac-proxy-agent@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/pac-proxy-agent/-/pac-proxy-agent-2.0.2.tgz#90d9f6730ab0f4d2607dcdcd4d3d641aa26c3896" - dependencies: - agent-base "^4.2.0" - debug "^3.1.0" - get-uri "^2.0.0" - http-proxy-agent "^2.1.0" - https-proxy-agent "^2.2.1" - pac-resolver "^3.0.0" - raw-body "^2.2.0" - socks-proxy-agent "^3.0.0" - -pac-resolver@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pac-resolver/-/pac-resolver-3.0.0.tgz#6aea30787db0a891704deb7800a722a7615a6f26" - dependencies: - co "^4.6.0" - degenerator "^1.0.4" - ip "^1.1.5" - netmask "^1.0.6" - thunkify "^2.1.2" - package-json@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/package-json/-/package-json-4.0.1.tgz#8869a0401253661c4c4ca3da6c2121ed555f5eed" @@ -5806,12 +5219,6 @@ path-parse@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" -path-proxy@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/path-proxy/-/path-proxy-1.0.0.tgz#18e8a36859fc9d2f1a53b48dee138543c020de5e" - dependencies: - inflection "~1.3.0" - path-to-regexp@0.1.7: version "0.1.7" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" @@ -5846,10 +5253,6 @@ pbkdf2@^3.0.3: safe-buffer "^5.0.1" sha.js "^2.4.8" -performance-now@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" - pify@^2.0.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" @@ -6003,12 +5406,6 @@ promise-inflight@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" -promisify-call@^2.0.2: - version "2.0.4" - resolved "https://registry.yarnpkg.com/promisify-call/-/promisify-call-2.0.4.tgz#d48c2d45652ccccd52801ddecbd533a6d4bd5fba" - dependencies: - with-callback "^1.0.2" - proxy-addr@~2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.3.tgz#355f262505a621646b3130a728eb647e22055341" @@ -6016,23 +5413,6 @@ proxy-addr@~2.0.2: forwarded "~0.1.2" ipaddr.js "1.6.0" -proxy-agent@~3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/proxy-agent/-/proxy-agent-3.0.1.tgz#4fb7b61b1476d0fe8e3a3384d90e2460bbded3f9" - dependencies: - agent-base "^4.2.0" - debug "^3.1.0" - http-proxy-agent "^2.1.0" - https-proxy-agent "^2.2.1" - lru-cache "^4.1.2" - pac-proxy-agent "^2.0.1" - proxy-from-env "^1.0.0" - socks-proxy-agent "^4.0.1" - -proxy-from-env@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.0.0.tgz#33c50398f70ea7eb96d21f7b817630a55791c7ee" - prr@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" @@ -6078,26 +5458,18 @@ pumpify@^1.3.3: inherits "^2.0.3" pump "^2.0.0" -punycode@1.3.2: +punycode@1.3.2, punycode@^1.2.4: version "1.3.2" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" -punycode@1.4.1, punycode@^1.2.4, punycode@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" - qjobs@^1.1.4: version "1.2.0" resolved "https://registry.yarnpkg.com/qjobs/-/qjobs-1.2.0.tgz#c45e9c61800bd087ef88d7e256423bdd49e5d071" -qs@6.5.1, qs@~6.5.1: +qs@6.5.1: version "6.5.1" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" -qs@~6.2.0: - version "6.2.3" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.2.3.tgz#1cfcb25c10a9b2b483053ff39f5dfc9233908cfe" - query-string@^5.0.1: version "5.1.1" resolved "https://registry.yarnpkg.com/query-string/-/query-string-5.1.1.tgz#a78c012b71c17e05f2e3fa2319dd330682efb3cb" @@ -6158,15 +5530,6 @@ raw-body@2.3.2: iconv-lite "0.4.19" unpipe "1.0.0" -raw-body@^2.2.0: - version "2.3.3" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.3.tgz#1b324ece6b5706e153855bc1148c65bb7f6ea0c3" - dependencies: - bytes "3.0.0" - http-errors "1.6.3" - iconv-lite "0.4.23" - unpipe "1.0.0" - raw-loader@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/raw-loader/-/raw-loader-0.5.1.tgz#0c3d0beaed8a01c966d9787bf778281252a979aa" @@ -6210,7 +5573,7 @@ read-pkg@^2.0.0: normalize-package-data "^2.3.2" path-type "^2.0.0" -"readable-stream@1 || 2", readable-stream@2, readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.2.9, readable-stream@^2.3.0, readable-stream@^2.3.3, readable-stream@^2.3.6: +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.2.9, readable-stream@^2.3.0, readable-stream@^2.3.3, readable-stream@^2.3.6: version "2.3.6" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" dependencies: @@ -6222,16 +5585,7 @@ read-pkg@^2.0.0: string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@1.1.x, "readable-stream@1.x >=1.1.9": - version "1.1.14" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - -readable-stream@~2.0.5, readable-stream@~2.0.6: +readable-stream@~2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" dependencies: @@ -6258,22 +5612,6 @@ redent@^1.0.0: indent-string "^2.1.0" strip-indent "^1.0.1" -redis-commands@^1.2.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/redis-commands/-/redis-commands-1.3.1.tgz#81d826f45fa9c8b2011f4cd7a0fe597d241d442b" - -redis-parser@^2.6.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-2.6.0.tgz#52ed09dacac108f1a631c07e9b69941e7a19504b" - -redis@^2.7.1: - version "2.8.0" - resolved "https://registry.yarnpkg.com/redis/-/redis-2.8.0.tgz#202288e3f58c49f6079d97af7a10e1303ae14b02" - dependencies: - double-ended-queue "^2.1.0-0" - redis-commands "^1.2.0" - redis-parser "^2.6.0" - regenerate@^1.2.1: version "1.3.2" resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.2.tgz#d1941c67bad437e1be76433add5b385f95b19260" @@ -6362,68 +5700,6 @@ repeating@^2.0.0: dependencies: is-finite "^1.0.0" -request@2.75.x: - version "2.75.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.75.0.tgz#d2b8268a286da13eaa5d01adf5d18cc90f657d93" - dependencies: - aws-sign2 "~0.6.0" - aws4 "^1.2.1" - bl "~1.1.2" - caseless "~0.11.0" - combined-stream "~1.0.5" - extend "~3.0.0" - forever-agent "~0.6.1" - form-data "~2.0.0" - har-validator "~2.0.6" - hawk "~3.1.3" - http-signature "~1.1.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.7" - node-uuid "~1.4.7" - oauth-sign "~0.8.1" - qs "~6.2.0" - stringstream "~0.0.4" - tough-cookie "~2.3.0" - tunnel-agent "~0.4.1" - -request@^2.0.0, request@^2.74.0: - version "2.83.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.83.0.tgz#ca0b65da02ed62935887808e6f510381034e3356" - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.6.0" - caseless "~0.12.0" - combined-stream "~1.0.5" - extend "~3.0.1" - forever-agent "~0.6.1" - form-data "~2.3.1" - har-validator "~5.0.3" - hawk "~6.0.2" - http-signature "~1.2.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.17" - oauth-sign "~0.8.2" - performance-now "^2.1.0" - qs "~6.5.1" - safe-buffer "^5.1.1" - stringstream "~0.0.5" - tough-cookie "~2.3.3" - tunnel-agent "^0.6.0" - uuid "^3.1.0" - -requestretry@^1.2.2: - version "1.13.0" - resolved "https://registry.yarnpkg.com/requestretry/-/requestretry-1.13.0.tgz#213ec1006eeb750e8b8ce54176283d15a8d55d94" - dependencies: - extend "^3.0.0" - lodash "^4.15.0" - request "^2.74.0" - when "^3.7.7" - require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" @@ -6488,6 +5764,10 @@ ret@~0.1.10: version "0.1.15" resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" +rfdc@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.1.2.tgz#e6e72d74f5dc39de8f538f65e00c36c18018e349" + right-align@^0.1.1: version "0.1.3" resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" @@ -6543,11 +5823,11 @@ rxjs@^6.1.0: dependencies: tslib "^1.9.0" -safe-buffer@5.1.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: +safe-buffer@5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" -safe-buffer@^5.1.2: +safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" @@ -6727,12 +6007,6 @@ signal-exit@^3.0.0, signal-exit@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" -slack-node@~0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/slack-node/-/slack-node-0.2.0.tgz#de4b8dddaa8b793f61dbd2938104fdabf37dfa30" - dependencies: - requestretry "^1.2.2" - slash@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" @@ -6743,14 +6017,6 @@ slice-ansi@1.0.0: dependencies: is-fullwidth-code-point "^2.0.0" -smart-buffer@^1.0.13, smart-buffer@^1.0.4: - version "1.1.15" - resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-1.1.15.tgz#7f114b5b65fab3e2a35aa775bb12f0d1c649bf16" - -smart-buffer@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.0.1.tgz#07ea1ca8d4db24eb4cac86537d7d18995221ace3" - smooshpack@^0.0.48: version "0.0.48" resolved "https://registry.yarnpkg.com/smooshpack/-/smooshpack-0.0.48.tgz#6fbeaaf59226a1fe500f56aa17185eed377d2823" @@ -6759,13 +6025,6 @@ smooshpack@^0.0.48: codesandbox-import-utils "^1.2.3" lodash.isequal "^4.5.0" -smtp-connection@2.12.0: - version "2.12.0" - resolved "https://registry.yarnpkg.com/smtp-connection/-/smtp-connection-2.12.0.tgz#d76ef9127cb23c2259edb1e8349c2e8d5e2d74c1" - dependencies: - httpntlm "1.6.1" - nodemailer-shared "1.1.0" - snapdragon-node@^2.0.1: version "2.1.1" resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" @@ -6793,58 +6052,47 @@ snapdragon@^0.8.1: source-map-resolve "^0.5.0" use "^2.0.0" -sntp@1.x.x: - version "1.0.9" - resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" - dependencies: - hoek "2.x.x" - -sntp@2.x.x: - version "2.1.0" - resolved "https://registry.yarnpkg.com/sntp/-/sntp-2.1.0.tgz#2c6cec14fedc2222739caf9b5c3d85d1cc5a2cc8" - dependencies: - hoek "4.x.x" - socket.io-adapter@~1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz#2a805e8a14d6372124dd9159ad4502f8cb07f06b" -socket.io-client@2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-2.0.4.tgz#0918a552406dc5e540b380dcd97afc4a64332f8e" +socket.io-client@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-2.1.1.tgz#dcb38103436ab4578ddb026638ae2f21b623671f" dependencies: backo2 "1.0.2" base64-arraybuffer "0.1.5" component-bind "1.0.0" component-emitter "1.2.1" - debug "~2.6.4" - engine.io-client "~3.1.0" + debug "~3.1.0" + engine.io-client "~3.2.0" + has-binary2 "~1.0.2" has-cors "1.1.0" indexof "0.0.1" object-component "0.0.3" parseqs "0.0.5" parseuri "0.0.5" - socket.io-parser "~3.1.1" + socket.io-parser "~3.2.0" to-array "0.1.4" -socket.io-parser@~3.1.1: - version "3.1.2" - resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.1.2.tgz#dbc2282151fc4faebbe40aeedc0772eba619f7f2" +socket.io-parser@~3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.2.0.tgz#e7c6228b6aa1f814e6148aea325b51aa9499e077" dependencies: component-emitter "1.2.1" - debug "~2.6.4" - has-binary2 "~1.0.2" + debug "~3.1.0" isarray "2.0.1" -socket.io@2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-2.0.4.tgz#c1a4590ceff87ecf13c72652f046f716b29e6014" +socket.io@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-2.1.1.tgz#a069c5feabee3e6b214a75b40ce0652e1cfb9980" dependencies: - debug "~2.6.6" - engine.io "~3.1.0" + debug "~3.1.0" + engine.io "~3.2.0" + has-binary2 "~1.0.2" socket.io-adapter "~1.1.0" - socket.io-client "2.0.4" - socket.io-parser "~3.1.1" + socket.io-client "2.1.1" + socket.io-parser "~3.2.0" sockjs-client@1.1.4: version "1.1.4" @@ -6864,41 +6112,6 @@ sockjs@0.3.19: faye-websocket "^0.10.0" uuid "^3.0.1" -socks-proxy-agent@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-3.0.1.tgz#2eae7cf8e2a82d34565761539a7f9718c5617659" - dependencies: - agent-base "^4.1.0" - socks "^1.1.10" - -socks-proxy-agent@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-4.0.1.tgz#5936bf8b707a993079c6f37db2091821bffa6473" - dependencies: - agent-base "~4.2.0" - socks "~2.2.0" - -socks@1.1.9: - version "1.1.9" - resolved "https://registry.yarnpkg.com/socks/-/socks-1.1.9.tgz#628d7e4d04912435445ac0b6e459376cb3e6d691" - dependencies: - ip "^1.1.2" - smart-buffer "^1.0.4" - -socks@^1.1.10: - version "1.1.10" - resolved "https://registry.yarnpkg.com/socks/-/socks-1.1.10.tgz#5b8b7fc7c8f341c53ed056e929b7bf4de8ba7b5a" - dependencies: - ip "^1.1.4" - smart-buffer "^1.0.13" - -socks@~2.2.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/socks/-/socks-2.2.1.tgz#68ad678b3642fbc5d99c64c165bc561eab0215f9" - dependencies: - ip "^1.1.5" - smart-buffer "^4.0.1" - sort-keys@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-2.0.0.tgz#658535584861ec97d730d6cf41822e1f56684128" @@ -6943,7 +6156,7 @@ source-map@^0.4.4: dependencies: amdefine ">=0.0.4" -source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.1, source-map@~0.5.6: +source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.1: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" @@ -7021,20 +6234,6 @@ srcset@^1.0.0: array-uniq "^1.0.2" number-is-nan "^1.0.0" -sshpk@^1.7.0: - version "1.13.1" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.13.1.tgz#512df6da6287144316dc4c18fe1cf1d940739be3" - dependencies: - asn1 "~0.2.3" - assert-plus "^1.0.0" - dashdash "^1.12.0" - getpass "^0.1.1" - optionalDependencies: - bcrypt-pbkdf "^1.0.0" - ecc-jsbn "~0.1.1" - jsbn "~0.1.0" - tweetnacl "~0.14.0" - ssri@^5.2.4: version "5.2.4" resolved "https://registry.yarnpkg.com/ssri/-/ssri-5.2.4.tgz#9985e14041e65fc397af96542be35724ac11da52" @@ -7048,11 +6247,7 @@ static-extend@^0.1.1: define-property "^0.2.5" object-copy "^0.1.0" -"statuses@>= 1.3.1 < 2", "statuses@>= 1.4.0 < 2": - version "1.5.0" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" - -statuses@~1.3.1: +"statuses@>= 1.3.1 < 2", statuses@~1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" @@ -7132,10 +6327,6 @@ string_decoder@~0.10.x: version "0.10.31" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" -stringstream@~0.0.4, stringstream@~0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" - strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" @@ -7277,10 +6468,6 @@ through@2, through@^2.3.6, through@~2.3, through@~2.3.1: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" -thunkify@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/thunkify/-/thunkify-2.1.2.tgz#faa0e9d230c51acc95ca13a361ac05ca7e04553d" - thunky@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/thunky/-/thunky-0.1.0.tgz#bf30146824e2b6e67b0f2d7a4ac8beb26908684e" @@ -7301,10 +6488,6 @@ timers-browserify@^2.0.4: dependencies: setimmediate "^1.0.4" -timespan@2.3.x: - version "2.3.0" - resolved "https://registry.yarnpkg.com/timespan/-/timespan-2.3.0.tgz#4902ce040bd13d845c8f59b27e9d59bad6f39929" - tiny-emitter@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-2.0.2.tgz#82d27468aca5ade8e5fd1e6d22b57dd43ebdfb7c" @@ -7359,12 +6542,6 @@ touch@^3.1.0: dependencies: nopt "~1.0.10" -tough-cookie@~2.3.0, tough-cookie@~2.3.3: - version "2.3.3" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.3.tgz#0b618a5565b6dea90bf3425d04d55edc475a7561" - dependencies: - punycode "^1.4.1" - traverse@0.6.6: version "0.6.6" resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.6.6.tgz#cbdf560fd7b9af632502fed40f918c157ea97137" @@ -7389,28 +6566,10 @@ tslib@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" -tsscmp@~1.0.0: - version "1.0.5" - resolved "https://registry.yarnpkg.com/tsscmp/-/tsscmp-1.0.5.tgz#7dc4a33af71581ab4337da91d85ca5427ebd9a97" - tty-browserify@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" -tunnel-agent@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - dependencies: - safe-buffer "^5.0.1" - -tunnel-agent@~0.4.1: - version "0.4.3" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" - -tweetnacl@^0.14.3, tweetnacl@~0.14.0: - version "0.14.5" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" - type-check@~0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" @@ -7479,10 +6638,6 @@ underscore@^1.9.0: version "1.9.0" resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.9.0.tgz#31dbb314cfcc88f169cd3692d9149d81a00a73e4" -underscore@~1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.7.0.tgz#6bbaf0877500d36be34ecaa584e0db9fef035209" - union-value@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" @@ -7630,12 +6785,8 @@ utils-merge@1.0.1: resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" uuid@^3.0.1, uuid@^3.1.0: - version "3.2.1" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14" - -uws@~9.14.0: - version "9.14.0" - resolved "https://registry.yarnpkg.com/uws/-/uws-9.14.0.tgz#fac8386befc33a7a3705cbd58dc47b430ca4dd95" + version "3.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" v8-compile-cache@^2.0.0: version "2.0.0" @@ -7652,14 +6803,6 @@ vary@~1.1.1, vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" -verror@1.10.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" - dependencies: - assert-plus "^1.0.0" - core-util-is "1.0.2" - extsprintf "^1.2.0" - visibilityjs@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/visibilityjs/-/visibilityjs-1.2.4.tgz#bff8663da62c8c10ad4ee5ae6a1ae6fac4259d63" @@ -7895,10 +7038,6 @@ websocket-extensions@>=0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.1.tgz#76899499c184b6ef754377c2dbb0cd6cb55d29e7" -when@^3.7.7: - version "3.7.8" - resolved "https://registry.yarnpkg.com/when/-/when-3.7.8.tgz#c7130b6a7ea04693e842cdc9e7a1f2aa39a39f82" - which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" @@ -7925,10 +7064,6 @@ window-size@0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" -with-callback@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/with-callback/-/with-callback-1.0.2.tgz#a09629b9a920028d721404fb435bdcff5c91bc21" - wordwrap@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" @@ -8008,10 +7143,6 @@ xmlhttprequest@1: version "1.8.0" resolved "https://registry.yarnpkg.com/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz#67fe075c5c24fef39f9d65f5f7b7fe75171968fc" -xregexp@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-2.0.0.tgz#52a63e56ca0b84a7f3a5f3d61872f126ad7a5943" - xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" |