diff options
2059 files changed, 15586 insertions, 5737 deletions
diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 41714eefa97..3898206e3b5 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -262,25 +262,6 @@ Naming/HeredocDelimiterNaming: Naming/RescuedExceptionsVariableName: Enabled: false -# Offense count: 6 -# Cop supports --auto-correct. -Performance/InefficientHashSearch: - Exclude: - - 'app/controllers/concerns/sessionless_authentication.rb' - - 'app/models/note.rb' - - 'app/models/user_preference.rb' - - 'ee/app/models/ee/project.rb' - - 'lib/gitlab/import_export/members_mapper.rb' - - 'qa/spec/spec_helper.rb' - -# Offense count: 3 -# Cop supports --auto-correct. -Performance/ReverseEach: - Exclude: - - 'app/models/commit.rb' - - 'db/migrate/20190222051615_add_indexes_for_merge_request_diffs_query.rb' - - 'lib/gitlab/profiler.rb' - # Offense count: 7081 # Configuration parameters: Prefixes. # Prefixes: when, with, without diff --git a/CHANGELOG.md b/CHANGELOG.md index 34ace58bb14..d93cc182c62 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,29 @@ documentation](doc/development/changelog.md) for instructions on adding your own entry. +## 12.1.2 + +### Security (1 change) + +- Use source project as permissions reference for MergeRequestsController#pipelines. + +### Security (9 changes) + +- Restrict slash commands to users who can log in. +- Patch XSS issue in wiki links. +- Queries for Upload should be scoped by model. +- Filter merge request params on the new merge request page. +- Fix Server Side Request Forgery mitigation bypass. +- Show badges if pipelines are public otherwise default to project permissions. +- Do not allow localhost url redirection in GitHub Integration. +- Do not show moved issue id for users that cannot read issue. +- Drop feature to take ownership of trigger token. + + +## 12.1.1 + +- No changes. + ## 12.1.0 ### Security (11 changes, 2 of them are from the community) @@ -621,6 +644,21 @@ entry. - Moves snowplow to CE repo. +## 11.11.7 + +### Security (9 changes) + +- Restrict slash commands to users who can log in. +- Patch XSS issue in wiki links. +- Filter merge request params on the new merge request page. +- Fix Server Side Request Forgery mitigation bypass. +- Show badges if pipelines are public otherwise default to project permissions. +- Do not allow localhost url redirection in GitHub Integration. +- Do not show moved issue id for users that cannot read issue. +- Use source project as permissions reference for MergeRequestsController#pipelines. +- Drop feature to take ownership of trigger token. + + ## 11.11.4 (2019-06-26) ### Fixed (3 changes) @@ -16,7 +16,7 @@ gem 'sprockets', '~> 3.7.0' gem 'default_value_for', '~> 3.2.0' # Supported DBs -gem 'pg', '~> 1.1', group: :postgres +gem 'pg', '~> 1.1' gem 'rugged', '~> 0.28' gem 'grape-path-helpers', '~> 1.1' @@ -134,7 +134,7 @@ gem 'wikicloth', '0.8.1' gem 'asciidoctor', '~> 2.0.10' gem 'asciidoctor-include-ext', '~> 0.3.1', require: false gem 'asciidoctor-plantuml', '0.0.9' -gem 'rouge', '~> 3.5' +gem 'rouge', '~> 3.7' gem 'truncato', '~> 0.7.11' gem 'bootstrap_form', '~> 4.2.0' gem 'nokogiri', '~> 1.10.3' @@ -297,8 +297,6 @@ gem 'batch-loader', '~> 1.4.0' # Perf bar gem 'peek', '~> 1.0.1' gem 'peek-gc', '~> 0.0.2' -gem 'peek-pg', '~> 1.3.0', group: :postgres -gem 'peek-rblineprof', '~> 0.2.0' # Memory benchmarks gem 'derailed_benchmarks', require: false @@ -389,7 +387,6 @@ group :test do gem 'json-schema', '~> 2.8.0' gem 'webmock', '~> 3.5.1' gem 'rails-controller-testing' - gem 'sham_rack', '~> 1.3.6' gem 'concurrent-ruby', '~> 1.1' gem 'test-prof', '~> 0.2.5' gem 'rspec_junit_formatter' diff --git a/Gemfile.lock b/Gemfile.lock index 7e26c5bbc45..45f1464a5b5 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -643,14 +643,6 @@ GEM railties (>= 4.0.0) peek-gc (0.0.2) peek - peek-pg (1.3.0) - concurrent-ruby - concurrent-ruby-ext - peek - pg - peek-rblineprof (0.2.0) - peek - rblineprof pg (1.1.4) po_to_json (1.0.1) json (>= 1.6.0) @@ -785,7 +777,7 @@ GEM retriable (3.1.2) rinku (2.0.0) rotp (2.1.2) - rouge (3.5.1) + rouge (3.7.0) rqrcode (0.7.0) chunky_png rqrcode-rails3 (0.1.7) @@ -853,7 +845,7 @@ GEM rubyntlm (0.6.2) rubypants (0.2.0) rubyzip (1.2.2) - rugged (0.28.1) + rugged (0.28.2) safe_yaml (1.0.4) sanitize (4.6.6) crass (~> 1.0.2) @@ -889,8 +881,6 @@ GEM faraday (>= 0.7.6, < 1.0) settingslogic (2.0.9) sexp_processor (4.12.0) - sham_rack (1.3.6) - rack shoulda-matchers (4.0.1) activesupport (>= 4.2.0) sidekiq (5.2.7) @@ -1184,8 +1174,6 @@ DEPENDENCIES org-ruby (~> 0.9.12) peek (~> 1.0.1) peek-gc (~> 0.0.2) - peek-pg (~> 1.3.0) - peek-rblineprof (~> 0.2.0) pg (~> 1.1) premailer-rails (~> 1.9.7) prometheus-client-mmap (~> 0.9.8) @@ -1214,7 +1202,7 @@ DEPENDENCIES redis-rails (~> 5.0.2) request_store (~> 1.3) responders (~> 2.0) - rouge (~> 3.5) + rouge (~> 3.7) rqrcode-rails3 (~> 0.1.7) rspec-parameterized rspec-rails (~> 3.8.0) @@ -1238,7 +1226,6 @@ DEPENDENCIES selenium-webdriver (~> 3.141) sentry-raven (~> 2.9) settingslogic (~> 2.0.9) - sham_rack (~> 1.3.6) shoulda-matchers (~> 4.0.1) sidekiq (~> 5.2.7) sidekiq-cron (~> 1.0) diff --git a/README.md b/README.md index 51dc87ac653..73bfcc988cc 100644 --- a/README.md +++ b/README.md @@ -81,7 +81,7 @@ Instructions on how to start GitLab and how to run the tests can be found in the GitLab is a Ruby on Rails application that runs on the following software: - Ubuntu/Debian/CentOS/RHEL/OpenSUSE -- Ruby (MRI) 2.4 +- Ruby (MRI) 2.6.3 - Git 2.8.4+ - Redis 2.8+ - PostgreSQL (preferred) or MySQL diff --git a/app/assets/javascripts/boards/components/board_form.vue b/app/assets/javascripts/boards/components/board_form.vue index 6754abf4019..ebf48cee2ae 100644 --- a/app/assets/javascripts/boards/components/board_form.vue +++ b/app/assets/javascripts/boards/components/board_form.vue @@ -1,4 +1,5 @@ <script> +import { __ } from '~/locale'; import Flash from '~/flash'; import DeprecatedModal from '~/vue_shared/components/deprecated_modal.vue'; import { visitUrl } from '~/lib/utils/url_utility'; @@ -86,12 +87,12 @@ export default { }, buttonText() { if (this.isNewForm) { - return 'Create board'; + return __('Create board'); } if (this.isDeleteForm) { - return 'Delete'; + return __('Delete'); } - return 'Save changes'; + return __('Save changes'); }, buttonKind() { if (this.isNewForm) { @@ -104,15 +105,15 @@ export default { }, title() { if (this.isNewForm) { - return 'Create new board'; + return __('Create new board'); } if (this.isDeleteForm) { - return 'Delete board'; + return __('Delete board'); } if (this.readonly) { - return 'Board scope'; + return __('Board scope'); } - return 'Edit board'; + return __('Edit board'); }, readonly() { return !this.canAdminBoard; @@ -138,7 +139,7 @@ export default { visitUrl(boardsStore.rootPath); }) .catch(() => { - Flash('Failed to delete board. Please try again.'); + Flash(__('Failed to delete board. Please try again.')); this.isLoading = false; }); } else { @@ -149,7 +150,7 @@ export default { visitUrl(data.board_path); }) .catch(() => { - Flash('Unable to save your changes. Please try again.'); + Flash(__('Unable to save your changes. Please try again.')); this.isLoading = false; }); } @@ -182,17 +183,19 @@ export default { @submit="submit" > <template slot="body"> - <p v-if="isDeleteForm">Are you sure you want to delete this board?</p> + <p v-if="isDeleteForm">{{ __('Are you sure you want to delete this board?') }}</p> <form v-else class="js-board-config-modal" @submit.prevent> <div v-if="!readonly" class="append-bottom-20"> - <label class="form-section-title label-bold" for="board-new-name"> Board name </label> + <label class="form-section-title label-bold" for="board-new-name">{{ + __('Board name') + }}</label> <input id="board-new-name" ref="name" v-model="board.name" class="form-control" type="text" - placeholder="Enter board name" + :placeholder="__('Enter board name')" @keyup.enter="submit" /> </div> diff --git a/app/assets/javascripts/commits.js b/app/assets/javascripts/commits.js index 54e2589c707..7dd75d03ab9 100644 --- a/app/assets/javascripts/commits.js +++ b/app/assets/javascripts/commits.js @@ -1,5 +1,5 @@ import $ from 'jquery'; -import { pluralize } from './lib/utils/text_utility'; +import { n__ } from '~/locale'; import { localTimeAgo } from './lib/utils/datetime_utility'; import Pager from './pager'; import axios from './lib/utils/axios_utils'; @@ -90,9 +90,10 @@ export default class CommitsList { .first() .find('li.commit').length, ); + $commitsHeadersLast .find('span.commits-count') - .text(`${commitsCount} ${pluralize('commit', commitsCount)}`); + .text(n__('%d commit', '%d commits', commitsCount)); } localTimeAgo($processedData.find('.js-timeago')); diff --git a/app/assets/javascripts/commons/polyfills.js b/app/assets/javascripts/commons/polyfills.js index 7a6ad3dc771..daa941a63cd 100644 --- a/app/assets/javascripts/commons/polyfills.js +++ b/app/assets/javascripts/commons/polyfills.js @@ -12,6 +12,7 @@ import 'core-js/es/promise/finally'; import 'core-js/es/string/code-point-at'; import 'core-js/es/string/from-code-point'; import 'core-js/es/string/includes'; +import 'core-js/es/string/repeat'; import 'core-js/es/string/starts-with'; import 'core-js/es/string/ends-with'; import 'core-js/es/symbol'; diff --git a/app/assets/javascripts/cycle_analytics/cycle_analytics_service.js b/app/assets/javascripts/cycle_analytics/cycle_analytics_service.js index a0426301a0a..babbfe93082 100644 --- a/app/assets/javascripts/cycle_analytics/cycle_analytics_service.js +++ b/app/assets/javascripts/cycle_analytics/cycle_analytics_service.js @@ -8,22 +8,26 @@ export default class CycleAnalyticsService { } fetchCycleAnalyticsData(options = { startDate: 30 }) { + const { startDate, projectIds } = options; + return this.axios .get('', { params: { - 'cycle_analytics[start_date]': options.startDate, + 'cycle_analytics[start_date]': startDate, + 'cycle_analytics[project_ids]': projectIds, }, }) .then(x => x.data); } fetchStageData(options) { - const { stage, startDate } = options; + const { stage, startDate, projectIds } = options; return this.axios .get(`events/${stage.name}.json`, { params: { 'cycle_analytics[start_date]': startDate, + 'cycle_analytics[project_ids]': projectIds, }, }) .then(x => x.data); diff --git a/app/assets/javascripts/diffs/components/diff_discussion_reply.vue b/app/assets/javascripts/diffs/components/diff_discussion_reply.vue index 2aa5e9b3339..531ebaddacd 100644 --- a/app/assets/javascripts/diffs/components/diff_discussion_reply.vue +++ b/app/assets/javascripts/diffs/components/diff_discussion_reply.vue @@ -44,7 +44,6 @@ export default { class="d-none d-sm-block" /> <reply-placeholder - class="qa-discussion-reply" :button-text="__('Start a new discussion...')" @onClick="$emit('showNewDiscussionForm')" /> diff --git a/app/assets/javascripts/diffs/components/diff_file_header.vue b/app/assets/javascripts/diffs/components/diff_file_header.vue index 4b226e30699..32fbeaaa905 100644 --- a/app/assets/javascripts/diffs/components/diff_file_header.vue +++ b/app/assets/javascripts/diffs/components/diff_file_header.vue @@ -263,6 +263,7 @@ export default { :disabled="!diffHasDiscussions(diffFile)" :class="{ active: hasExpandedDiscussions }" class="js-btn-vue-toggle-comments btn" + data-qa-selector="toggle_comments_button" type="button" @click="handleToggleDiscussions" > diff --git a/app/assets/javascripts/diffs/components/diff_gutter_avatars.vue b/app/assets/javascripts/diffs/components/diff_gutter_avatars.vue index af5550aec3b..7ede7a4f430 100644 --- a/app/assets/javascripts/diffs/components/diff_gutter_avatars.vue +++ b/app/assets/javascripts/diffs/components/diff_gutter_avatars.vue @@ -1,6 +1,7 @@ <script> +import { n__ } from '~/locale'; import Icon from '~/vue_shared/components/icon.vue'; -import { pluralize, truncate } from '~/lib/utils/text_utility'; +import { truncate } from '~/lib/utils/text_utility'; import UserAvatarImage from '~/vue_shared/components/user_avatar/user_avatar_image.vue'; import { GlTooltipDirective } from '@gitlab/ui'; import { COUNT_OF_AVATARS_IN_GUTTER, LENGTH_OF_AVATAR_TOOLTIP } from '../constants'; @@ -42,7 +43,7 @@ export default { return ''; } - return pluralize(`${this.moreCount} more comment`, this.moreCount); + return n__('%d more comment', '%d more comments', this.moreCount); }, }, methods: { diff --git a/app/assets/javascripts/gl_form.js b/app/assets/javascripts/gl_form.js index a66555838ba..b98fe9f6ce2 100644 --- a/app/assets/javascripts/gl_form.js +++ b/app/assets/javascripts/gl_form.js @@ -3,9 +3,16 @@ import autosize from 'autosize'; import GfmAutoComplete, { defaultAutocompleteConfig } from 'ee_else_ce/gfm_auto_complete'; import dropzoneInput from './dropzone_input'; import { addMarkdownListeners, removeMarkdownListeners } from './lib/utils/text_markdown'; +import IndentHelper from './helpers/indent_helper'; +import { keystroke } from './lib/utils/common_utils'; +import * as keys from './lib/utils/keycodes'; +import UndoStack from './lib/utils/undo_stack'; export default class GLForm { constructor(form, enableGFM = {}) { + this.handleKeyShortcuts = this.handleKeyShortcuts.bind(this); + this.setState = this.setState.bind(this); + this.form = form; this.textarea = this.form.find('textarea.js-gfm-input'); this.enableGFM = Object.assign({}, defaultAutocompleteConfig, enableGFM); @@ -16,6 +23,10 @@ export default class GLForm { this.enableGFM[item] = Boolean(dataSources[item]); } }); + + this.undoStack = new UndoStack(); + this.indentHelper = new IndentHelper(this.textarea[0]); + // Before we start, we should clean up any previous data for this form this.destroy(); // Set up the form @@ -85,9 +96,84 @@ export default class GLForm { clearEventListeners() { this.textarea.off('focus'); this.textarea.off('blur'); + this.textarea.off('keydown'); removeMarkdownListeners(this.form); } + setState(state) { + const selection = [this.textarea[0].selectionStart, this.textarea[0].selectionEnd]; + this.textarea.val(state); + this.textarea[0].setSelectionRange(selection[0], selection[1]); + } + + /* + Handle keypresses for a custom undo/redo stack. + We need this because the toolbar buttons and indentation helpers mess with the browser's + native undo/redo capability. + */ + handleUndo(event) { + const content = this.textarea.val(); + const { selectionStart, selectionEnd } = this.textarea[0]; + const stack = this.undoStack; + + if (stack.isEmpty()) { + // ==== Save initial state in undo history ==== + stack.save(content); + } + + if (keystroke(event, keys.Z_KEY_CODE, 'l')) { + // ==== Undo ==== + event.preventDefault(); + stack.save(content); + if (stack.canUndo()) { + this.setState(stack.undo()); + } + } else if (keystroke(event, keys.Z_KEY_CODE, 'ls') || keystroke(event, keys.Y_KEY_CODE, 'l')) { + // ==== Redo ==== + event.preventDefault(); + if (stack.canRedo()) { + this.setState(stack.redo()); + } + } else if ( + keystroke(event, keys.SPACE_KEY_CODE) || + keystroke(event, keys.ENTER_KEY_CODE) || + selectionStart !== selectionEnd + ) { + // ==== Save after finishing a word or before deleting a large selection ==== + stack.save(content); + } else if (content === '') { + // ==== Save after deleting everything ==== + stack.save(''); + } else { + // ==== Save after 1 second of inactivity ==== + stack.scheduleSave(content); + } + } + + handleIndent(event) { + if (keystroke(event, keys.LEFT_BRACKET_KEY_CODE, 'l')) { + // ==== Unindent selected lines ==== + event.preventDefault(); + this.indentHelper.unindent(); + } else if (keystroke(event, keys.RIGHT_BRACKET_KEY_CODE, 'l')) { + // ==== Indent selected lines ==== + event.preventDefault(); + this.indentHelper.indent(); + } else if (keystroke(event, keys.ENTER_KEY_CODE)) { + // ==== Auto-indent new lines ==== + event.preventDefault(); + this.indentHelper.newline(); + } else if (keystroke(event, keys.BACKSPACE_KEY_CODE)) { + // ==== Auto-delete indents at the beginning of the line ==== + this.indentHelper.backspace(event); + } + } + + handleKeyShortcuts(event) { + this.handleIndent(event); + this.handleUndo(event); + } + addEventListeners() { this.textarea.on('focus', function focusTextArea() { $(this) @@ -99,5 +185,6 @@ export default class GLForm { .closest('.md-area') .removeClass('is-focused'); }); + this.textarea.on('keydown', e => this.handleKeyShortcuts(e.originalEvent)); } } diff --git a/app/assets/javascripts/helpers/indent_helper.js b/app/assets/javascripts/helpers/indent_helper.js new file mode 100644 index 00000000000..a8815fac04e --- /dev/null +++ b/app/assets/javascripts/helpers/indent_helper.js @@ -0,0 +1,182 @@ +const INDENT_SEQUENCE = ' '; + +function countLeftSpaces(text) { + const i = text.split('').findIndex(c => c !== ' '); + return i === -1 ? text.length : i; +} + +/** + * IndentHelper provides methods that allow manual and smart indentation in + * textareas. It supports line indent/unindent, selection indent/unindent, + * auto indentation on newlines, and smart deletion of indents with backspace. + */ +export default class IndentHelper { + /** + * Creates a new IndentHelper and binds it to the given `textarea`. You can provide a custom indent sequence in the second parameter, but the `newline` and `backspace` operations may work funny if the indent sequence isn't spaces only. + */ + constructor(textarea, indentSequence = INDENT_SEQUENCE) { + this.element = textarea; + this.seq = indentSequence; + } + + getSelection() { + return { start: this.element.selectionStart, end: this.element.selectionEnd }; + } + + isRangeSelection() { + return this.element.selectionStart !== this.element.selectionEnd; + } + + /** + * Re-implementation of textarea's setRangeText method, because IE/Edge don't support it. + * + * @see https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-textarea%2Finput-setrangetext + */ + setRangeText(replacement, start, end, selectMode) { + // Disable eslint to remain as faithful as possible to the above linked spec + /* eslint-disable no-param-reassign, no-case-declarations */ + const text = this.element.value; + + if (start > end) { + throw new RangeError('setRangeText: start index must be less than or equal to end index'); + } + + // Clamp to [0, len] + start = Math.max(0, Math.min(start, text.length)); + end = Math.max(0, Math.min(end, text.length)); + + let selection = { start: this.element.selectionStart, end: this.element.selectionEnd }; + + this.element.value = text.slice(0, start) + replacement + text.slice(end); + + const newLength = replacement.length; + const newEnd = start + newLength; + + switch (selectMode) { + case 'select': + selection = { start, newEnd }; + break; + case 'start': + selection = { start, end: start }; + break; + case 'end': + selection = { start: newEnd, end: newEnd }; + break; + case 'preserve': + default: + const oldLength = end - start; + const delta = newLength - oldLength; + if (selection.start > end) { + selection.start += delta; + } else if (selection.start > start) { + selection.start = start; + } + if (selection.end > end) { + selection.end += delta; + } else if (selection.end > start) { + selection.end = newEnd; + } + } + + this.element.setSelectionRange(selection.start, selection.end); + + /* eslint-enable no-param-reassign, no-case-declarations */ + } + + /** + * Returns an array of lines in the textarea, with information about their + * start/end offsets and whether they are included in the current selection. + */ + splitLines() { + const { start, end } = this.getSelection(); + + const lines = this.element.value.split('\n'); + let textStart = 0; + const lineObjects = []; + lines.forEach(line => { + const lineObj = { + text: line, + start: textStart, + end: textStart + line.length, + }; + lineObj.inSelection = lineObj.start <= end && lineObj.end >= start; + lineObjects.push(lineObj); + textStart += line.length + 1; + }); + return lineObjects; + } + + /** + * Indents selected lines by one level. + */ + indent() { + const { start } = this.getSelection(); + + const selectedLines = this.splitLines().filter(line => line.inSelection); + if (!this.isRangeSelection() && start === selectedLines[0].start) { + // Special case: if cursor is at the beginning of the line, move it one + // indent right. + const line = selectedLines[0]; + this.setRangeText(this.seq, line.start, line.start, 'end'); + } else { + selectedLines.reverse(); + selectedLines.forEach(line => { + this.setRangeText(INDENT_SEQUENCE, line.start, line.start, 'preserve'); + }); + } + } + + /** + * Unindents selected lines by one level. + */ + unindent() { + const lines = this.splitLines().filter(line => line.inSelection); + lines.reverse(); + lines + .filter(line => line.text.startsWith(this.seq)) + .forEach(line => { + this.setRangeText('', line.start, line.start + this.seq.length, 'preserve'); + }); + } + + /** + * Emulates a newline keypress, automatically indenting the new line. + */ + newline() { + const { start, end } = this.getSelection(); + + if (this.isRangeSelection()) { + // Manually kill the selection before calculating the indent + this.setRangeText('', start, end, 'start'); + } + + // Auto-indent the next line + const currentLine = this.splitLines().find(line => line.end >= start); + const spaces = countLeftSpaces(currentLine.text); + this.setRangeText(`\n${' '.repeat(spaces)}`, start, start, 'end'); + } + + /** + * If the cursor is positioned at the end of a line's leading indents, + * emulates a backspace keypress by deleting a single level of indents. + * @param event The DOM KeyboardEvent that triggers this action, or null. + */ + backspace(event) { + const { start } = this.getSelection(); + + // If the cursor is at the end of leading indents, delete an indent. + if (!this.isRangeSelection()) { + const currentLine = this.splitLines().find(line => line.end >= start); + const cursorPosition = start - currentLine.start; + if (countLeftSpaces(currentLine.text) === cursorPosition && cursorPosition > 0) { + if (event) event.preventDefault(); + + let spacesToDelete = cursorPosition % this.seq.length; + if (spacesToDelete === 0) { + spacesToDelete = this.seq.length; + } + this.setRangeText('', start - spacesToDelete, start, 'start'); + } + } + } +} diff --git a/app/assets/javascripts/ide/components/commit_sidebar/success_message.vue b/app/assets/javascripts/ide/components/commit_sidebar/success_message.vue index b1d5de8682d..137f8bb18c7 100644 --- a/app/assets/javascripts/ide/components/commit_sidebar/success_message.vue +++ b/app/assets/javascripts/ide/components/commit_sidebar/success_message.vue @@ -10,7 +10,9 @@ export default { <template> <div class="multi-file-commit-panel-success-message" aria-live="assertive"> - <div class="svg-content svg-80"><img :src="committedStateSvgPath" alt="" /></div> + <div class="svg-content svg-80"> + <img :src="committedStateSvgPath" :alt="s__('IDE|Successful commit')" /> + </div> <div class="append-right-default prepend-left-default"> <div class="text-content text-center"> <h4>{{ __('All changes are committed') }}</h4> diff --git a/app/assets/javascripts/jobs/components/empty_state.vue b/app/assets/javascripts/jobs/components/empty_state.vue index 04f910b6b80..275ed80146e 100644 --- a/app/assets/javascripts/jobs/components/empty_state.vue +++ b/app/assets/javascripts/jobs/components/empty_state.vue @@ -1,9 +1,11 @@ <script> import { GlLink } from '@gitlab/ui'; +import ManualVariablesForm from './manual_variables_form.vue'; export default { components: { GlLink, + ManualVariablesForm, }, props: { illustrationPath: { @@ -23,6 +25,21 @@ export default { required: false, default: null, }, + playable: { + type: Boolean, + required: true, + default: false, + }, + scheduled: { + type: Boolean, + required: false, + default: false, + }, + variablesSettingsUrl: { + type: String, + required: false, + default: null, + }, action: { type: Object, required: false, @@ -37,28 +54,40 @@ export default { }, }, }, + computed: { + shouldRenderManualVariables() { + return this.playable && !this.scheduled; + }, + }, }; </script> <template> <div class="row empty-state"> <div class="col-12"> - <div :class="illustrationSizeClass" class="svg-content"><img :src="illustrationPath" /></div> + <div :class="illustrationSizeClass" class="svg-content"> + <img :src="illustrationPath" /> + </div> </div> <div class="col-12"> <div class="text-content"> <h4 class="js-job-empty-state-title text-center">{{ title }}</h4> - <p v-if="content" class="js-job-empty-state-content text-center">{{ content }}</p> - + <p v-if="content" class="js-job-empty-state-content">{{ content }}</p> + </div> + <manual-variables-form + v-if="shouldRenderManualVariables" + :action="action" + :variables-settings-url="variablesSettingsUrl" + /> + <div class="text-content"> <div v-if="action" class="text-center"> <gl-link :href="action.path" :data-method="action.method" class="js-job-empty-state-action btn btn-primary" + >{{ action.button_title }}</gl-link > - {{ action.button_title }} - </gl-link> </div> </div> </div> diff --git a/app/assets/javascripts/jobs/components/job_app.vue b/app/assets/javascripts/jobs/components/job_app.vue index 79fb67d38cd..ef9fb6d08d1 100644 --- a/app/assets/javascripts/jobs/components/job_app.vue +++ b/app/assets/javascripts/jobs/components/job_app.vue @@ -45,6 +45,11 @@ export default { required: false, default: null, }, + variablesSettingsUrl: { + type: String, + required: false, + default: null, + }, runnerHelpUrl: { type: String, required: false, @@ -313,6 +318,9 @@ export default { :title="emptyStateTitle" :content="emptyStateIllustration.content" :action="emptyStateAction" + :playable="job.playable" + :scheduled="job.scheduled" + :variables-settings-url="variablesSettingsUrl" /> <!-- EO empty state --> diff --git a/app/assets/javascripts/jobs/components/manual_variables_form.vue b/app/assets/javascripts/jobs/components/manual_variables_form.vue new file mode 100644 index 00000000000..c32a3cac7be --- /dev/null +++ b/app/assets/javascripts/jobs/components/manual_variables_form.vue @@ -0,0 +1,179 @@ +<script> +import _ from 'underscore'; +import { mapActions } from 'vuex'; +import { GlButton } from '@gitlab/ui'; +import { s__, sprintf } from '~/locale'; +import Icon from '~/vue_shared/components/icon.vue'; + +export default { + name: 'ManualVariablesForm', + components: { + GlButton, + Icon, + }, + props: { + action: { + type: Object, + required: false, + default: null, + validator(value) { + return ( + value === null || + (_.has(value, 'path') && _.has(value, 'method') && _.has(value, 'button_title')) + ); + }, + }, + variablesSettingsUrl: { + type: String, + required: true, + default: '', + }, + }, + inputTypes: { + key: 'key', + value: 'value', + }, + i18n: { + keyPlaceholder: s__('CiVariables|Input variable key'), + valuePlaceholder: s__('CiVariables|Input variable value'), + }, + data() { + return { + variables: [], + key: '', + secretValue: '', + }; + }, + computed: { + helpText() { + return sprintf( + s__( + 'CiVariables|Specify variable values to be used in this run. The values specified in %{linkStart}CI/CD settings%{linkEnd} will be used as default', + ), + { + linkStart: `<a href="${this.variablesSettingsUrl}">`, + linkEnd: '</a>', + }, + false, + ); + }, + }, + watch: { + key(newVal) { + this.handleValueChange(newVal, this.$options.inputTypes.key); + }, + secretValue(newVal) { + this.handleValueChange(newVal, this.$options.inputTypes.value); + }, + }, + methods: { + ...mapActions(['triggerManualJob']), + handleValueChange(newValue, type) { + if (newValue !== '') { + this.createNewVariable(type); + this.resetForm(); + } + }, + createNewVariable(type) { + const newVariable = { + key: this.key, + secret_value: this.secretValue, + id: _.uniqueId(), + }; + + this.variables.push(newVariable); + + return this.$nextTick().then(() => { + this.$refs[`${this.$options.inputTypes[type]}-${newVariable.id}`][0].focus(); + }); + }, + resetForm() { + this.key = ''; + this.secretValue = ''; + }, + deleteVariable(id) { + this.variables.splice(this.variables.findIndex(el => el.id === id), 1); + }, + }, +}; +</script> +<template> + <div class="js-manual-vars-form col-12"> + <label>{{ s__('CiVariables|Variables') }}</label> + + <div class="ci-table"> + <div class="gl-responsive-table-row table-row-header pb-0 pt-0 border-0" role="row"> + <div class="table-section section-50" role="rowheader">{{ s__('CiVariables|Key') }}</div> + <div class="table-section section-50" role="rowheader">{{ s__('CiVariables|Value') }}</div> + </div> + + <div v-for="variable in variables" :key="variable.id" class="gl-responsive-table-row"> + <div class="table-section section-50"> + <div class="table-mobile-header" role="rowheader">{{ s__('Pipeline|Key') }}</div> + <div class="table-mobile-content append-right-10"> + <input + :ref="`${$options.inputTypes.key}-${variable.id}`" + v-model="variable.key" + :placeholder="$options.i18n.keyPlaceholder" + class="ci-variable-body-item form-control" + /> + </div> + </div> + + <div class="table-section section-50"> + <div class="table-mobile-header" role="rowheader">{{ s__('Pipeline|Value') }}</div> + <div class="table-mobile-content append-right-10"> + <input + :ref="`${$options.inputTypes.value}-${variable.id}`" + v-model="variable.secret_value" + :placeholder="$options.i18n.valuePlaceholder" + class="ci-variable-body-item form-control" + /> + </div> + </div> + + <div class="table-section section-10"> + <div class="table-mobile-header" role="rowheader"></div> + <div class="table-mobile-content justify-content-end"> + <gl-button class="btn-transparent btn-blank w-25" @click="deleteVariable(variable.id)"> + <icon name="clear" /> + </gl-button> + </div> + </div> + </div> + <div class="gl-responsive-table-row"> + <div class="table-section section-50"> + <div class="table-mobile-header" role="rowheader">{{ s__('Pipeline|Key') }}</div> + <div class="table-mobile-content append-right-10"> + <input + ref="inputKey" + v-model="key" + class="js-input-key form-control" + :placeholder="$options.i18n.keyPlaceholder" + /> + </div> + </div> + + <div class="table-section section-50"> + <div class="table-mobile-header" role="rowheader">{{ s__('Pipeline|Value') }}</div> + <div class="table-mobile-content append-right-10"> + <input + ref="inputSecretValue" + v-model="secretValue" + class="ci-variable-body-item form-control" + :placeholder="$options.i18n.valuePlaceholder" + /> + </div> + </div> + </div> + </div> + <div class="d-flex prepend-top-default justify-content-center"> + <p class="text-muted" v-html="helpText"></p> + </div> + <div class="d-flex justify-content-center"> + <gl-button variant="primary" @click="triggerManualJob(variables)"> + {{ action.button_title }} + </gl-button> + </div> + </div> +</template> diff --git a/app/assets/javascripts/jobs/index.js b/app/assets/javascripts/jobs/index.js index 25132449458..06514fcce1d 100644 --- a/app/assets/javascripts/jobs/index.js +++ b/app/assets/javascripts/jobs/index.js @@ -15,6 +15,7 @@ export default () => { deploymentHelpUrl: element.dataset.deploymentHelpUrl, runnerHelpUrl: element.dataset.runnerHelpUrl, runnerSettingsUrl: element.dataset.runnerSettingsUrl, + variablesSettingsUrl: element.dataset.variablesSettingsUrl, endpoint: element.dataset.endpoint, pagePath: element.dataset.buildOptionsPagePath, logState: element.dataset.buildOptionsLogState, diff --git a/app/assets/javascripts/jobs/store/actions.js b/app/assets/javascripts/jobs/store/actions.js index 12d67a43599..a2daef96a2d 100644 --- a/app/assets/javascripts/jobs/store/actions.js +++ b/app/assets/javascripts/jobs/store/actions.js @@ -209,5 +209,19 @@ export const receiveJobsForStageError = ({ commit }) => { flash(__('An error occurred while fetching the jobs.')); }; +export const triggerManualJob = ({ state }, variables) => { + const parsedVariables = variables.map(variable => { + const copyVar = Object.assign({}, variable); + delete copyVar.id; + return copyVar; + }); + + axios + .post(state.job.status.action.path, { + job_variables_attributes: parsedVariables, + }) + .catch(() => flash(__('An error occurred while triggering the job.'))); +}; + // prevent babel-plugin-rewire from generating an invalid default during karma tests export default () => {}; diff --git a/app/assets/javascripts/lib/utils/color_utils.js b/app/assets/javascripts/lib/utils/color_utils.js new file mode 100644 index 00000000000..07fb2915ca7 --- /dev/null +++ b/app/assets/javascripts/lib/utils/color_utils.js @@ -0,0 +1,25 @@ +/** + * Convert hex color to rgb array + * + * @param hex string + * @returns array|null + */ +export const hexToRgb = hex => { + // Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF") + const shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i; + const fullHex = hex.replace(shorthandRegex, (_m, r, g, b) => r + r + g + g + b + b); + + const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(fullHex); + return result + ? [parseInt(result[1], 16), parseInt(result[2], 16), parseInt(result[3], 16)] + : null; +}; + +export const textColorForBackground = backgroundColor => { + const [r, g, b] = hexToRgb(backgroundColor); + + if (r + g + b > 500) { + return '#333333'; + } + return '#FFFFFF'; +}; diff --git a/app/assets/javascripts/lib/utils/common_utils.js b/app/assets/javascripts/lib/utils/common_utils.js index 5e90893b684..1a94aee2398 100644 --- a/app/assets/javascripts/lib/utils/common_utils.js +++ b/app/assets/javascripts/lib/utils/common_utils.js @@ -203,6 +203,71 @@ export const isMetaKey = e => e.metaKey || e.ctrlKey || e.altKey || e.shiftKey; // 3) Middle-click or Mouse Wheel Click (e.which is 2) export const isMetaClick = e => e.metaKey || e.ctrlKey || e.which === 2; +export const getPlatformLeaderKey = () => { + // eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings + if (navigator && navigator.platform && navigator.platform.startsWith('Mac')) { + return 'meta'; + } + return 'ctrl'; +}; + +export const getPlatformLeaderKeyHTML = () => { + if (getPlatformLeaderKey() === 'meta') { + return '⌘'; + } + // eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings + return 'Ctrl'; +}; + +export const isPlatformLeaderKey = e => { + if (getPlatformLeaderKey() === 'meta') { + return Boolean(e.metaKey); + } + return Boolean(e.ctrlKey); +}; + +/** + * Tests if a KeyboardEvent corresponds exactly to a keystroke. + * + * This function avoids hacking around an old version of Mousetrap, which we ship at the moment. It should be removed after we upgrade to the newest Mousetrap. See: + * - https://gitlab.com/gitlab-org/gitlab-ce/issues/63182 + * - https://gitlab.com/gitlab-org/gitlab-ce/issues/64246 + * + * @example + * // Matches the enter key with exactly zero modifiers + * keystroke(event, 13) + * + * @example + * // Matches Control-Shift-Z + * keystroke(event, 90, 'cs') + * + * @param e The KeyboardEvent to test. + * @param keyCode The key code of the key to test. Why keycodes? IE/Edge don't support the more convenient `key` and `code` properties. + * @param modifiers A string of modifiers keys. Each modifier key is represented by one character. The set of pressed modifier keys must match the given string exactly. Available options are 'a' for Alt/Option, 'c' for Control, 'm' for Meta/Command, 's' for Shift, and 'l' for the leader key (Meta on MacOS and Control otherwise). + * @returns {boolean} True if the KeyboardEvent corresponds to the given keystroke. + */ +export const keystroke = (e, keyCode, modifiers = '') => { + if (!e || !keyCode) { + return false; + } + + const leader = getPlatformLeaderKey(); + const mods = modifiers.toLowerCase().replace('l', leader.charAt(0)); + + // Match depressed modifier keys + if ( + e.altKey !== mods.includes('a') || + e.ctrlKey !== mods.includes('c') || + e.metaKey !== mods.includes('m') || + e.shiftKey !== mods.includes('s') + ) { + return false; + } + + // Match the depressed key + return keyCode === (e.keyCode || e.which); +}; + export const contentTop = () => { const perfBar = $('#js-peek').outerHeight() || 0; const mrTabsHeight = $('.merge-request-tabs').outerHeight() || 0; diff --git a/app/assets/javascripts/lib/utils/datetime_utility.js b/app/assets/javascripts/lib/utils/datetime_utility.js index 062d21ed247..a4715789337 100644 --- a/app/assets/javascripts/lib/utils/datetime_utility.js +++ b/app/assets/javascripts/lib/utils/datetime_utility.js @@ -2,8 +2,7 @@ import $ from 'jquery'; import _ from 'underscore'; import timeago from 'timeago.js'; import dateFormat from 'dateformat'; -import { pluralize } from './text_utility'; -import { languageCode, s__, __ } from '../../locale'; +import { languageCode, s__, __, n__ } from '../../locale'; window.timeago = timeago; @@ -231,14 +230,10 @@ export const timeIntervalInWords = intervalInSeconds => { const secondsInteger = parseInt(intervalInSeconds, 10); const minutes = Math.floor(secondsInteger / 60); const seconds = secondsInteger - minutes * 60; - let text = ''; - - if (minutes >= 1) { - text = `${minutes} ${pluralize('minute', minutes)} ${seconds} ${pluralize('second', seconds)}`; - } else { - text = `${seconds} ${pluralize('second', seconds)}`; - } - return text; + const secondsText = n__('%d second', '%d seconds', seconds); + return minutes >= 1 + ? [n__('%d minute', '%d minutes', minutes), secondsText].join(' ') + : secondsText; }; export const dateInWords = (date, abbreviated = false, hideYear = false) => { diff --git a/app/assets/javascripts/lib/utils/keycodes.js b/app/assets/javascripts/lib/utils/keycodes.js index 5e0f9b612a2..e24fcf47d71 100644 --- a/app/assets/javascripts/lib/utils/keycodes.js +++ b/app/assets/javascripts/lib/utils/keycodes.js @@ -1,4 +1,10 @@ -export const UP_KEY_CODE = 38; -export const DOWN_KEY_CODE = 40; +export const BACKSPACE_KEY_CODE = 8; export const ENTER_KEY_CODE = 13; export const ESC_KEY_CODE = 27; +export const SPACE_KEY_CODE = 32; +export const UP_KEY_CODE = 38; +export const DOWN_KEY_CODE = 40; +export const Y_KEY_CODE = 89; +export const Z_KEY_CODE = 90; +export const LEFT_BRACKET_KEY_CODE = 219; +export const RIGHT_BRACKET_KEY_CODE = 221; diff --git a/app/assets/javascripts/lib/utils/text_utility.js b/app/assets/javascripts/lib/utils/text_utility.js index d38f59b5861..d13fbeb5fc7 100644 --- a/app/assets/javascripts/lib/utils/text_utility.js +++ b/app/assets/javascripts/lib/utils/text_utility.js @@ -29,14 +29,6 @@ export const humanize = string => string.charAt(0).toUpperCase() + string.replace(/_/g, ' ').slice(1); /** - * Adds an 's' to the end of the string when count is bigger than 0 - * @param {String} str - * @param {Number} count - * @returns {String} - */ -export const pluralize = (str, count) => str + (count > 1 || count === 0 ? 's' : ''); - -/** * Replaces underscores with dashes * @param {*} str * @returns {String} diff --git a/app/assets/javascripts/lib/utils/undo_stack.js b/app/assets/javascripts/lib/utils/undo_stack.js new file mode 100644 index 00000000000..6cfdc2a0a0f --- /dev/null +++ b/app/assets/javascripts/lib/utils/undo_stack.js @@ -0,0 +1,105 @@ +/** + * UndoStack provides a custom implementation of an undo/redo engine. It was originally written for GitLab's Markdown editor (`gl_form.js`), whose rich text editing capabilities broke native browser undo/redo behaviour. + * + * UndoStack supports predictable undos/redos, debounced saves, maximum history length, and duplicate detection. + * + * Usage: + * - `stack = new UndoStack();` + * - Saves a state to the stack with `stack.save(state)`. + * - Get the current state with `stack.current()`. + * - Revert to the previous state with `stack.undo()`. + * - Redo a previous undo with `stack.redo()`; + * - Queue a future save with `stack.scheduleSave(state, delay)`. Useful for text editors. + * - See the full undo history in `stack.history`. + */ +export default class UndoStack { + constructor(maxLength = 1000) { + this.clear(); + this.maxLength = maxLength; + + // If you're storing reference-types in the undo stack, you might want to + // reassign this property to some deep-equals function. + this.comparator = (a, b) => a === b; + } + + current() { + if (this.cursor === -1) { + return undefined; + } + return this.history[this.cursor]; + } + + isEmpty() { + return this.history.length === 0; + } + + clear() { + this.clearPending(); + this.history = []; + this.cursor = -1; + } + + save(state) { + this.clearPending(); + if (this.comparator(state, this.current())) { + // Don't save state if it's the same as the current state + return; + } + + this.history.length = this.cursor + 1; + this.history.push(state); + this.cursor += 1; + + if (this.history.length > this.maxLength) { + this.history.shift(); + this.cursor -= 1; + } + } + + scheduleSave(state, delay = 1000) { + this.clearPending(); + this.pendingState = state; + this.timeout = setTimeout(this.saveNow.bind(this), delay); + } + + saveNow() { + // Persists scheduled saves immediately + this.save(this.pendingState); + this.clearPending(); + } + + clearPending() { + // Cancels any scheduled saves + if (this.timeout) { + clearTimeout(this.timeout); + delete this.timeout; + delete this.pendingState; + } + } + + canUndo() { + return this.cursor > 0; + } + + undo() { + this.clearPending(); + if (!this.canUndo()) { + return undefined; + } + this.cursor -= 1; + return this.history[this.cursor]; + } + + canRedo() { + return this.cursor >= 0 && this.cursor < this.history.length - 1; + } + + redo() { + this.clearPending(); + if (!this.canRedo()) { + return undefined; + } + this.cursor += 1; + return this.history[this.cursor]; + } +} diff --git a/app/assets/javascripts/monitoring/components/charts/empty_chart.vue b/app/assets/javascripts/monitoring/components/charts/empty_chart.vue new file mode 100644 index 00000000000..73682adc4ee --- /dev/null +++ b/app/assets/javascripts/monitoring/components/charts/empty_chart.vue @@ -0,0 +1,41 @@ +<script> +import chartEmptyStateIllustration from '@gitlab/svgs/dist/illustrations/chart-empty-state.svg'; +import { chartHeight } from '../../constants'; + +export default { + props: { + graphTitle: { + type: String, + required: true, + }, + }, + data() { + return { + height: chartHeight, + }; + }, + computed: { + svgContainerStyle() { + return { + height: `${this.height}px`, + }; + }, + }, + created() { + this.chartEmptyStateIllustration = chartEmptyStateIllustration; + }, +}; +</script> +<template> + <div class="prometheus-graph col-12 col-lg-6 d-flex flex-column justify-content-center"> + <div class="prometheus-graph-header"> + <h5 ref="graphTitle" class="prometheus-graph-title">{{ graphTitle }}</h5> + </div> + <div + class="prepend-top-8 svg-w-100 d-flex align-items-center" + :style="svgContainerStyle" + v-html="chartEmptyStateIllustration" + ></div> + <h5 class="text-center prepend-top-8">{{ __('No data to display') }}</h5> + </div> +</template> diff --git a/app/assets/javascripts/monitoring/components/dashboard.vue b/app/assets/javascripts/monitoring/components/dashboard.vue index c7c55880040..45543ef2cc8 100644 --- a/app/assets/javascripts/monitoring/components/dashboard.vue +++ b/app/assets/javascripts/monitoring/components/dashboard.vue @@ -157,9 +157,6 @@ export default { 'multipleDashboardsEnabled', 'additionalPanelTypesEnabled', ]), - groupsWithData() { - return this.groups.filter(group => this.chartsWithData(group.metrics).length > 0); - }, selectedDashboardText() { return this.currentDashboard || (this.allDashboards[0] && this.allDashboards[0].display_name); }, @@ -256,6 +253,9 @@ export default { setTimeWindowParameter(key) { return `?time_window=${key}`; }, + groupHasData(group) { + return this.chartsWithData(group.metrics).length > 0; + }, }, addMetric: { title: s__('Metrics|Add metric'), @@ -369,17 +369,19 @@ export default { </div> <div v-if="!showEmptyState"> <graph-group - v-for="groupData in groupsWithData" + v-for="(groupData, index) in groups" :key="`${groupData.group}.${groupData.priority}`" :name="groupData.group" :show-panels="showPanels" + :collapse-group="groupHasData(groupData)" > <template v-if="additionalPanelTypesEnabled"> <panel-type - v-for="(graphData, graphIndex) in chartsWithData(groupData.metrics)" + v-for="(graphData, graphIndex) in groupData.metrics" :key="`panel-type-${graphIndex}`" :graph-data="graphData" :dashboard-width="elWidth" + :index="`${index}-${graphIndex}`" /> </template> <template v-else> @@ -398,6 +400,7 @@ export default { :alerts-endpoint="alertsEndpoint" :relevant-queries="graphData.queries" :alerts-to-manage="getGraphAlerts(graphData.queries)" + :modal-id="`alert-modal-${index}-${graphIndex}`" @setAlerts="setAlerts" /> </monitor-area-chart> diff --git a/app/assets/javascripts/monitoring/components/graph_group.vue b/app/assets/javascripts/monitoring/components/graph_group.vue index b20ad1802f3..0f5c5b3d60f 100644 --- a/app/assets/javascripts/monitoring/components/graph_group.vue +++ b/app/assets/javascripts/monitoring/components/graph_group.vue @@ -10,6 +10,10 @@ export default { required: false, default: true, }, + collapseGroup: { + type: Boolean, + required: true, + }, }, }; </script> @@ -19,7 +23,7 @@ export default { <div class="card-header"> <h4>{{ name }}</h4> </div> - <div class="card-body prometheus-graph-group"><slot></slot></div> + <div v-if="collapseGroup" class="card-body prometheus-graph-group"><slot></slot></div> </div> <div v-else class="prometheus-graph-group"><slot></slot></div> </template> diff --git a/app/assets/javascripts/monitoring/components/panel_type.vue b/app/assets/javascripts/monitoring/components/panel_type.vue index 45ee067de83..f1f02964a29 100644 --- a/app/assets/javascripts/monitoring/components/panel_type.vue +++ b/app/assets/javascripts/monitoring/components/panel_type.vue @@ -3,11 +3,13 @@ import { mapState } from 'vuex'; import _ from 'underscore'; import MonitorAreaChart from './charts/area.vue'; import MonitorSingleStatChart from './charts/single_stat.vue'; +import MonitorEmptyChart from './charts/empty_chart.vue'; export default { components: { MonitorAreaChart, MonitorSingleStatChart, + MonitorEmptyChart, }, props: { graphData: { @@ -18,12 +20,20 @@ export default { type: Number, required: true, }, + index: { + type: String, + required: false, + default: '', + }, }, computed: { ...mapState('monitoringDashboard', ['deploymentData', 'projectPath']), alertWidgetAvailable() { return IS_EE && this.prometheusAlertsAvailable && this.alertsEndpoint && this.graphData; }, + graphDataHasMetrics() { + return this.graphData.queries[0].result.length > 0; + }, }, methods: { getGraphAlerts(queries) { @@ -41,9 +51,12 @@ export default { }; </script> <template> - <monitor-single-stat-chart v-if="isPanelType('single-stat')" :graph-data="graphData" /> + <monitor-single-stat-chart + v-if="isPanelType('single-stat') && graphDataHasMetrics" + :graph-data="graphData" + /> <monitor-area-chart - v-else + v-else-if="graphDataHasMetrics" :graph-data="graphData" :deployment-data="deploymentData" :project-path="projectPath" @@ -56,7 +69,9 @@ export default { :alerts-endpoint="alertsEndpoint" :relevant-queries="graphData.queries" :alerts-to-manage="getGraphAlerts(graphData.queries)" + :modal-id="`alert-modal-${index}`" @setAlerts="setAlerts" /> </monitor-area-chart> + <monitor-empty-chart v-else :graph-title="graphData.title" /> </template> diff --git a/app/assets/javascripts/notes/components/discussion_actions.vue b/app/assets/javascripts/notes/components/discussion_actions.vue index 7aa8580d794..edab750b572 100644 --- a/app/assets/javascripts/notes/components/discussion_actions.vue +++ b/app/assets/javascripts/notes/components/discussion_actions.vue @@ -41,8 +41,8 @@ export default { <template> <div class="discussion-with-resolve-btn clearfix"> <reply-placeholder + data-qa-selector="discussion_reply_tab" :button-text="s__('MergeRequests|Reply...')" - class="qa-discussion-reply" @onClick="$emit('showReplyForm')" /> diff --git a/app/assets/javascripts/notes/components/note_form.vue b/app/assets/javascripts/notes/components/note_form.vue index 3823861c0b9..222badf70d1 100644 --- a/app/assets/javascripts/notes/components/note_form.vue +++ b/app/assets/javascripts/notes/components/note_form.vue @@ -293,12 +293,16 @@ export default { <input v-model="isUnresolving" type="checkbox" - class="qa-unresolve-review-discussion" + data-qa-selector="unresolve_review_discussion_checkbox" /> {{ __('Unresolve thread') }} </template> <template v-else> - <input v-model="isResolving" type="checkbox" class="qa-resolve-review-discussion" /> + <input + v-model="isResolving" + type="checkbox" + data-qa-selector="resolve_review_discussion_checkbox" + /> {{ __('Resolve thread') }} </template> </label> diff --git a/app/assets/javascripts/pages/admin/broadcast_messages/broadcast_message.js b/app/assets/javascripts/pages/admin/broadcast_messages/broadcast_message.js index 6e00e31b828..7a6a486f551 100644 --- a/app/assets/javascripts/pages/admin/broadcast_messages/broadcast_message.js +++ b/app/assets/javascripts/pages/admin/broadcast_messages/broadcast_message.js @@ -3,26 +3,31 @@ import _ from 'underscore'; import axios from '~/lib/utils/axios_utils'; import flash from '~/flash'; import { __ } from '~/locale'; +import { textColorForBackground } from '~/lib/utils/color_utils'; export default () => { - $('input#broadcast_message_color').on('input', function onMessageColorInput() { + const $broadcastMessageColor = $('input#broadcast_message_color'); + const $broadcastMessagePreview = $('div.broadcast-message-preview'); + $broadcastMessageColor.on('input', function onMessageColorInput() { const previewColor = $(this).val(); - $('div.broadcast-message-preview').css('background-color', previewColor); + $broadcastMessagePreview.css('background-color', previewColor); }); $('input#broadcast_message_font').on('input', function onMessageFontInput() { const previewColor = $(this).val(); - $('div.broadcast-message-preview').css('color', previewColor); + $broadcastMessagePreview.css('color', previewColor); }); - const previewPath = $('textarea#broadcast_message_message').data('previewPath'); + const $broadcastMessage = $('textarea#broadcast_message_message'); + const previewPath = $broadcastMessage.data('previewPath'); + const $jsBroadcastMessagePreview = $('.js-broadcast-message-preview'); - $('textarea#broadcast_message_message').on( + $broadcastMessage.on( 'input', _.debounce(function onMessageInput() { const message = $(this).val(); if (message === '') { - $('.js-broadcast-message-preview').text(__('Your message here')); + $jsBroadcastMessagePreview.text(__('Your message here')); } else { axios .post(previewPath, { @@ -31,10 +36,40 @@ export default () => { }, }) .then(({ data }) => { - $('.js-broadcast-message-preview').html(data.message); + $jsBroadcastMessagePreview.html(data.message); }) .catch(() => flash(__('An error occurred while rendering preview broadcast message'))); } }, 250), ); + + const updateColorPreview = () => { + const selectedBackgroundColor = $broadcastMessageColor.val(); + const contrastTextColor = textColorForBackground(selectedBackgroundColor); + + // save contrastTextColor to hidden input field + $('input.text-font-color').val(contrastTextColor); + + // Updates the preview color with the hex-color input + const selectedColorStyle = { + backgroundColor: selectedBackgroundColor, + color: contrastTextColor, + }; + + $('.label-color-preview').css(selectedColorStyle); + + return $broadcastMessagePreview.css(selectedColorStyle); + }; + + const setSuggestedColor = e => { + const color = $(e.currentTarget).data('color'); + $broadcastMessageColor + .val(color) + // Notify the form, that color has changed + .trigger('input'); + updateColorPreview(); + return e.preventDefault(); + }; + + $(document).on('click', '.suggest-colors a', setSuggestedColor); }; diff --git a/app/assets/javascripts/pages/projects/clusters/show/index.js b/app/assets/javascripts/pages/projects/clusters/show/index.js index 8001d2dd1da..f091c01fc98 100644 --- a/app/assets/javascripts/pages/projects/clusters/show/index.js +++ b/app/assets/javascripts/pages/projects/clusters/show/index.js @@ -1,5 +1,7 @@ import ClustersBundle from '~/clusters/clusters_bundle'; +import initGkeNamespace from '~/projects/gke_cluster_namespace'; document.addEventListener('DOMContentLoaded', () => { new ClustersBundle(); // eslint-disable-line no-new + initGkeNamespace(); }); diff --git a/app/assets/javascripts/pages/projects/index.js b/app/assets/javascripts/pages/projects/index.js index d4bd02c14e9..55c377ebec0 100644 --- a/app/assets/javascripts/pages/projects/index.js +++ b/app/assets/javascripts/pages/projects/index.js @@ -1,4 +1,5 @@ import initGkeDropdowns from '~/projects/gke_cluster_dropdowns'; +import initGkeNamespace from '~/projects/gke_cluster_namespace'; import PersistentUserCallout from '../../persistent_user_callout'; import Project from './project'; import ShortcutsNavigation from '../../behaviors/shortcuts/shortcuts_navigation'; @@ -16,6 +17,7 @@ document.addEventListener('DOMContentLoaded', () => { PersistentUserCallout.factory(callout); initGkeDropdowns(); + initGkeNamespace(); } new Project(); // eslint-disable-line no-new diff --git a/app/assets/javascripts/pdf/index.vue b/app/assets/javascripts/pdf/index.vue index 6d39abd4a1f..14640c172cd 100644 --- a/app/assets/javascripts/pdf/index.vue +++ b/app/assets/javascripts/pdf/index.vue @@ -14,7 +14,6 @@ export default { }, data() { return { - loading: false, pages: [], }; }, @@ -35,19 +34,24 @@ export default { load() { this.pages = []; return pdfjsLib - .getDocument(this.document) + .getDocument({ + url: this.document, + cMapUrl: '/assets/webpack/cmaps/', + cMapPacked: true, + }) .then(this.renderPages) - .then(() => this.$emit('pdflabload')) - .catch(error => this.$emit('pdflaberror', error)) - .then(() => { - this.loading = false; + .then(pages => { + this.pages = pages; + this.$emit('pdflabload'); + }) + .catch(error => { + this.$emit('pdflaberror', error); }); }, renderPages(pdf) { const pagePromises = []; - this.loading = true; for (let num = 1; num <= pdf.numPages; num += 1) { - pagePromises.push(pdf.getPage(num).then(p => this.pages.push(p))); + pagePromises.push(pdf.getPage(num)); } return Promise.all(pagePromises); }, @@ -59,8 +63,8 @@ export default { <div v-if="hasPDF" class="pdf-viewer"> <page v-for="(page, index) in pages" + v-if="page" :key="index" - :v-if="!loading" :page="page" :number="index + 1" /> diff --git a/app/assets/javascripts/pdf/page/index.vue b/app/assets/javascripts/pdf/page/index.vue index f16aaca6cd7..d933fdf220a 100644 --- a/app/assets/javascripts/pdf/page/index.vue +++ b/app/assets/javascripts/pdf/page/index.vue @@ -39,7 +39,9 @@ export default { .then(() => { this.rendering = false; }) - .catch(error => this.$emit('pdflaberror', error)); + .catch(error => { + this.$emit('pdflaberror', error); + }); }, }; </script> diff --git a/app/assets/javascripts/performance_bar/components/detailed_metric.vue b/app/assets/javascripts/performance_bar/components/detailed_metric.vue index d5f1cea8356..5bc1d5e0533 100644 --- a/app/assets/javascripts/performance_bar/components/detailed_metric.vue +++ b/app/assets/javascripts/performance_bar/components/detailed_metric.vue @@ -16,11 +16,14 @@ export default { type: String, required: true, }, - header: { + title: { type: String, - required: true, + required: false, + default() { + return this.metric; + }, }, - details: { + header: { type: String, required: true, }, @@ -34,7 +37,7 @@ export default { return this.currentRequest.details[this.metric]; }, detailsList() { - return this.metricDetails[this.details]; + return this.metricDetails.details; }, }, }; @@ -101,6 +104,6 @@ export default { <div slot="footer"></div> </gl-modal> - {{ metric }} + {{ title }} </div> </template> diff --git a/app/assets/javascripts/performance_bar/components/performance_bar_app.vue b/app/assets/javascripts/performance_bar/components/performance_bar_app.vue index 015c1527500..c0ea42ad1a2 100644 --- a/app/assets/javascripts/performance_bar/components/performance_bar_app.vue +++ b/app/assets/javascripts/performance_bar/components/performance_bar_app.vue @@ -1,5 +1,4 @@ <script> -import $ from 'jquery'; import { glEmojiTag } from '~/emoji'; import detailedMetric from './detailed_metric.vue'; @@ -28,23 +27,27 @@ export default { type: String, required: true, }, - profileUrl: { - type: String, - required: true, - }, }, detailedMetrics: [ - { metric: 'pg', header: s__('PerformanceBar|SQL queries'), details: 'queries', keys: ['sql'] }, + { + metric: 'active-record', + title: 'pg', + header: s__('PerformanceBar|SQL queries'), + keys: ['sql'], + }, { metric: 'gitaly', header: s__('PerformanceBar|Gitaly calls'), - details: 'details', keys: ['feature', 'request'], }, { + metric: 'rugged', + header: s__('PerformanceBar|Rugged calls'), + keys: ['feature', 'args'], + }, + { metric: 'redis', - header: 'Redis calls', - details: 'details', + header: s__('PerformanceBar|Redis calls'), keys: ['cmd'], }, ], @@ -66,9 +69,6 @@ export default { initialRequest() { return this.currentRequestId === this.requestId; }, - lineProfileModal() { - return $('#modal-peek-line-profile'); - }, hasHost() { return this.currentRequest && this.currentRequest.details && this.currentRequest.details.host; }, @@ -82,10 +82,6 @@ export default { }, mounted() { this.currentRequest = this.requestId; - - if (this.lineProfileModal.length) { - this.lineProfileModal.modal('toggle'); - } }, methods: { changeCurrentRequest(newRequestId) { @@ -112,21 +108,10 @@ export default { :key="metric.metric" :current-request="currentRequest" :metric="metric.metric" + :title="metric.title" :header="metric.header" - :details="metric.details" :keys="metric.keys" /> - <div v-if="initialRequest" id="peek-view-rblineprof" class="view"> - <button - v-if="lineProfileModal.length" - class="btn-link btn-blank" - data-toggle="modal" - data-target="#modal-peek-line-profile" - > - {{ s__('PerformanceBar|profile') }} - </button> - <a v-else :href="profileUrl">{{ s__('PerformanceBar|profile') }}</a> - </div> <div id="peek-view-gc" class="view"> <span v-if="currentRequest.details" class="bold"> <span title="Invoke Time">{{ currentRequest.details.gc.gc_time }}</span diff --git a/app/assets/javascripts/projects/gke_cluster_namespace/index.js b/app/assets/javascripts/projects/gke_cluster_namespace/index.js new file mode 100644 index 00000000000..288740203ad --- /dev/null +++ b/app/assets/javascripts/projects/gke_cluster_namespace/index.js @@ -0,0 +1,35 @@ +/** + * Disables & hides the namespace inputs when the gitlab-managed checkbox is checked/unchecked. + */ + +const setDisabled = (el, isDisabled) => { + if (isDisabled) { + el.classList.add('hidden'); + el.querySelector('input').setAttribute('disabled', true); + } else { + el.classList.remove('hidden'); + el.querySelector('input').removeAttribute('disabled'); + } +}; + +const setState = glManagedCheckbox => { + const glManaged = document.querySelector('.js-namespace-prefixed'); + const selfManaged = document.querySelector('.js-namespace'); + + if (glManagedCheckbox.checked) { + setDisabled(glManaged, false); + setDisabled(selfManaged, true); + } else { + setDisabled(glManaged, true); + setDisabled(selfManaged, false); + } +}; + +const initGkeNamespace = () => { + const glManagedCheckbox = document.querySelector('.js-gl-managed'); + + setState(glManagedCheckbox); // this is needed in order to set the initial state + glManagedCheckbox.addEventListener('change', () => setState(glManagedCheckbox)); +}; + +export default initGkeNamespace; diff --git a/app/assets/javascripts/visual_review_toolbar/components/comment.js b/app/assets/javascripts/visual_review_toolbar/components/comment.js index 04bfb5e9532..20effc1751d 100644 --- a/app/assets/javascripts/visual_review_toolbar/components/comment.js +++ b/app/assets/javascripts/visual_review_toolbar/components/comment.js @@ -1,148 +1,39 @@ -import { BLACK, COMMENT_BOX, MUTED, LOGOUT } from './constants'; -import { clearNote, postError } from './note'; -import { - buttonClearStyles, - selectCommentBox, - selectCommentButton, - selectNote, - selectNoteContainer, -} from './utils'; - -const comment = ` - <div> - <textarea id="${COMMENT_BOX}" name="${COMMENT_BOX}" rows="3" placeholder="Enter your feedback or idea" class="gitlab-input" aria-required="true"></textarea> - <p class="gitlab-metadata-note">Additional metadata will be included: browser, OS, current page, user agent, and viewport dimensions.</p> - </div> - <div class="gitlab-button-wrapper"> - <button class="gitlab-button gitlab-button-secondary" style="${buttonClearStyles}" type="button" id="${LOGOUT}"> Log out </button> - <button class="gitlab-button gitlab-button-success" style="${buttonClearStyles}" type="button" id="gitlab-comment-button"> Send feedback </button> - </div> -`; - -const resetCommentButton = () => { - const commentButton = selectCommentButton(); - - /* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */ - commentButton.innerText = 'Send feedback'; - commentButton.classList.replace('gitlab-button-secondary', 'gitlab-button-success'); - commentButton.style.opacity = 1; -}; - -const resetCommentBox = () => { - const commentBox = selectCommentBox(); - commentBox.style.pointerEvents = 'auto'; - commentBox.style.color = BLACK; -}; - -const resetCommentText = () => { - const commentBox = selectCommentBox(); - commentBox.value = ''; -}; - -const resetComment = () => { - resetCommentButton(); - resetCommentBox(); - resetCommentText(); -}; - -const confirmAndClear = feedbackInfo => { - const commentButton = selectCommentButton(); - const currentNote = selectNote(); - const noteContainer = selectNoteContainer(); - - /* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */ - commentButton.innerText = 'Feedback sent'; - noteContainer.style.visibility = 'visible'; - currentNote.insertAdjacentHTML('beforeend', feedbackInfo); - - setTimeout(resetComment, 1000); - setTimeout(clearNote, 6000); -}; - -const setInProgressState = () => { - const commentButton = selectCommentButton(); - const commentBox = selectCommentBox(); - - /* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */ - commentButton.innerText = 'Sending feedback'; - commentButton.classList.replace('gitlab-button-success', 'gitlab-button-secondary'); - commentButton.style.opacity = 0.5; - commentBox.style.color = MUTED; - commentBox.style.pointerEvents = 'none'; -}; - -const postComment = ({ - href, - platform, - browser, - userAgent, - innerWidth, - innerHeight, - projectId, - projectPath, - mergeRequestId, - mrUrl, - token, -}) => { - // Clear any old errors - clearNote(COMMENT_BOX); - - setInProgressState(); - - const commentText = selectCommentBox().value.trim(); - - if (!commentText) { - /* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */ - postError('Your comment appears to be empty.', COMMENT_BOX); - resetCommentBox(); - resetCommentButton(); - return; - } - - const detailText = ` - \n -<details> - <summary>Metadata</summary> - Posted from ${href} | ${platform} | ${browser} | ${innerWidth} x ${innerHeight}. - <br /><br /> - <em>User agent: ${userAgent}</em> -</details> +import { nextView } from '../store'; +import { localStorage, COMMENT_BOX, LOGOUT } from '../shared'; +import { clearNote } from './note'; +import { buttonClearStyles } from './utils'; +import { addForm } from './wrapper'; +import { changeSelectedMr, selectedMrNote } from './comment_mr_note'; +import postComment from './comment_post'; +import { saveComment, getSavedComment } from './comment_storage'; + +const comment = state => { + const savedComment = getSavedComment(); + + return ` + <div> + <textarea id="${COMMENT_BOX}" name="${COMMENT_BOX}" rows="3" placeholder="Enter your feedback or idea" class="gitlab-input" aria-required="true">${savedComment}</textarea> + ${selectedMrNote(state)} + <p class="gitlab-metadata-note">Additional metadata will be included: browser, OS, current page, user agent, and viewport dimensions.</p> + </div> + <div class="gitlab-button-wrapper"> + <button class="gitlab-button gitlab-button-success" style="${buttonClearStyles}" type="button" id="gitlab-comment-button"> Send feedback </button> + <button class="gitlab-button gitlab-button-secondary" style="${buttonClearStyles}" type="button" id="${LOGOUT}"> Log out </button> + </div> `; +}; - const url = ` - ${mrUrl}/api/v4/projects/${projectId}/merge_requests/${mergeRequestId}/discussions`; - - const body = `${commentText} ${detailText}`; - - fetch(url, { - method: 'POST', - headers: { - 'PRIVATE-TOKEN': token, - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ body }), - }) - .then(response => { - if (response.ok) { - return response.json(); - } - - throw new Error(`${response.status}: ${response.statusText}`); - }) - .then(data => { - const commentId = data.notes[0].id; - const feedbackLink = `${mrUrl}/${projectPath}/merge_requests/${mergeRequestId}#note_${commentId}`; - const feedbackInfo = `Feedback sent. View at <a class="gitlab-link" href="${feedbackLink}">${projectPath} #${mergeRequestId} (comment ${commentId})</a>`; - confirmAndClear(feedbackInfo); - }) - .catch(err => { - postError( - `Your comment could not be sent. Please try again. Error: ${err.message}`, - COMMENT_BOX, - ); - resetCommentBox(); - resetCommentButton(); - }); +// This function is here becaause it is called only from the comment view +// If we reach a design where we can logout from multiple views, promote this +// to it's own package +const logoutUser = state => { + localStorage.removeItem('token'); + localStorage.removeItem('mergeRequestId'); + state.token = ''; + state.mergeRequestId = ''; + + clearNote(); + addForm(nextView(state, COMMENT_BOX)); }; -export { comment, postComment }; +export { changeSelectedMr, comment, logoutUser, postComment, saveComment }; diff --git a/app/assets/javascripts/visual_review_toolbar/components/comment_mr_note.js b/app/assets/javascripts/visual_review_toolbar/components/comment_mr_note.js new file mode 100644 index 00000000000..f71ffbf4f20 --- /dev/null +++ b/app/assets/javascripts/visual_review_toolbar/components/comment_mr_note.js @@ -0,0 +1,31 @@ +import { nextView } from '../store'; +import { localStorage, CHANGE_MR_ID_BUTTON, COMMENT_BOX } from '../shared'; +import { clearNote } from './note'; +import { buttonClearStyles } from './utils'; +import { addForm } from './wrapper'; + +const selectedMrNote = state => { + const { mrUrl, projectPath, mergeRequestId } = state; + + const mrLink = `${mrUrl}/${projectPath}/merge_requests/${mergeRequestId}`; + + return ` + <p class="gitlab-metadata-note"> + This posts to merge request <a class="gitlab-link" href="${mrLink}">!${mergeRequestId}</a>. + <button style="${buttonClearStyles}" type="button" id="${CHANGE_MR_ID_BUTTON}" class="gitlab-link gitlab-link-button">Change</button> + </p> + `; +}; + +const clearMrId = state => { + localStorage.removeItem('mergeRequestId'); + state.mergeRequestId = ''; +}; + +const changeSelectedMr = state => { + clearMrId(state); + clearNote(); + addForm(nextView(state, COMMENT_BOX)); +}; + +export { changeSelectedMr, selectedMrNote }; diff --git a/app/assets/javascripts/visual_review_toolbar/components/comment_post.js b/app/assets/javascripts/visual_review_toolbar/components/comment_post.js new file mode 100644 index 00000000000..ee5f2b62425 --- /dev/null +++ b/app/assets/javascripts/visual_review_toolbar/components/comment_post.js @@ -0,0 +1,145 @@ +import { BLACK, COMMENT_BOX, MUTED } from '../shared'; +import { clearSavedComment } from './comment_storage'; +import { clearNote, postError } from './note'; +import { selectCommentBox, selectCommentButton, selectNote, selectNoteContainer } from './utils'; + +const resetCommentButton = () => { + const commentButton = selectCommentButton(); + + /* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */ + commentButton.innerText = 'Send feedback'; + commentButton.classList.replace('gitlab-button-secondary', 'gitlab-button-success'); + commentButton.style.opacity = 1; +}; + +const resetCommentBox = () => { + const commentBox = selectCommentBox(); + commentBox.style.pointerEvents = 'auto'; + commentBox.style.color = BLACK; +}; + +const resetCommentText = () => { + const commentBox = selectCommentBox(); + commentBox.value = ''; + clearSavedComment(); +}; + +const resetComment = () => { + resetCommentButton(); + resetCommentBox(); + resetCommentText(); +}; + +const confirmAndClear = feedbackInfo => { + const commentButton = selectCommentButton(); + const currentNote = selectNote(); + const noteContainer = selectNoteContainer(); + + /* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */ + commentButton.innerText = 'Feedback sent'; + noteContainer.style.visibility = 'visible'; + currentNote.insertAdjacentHTML('beforeend', feedbackInfo); + + setTimeout(resetComment, 1000); + setTimeout(clearNote, 6000); +}; + +const setInProgressState = () => { + const commentButton = selectCommentButton(); + const commentBox = selectCommentBox(); + + /* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */ + commentButton.innerText = 'Sending feedback'; + commentButton.classList.replace('gitlab-button-success', 'gitlab-button-secondary'); + commentButton.style.opacity = 0.5; + commentBox.style.color = MUTED; + commentBox.style.pointerEvents = 'none'; +}; + +const commentErrors = error => { + switch (error.status) { + case 401: + /* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */ + return 'Unauthorized. You may have entered an incorrect authentication token.'; + case 404: + /* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */ + return 'Not found. You may have entered an incorrect merge request ID.'; + default: + /* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */ + return `Your comment could not be sent. Please try again. Error: ${error.message}`; + } +}; + +const postComment = ({ + platform, + browser, + userAgent, + innerWidth, + innerHeight, + projectId, + projectPath, + mergeRequestId, + mrUrl, + token, +}) => { + // Clear any old errors + clearNote(COMMENT_BOX); + + setInProgressState(); + + const commentText = selectCommentBox().value.trim(); + // Get the href at the last moment to support SPAs + const { href } = window.location; + + if (!commentText) { + /* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */ + postError('Your comment appears to be empty.', COMMENT_BOX); + resetCommentBox(); + resetCommentButton(); + return; + } + + const detailText = ` + \n +<details> + <summary>Metadata</summary> + Posted from ${href} | ${platform} | ${browser} | ${innerWidth} x ${innerHeight}. + <br /><br /> + <em>User agent: ${userAgent}</em> +</details> + `; + + const url = ` + ${mrUrl}/api/v4/projects/${projectId}/merge_requests/${mergeRequestId}/discussions`; + + const body = `${commentText} ${detailText}`; + + fetch(url, { + method: 'POST', + headers: { + 'PRIVATE-TOKEN': token, + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ body }), + }) + .then(response => { + if (response.ok) { + return response.json(); + } + + throw response; + }) + .then(data => { + const commentId = data.notes[0].id; + const feedbackLink = `${mrUrl}/${projectPath}/merge_requests/${mergeRequestId}#note_${commentId}`; + const feedbackInfo = `Feedback sent. View at <a class="gitlab-link" href="${feedbackLink}">${projectPath} !${mergeRequestId} (comment ${commentId})</a>`; + confirmAndClear(feedbackInfo); + }) + .catch(err => { + postError(commentErrors(err), COMMENT_BOX); + resetCommentBox(); + resetCommentButton(); + }); +}; + +export default postComment; diff --git a/app/assets/javascripts/visual_review_toolbar/components/comment_storage.js b/app/assets/javascripts/visual_review_toolbar/components/comment_storage.js new file mode 100644 index 00000000000..32a9e7e2f05 --- /dev/null +++ b/app/assets/javascripts/visual_review_toolbar/components/comment_storage.js @@ -0,0 +1,20 @@ +import { selectCommentBox } from './utils'; +import { sessionStorage } from '../shared'; + +const getSavedComment = () => sessionStorage.getItem('comment') || ''; + +const saveComment = () => { + const currentComment = selectCommentBox(); + + // This may be added to any view via top-level beforeunload listener + // so let's skip if it does not apply + if (currentComment && currentComment.value) { + sessionStorage.setItem('comment', currentComment.value); + } +}; + +const clearSavedComment = () => { + sessionStorage.removeItem('comment'); +}; + +export { getSavedComment, saveComment, clearSavedComment }; diff --git a/app/assets/javascripts/visual_review_toolbar/components/form_elements.js b/app/assets/javascripts/visual_review_toolbar/components/form_elements.js new file mode 100644 index 00000000000..608488a6fea --- /dev/null +++ b/app/assets/javascripts/visual_review_toolbar/components/form_elements.js @@ -0,0 +1,17 @@ +import { REMEMBER_ITEM } from '../shared'; +import { buttonClearStyles } from './utils'; + +/* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */ +const rememberBox = (rememberText = 'Remember me') => ` + <div class="gitlab-checkbox-wrapper"> + <input type="checkbox" id="${REMEMBER_ITEM}" name="${REMEMBER_ITEM}" value="remember"> + <label for="${REMEMBER_ITEM}" class="gitlab-checkbox-label">${rememberText}</label> + </div> +`; + +const submitButton = buttonId => ` + <div class="gitlab-button-wrapper"> + <button class="gitlab-button-wide gitlab-button gitlab-button-success" style="${buttonClearStyles}" type="button" id="${buttonId}"> Submit </button> + </div> +`; +export { rememberBox, submitButton }; diff --git a/app/assets/javascripts/visual_review_toolbar/components/index.js b/app/assets/javascripts/visual_review_toolbar/components/index.js index 50b52d7d3a2..e88b3637ad8 100644 --- a/app/assets/javascripts/visual_review_toolbar/components/index.js +++ b/app/assets/javascripts/visual_review_toolbar/components/index.js @@ -1,33 +1,23 @@ -import { comment, postComment } from './comment'; -import { - COLLAPSE_BUTTON, - COMMENT_BUTTON, - FORM_CONTAINER, - LOGIN, - LOGOUT, - REVIEW_CONTAINER, -} from './constants'; +import { changeSelectedMr, comment, logoutUser, postComment, saveComment } from './comment'; import { authorizeUser, login } from './login'; +import { addMr, mrForm } from './mr_id'; import { note } from './note'; -import { selectContainer } from './utils'; -import { buttonAndForm, logoutUser, toggleForm } from './wrapper'; -import { collapseButton } from './wrapper_icons'; +import { selectContainer, selectForm } from './utils'; +import { buttonAndForm, toggleForm } from './wrapper'; export { + addMr, authorizeUser, buttonAndForm, - collapseButton, + changeSelectedMr, comment, login, logoutUser, + mrForm, note, postComment, + saveComment, selectContainer, + selectForm, toggleForm, - COLLAPSE_BUTTON, - COMMENT_BUTTON, - FORM_CONTAINER, - LOGIN, - LOGOUT, - REVIEW_CONTAINER, }; diff --git a/app/assets/javascripts/visual_review_toolbar/components/login.js b/app/assets/javascripts/visual_review_toolbar/components/login.js index 0a71299f041..4a6976ef2fd 100644 --- a/app/assets/javascripts/visual_review_toolbar/components/login.js +++ b/app/assets/javascripts/visual_review_toolbar/components/login.js @@ -1,35 +1,31 @@ -import { LOGIN, REMEMBER_TOKEN, TOKEN_BOX } from './constants'; +import { nextView } from '../store'; +import { localStorage, LOGIN, TOKEN_BOX } from '../shared'; import { clearNote, postError } from './note'; -import { buttonClearStyles, selectRemember, selectToken } from './utils'; -import { addCommentForm } from './wrapper'; +import { rememberBox, submitButton } from './form_elements'; +import { selectRemember, selectToken } from './utils'; +import { addForm } from './wrapper'; + +const labelText = ` + Enter your <a class="gitlab-link" href="https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html">personal access token</a> +`; const login = ` - <div> - <label for="${TOKEN_BOX}" class="gitlab-label">Enter your <a class="gitlab-link" href="https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html">personal access token</a></label> - <input class="gitlab-input" type="password" id="${TOKEN_BOX}" name="${TOKEN_BOX}" aria-required="true" autocomplete="current-password"> - </div> - <div class="gitlab-checkbox-wrapper"> - <input type="checkbox" id="${REMEMBER_TOKEN}" name="${REMEMBER_TOKEN}" value="remember"> - <label for="${REMEMBER_TOKEN}" class="gitlab-checkbox-label">Remember me</label> - </div> - <div class="gitlab-button-wrapper"> - <button class="gitlab-button-wide gitlab-button gitlab-button-success" style="${buttonClearStyles}" type="button" id="${LOGIN}"> Submit </button> - </div> + <div> + <label for="${TOKEN_BOX}" class="gitlab-label">${labelText}</label> + <input class="gitlab-input" type="password" id="${TOKEN_BOX}" name="${TOKEN_BOX}" autocomplete="current-password" aria-required="true"> + </div> + ${rememberBox()} + ${submitButton(LOGIN)} `; const storeToken = (token, state) => { - const { localStorage } = window; const rememberMe = selectRemember().checked; - // All the browsers we support have localStorage, so let's silently fail - // and go on with the rest of the functionality. - try { - if (rememberMe) { - localStorage.setItem('token', token); - } - } finally { - state.token = token; + if (rememberMe) { + localStorage.setItem('token', token); } + + state.token = token; }; const authorizeUser = state => { @@ -45,7 +41,7 @@ const authorizeUser = state => { } storeToken(token, state); - addCommentForm(); + addForm(nextView(state, LOGIN)); }; -export { authorizeUser, login }; +export { authorizeUser, login, storeToken }; diff --git a/app/assets/javascripts/visual_review_toolbar/components/mr_id.js b/app/assets/javascripts/visual_review_toolbar/components/mr_id.js new file mode 100644 index 00000000000..f51e9631dd2 --- /dev/null +++ b/app/assets/javascripts/visual_review_toolbar/components/mr_id.js @@ -0,0 +1,63 @@ +import { nextView } from '../store'; +import { MR_ID, MR_ID_BUTTON, localStorage } from '../shared'; +import { clearNote, postError } from './note'; +import { rememberBox, submitButton } from './form_elements'; +import { selectForm, selectMrBox, selectRemember } from './utils'; +import { addForm } from './wrapper'; + +/* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */ +const mrLabel = `Enter your merge request ID`; +/* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */ +const mrRememberText = `Remember this number`; + +const mrForm = ` + <div> + <label for="${MR_ID}" class="gitlab-label">${mrLabel}</label> + <input class="gitlab-input" type="text" pattern="[1-9][0-9]*" id="${MR_ID}" name="${MR_ID}" placeholder="e.g., 321" aria-required="true"> + </div> + ${rememberBox(mrRememberText)} + ${submitButton(MR_ID_BUTTON)} +`; + +const storeMR = (id, state) => { + const rememberMe = selectRemember().checked; + + if (rememberMe) { + localStorage.setItem('mergeRequestId', id); + } + + state.mergeRequestId = id; +}; + +const getFormError = (mrNumber, form) => { + if (!mrNumber) { + /* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */ + return 'Please enter your merge request ID number.'; + } + + if (!form.checkValidity()) { + /* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */ + return 'Please remove any non-number values from the field.'; + } + + return null; +}; + +const addMr = state => { + // Clear any old errors + clearNote(MR_ID); + + const mrNumber = selectMrBox().value; + const form = selectForm(); + const formError = getFormError(mrNumber, form); + + if (formError) { + postError(formError, MR_ID); + return; + } + + storeMR(mrNumber, state); + addForm(nextView(state, MR_ID)); +}; + +export { addMr, mrForm, storeMR }; diff --git a/app/assets/javascripts/visual_review_toolbar/components/note.js b/app/assets/javascripts/visual_review_toolbar/components/note.js index 0150f640aae..9cddcb710f2 100644 --- a/app/assets/javascripts/visual_review_toolbar/components/note.js +++ b/app/assets/javascripts/visual_review_toolbar/components/note.js @@ -1,4 +1,4 @@ -import { NOTE, NOTE_CONTAINER, RED } from './constants'; +import { NOTE, NOTE_CONTAINER, RED } from '../shared'; import { selectById, selectNote, selectNoteContainer } from './utils'; const note = ` diff --git a/app/assets/javascripts/visual_review_toolbar/components/utils.js b/app/assets/javascripts/visual_review_toolbar/components/utils.js index 00f4460925d..4ec9bd4a32a 100644 --- a/app/assets/javascripts/visual_review_toolbar/components/utils.js +++ b/app/assets/javascripts/visual_review_toolbar/components/utils.js @@ -6,12 +6,13 @@ import { COMMENT_BUTTON, FORM, FORM_CONTAINER, + MR_ID, NOTE, NOTE_CONTAINER, - REMEMBER_TOKEN, + REMEMBER_ITEM, REVIEW_CONTAINER, TOKEN_BOX, -} from './constants'; +} from '../shared'; // this style must be applied inline in a handful of components /* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */ @@ -27,9 +28,10 @@ const selectCommentButton = () => document.getElementById(COMMENT_BUTTON); const selectContainer = () => document.getElementById(REVIEW_CONTAINER); const selectForm = () => document.getElementById(FORM); const selectFormContainer = () => document.getElementById(FORM_CONTAINER); +const selectMrBox = () => document.getElementById(MR_ID); const selectNote = () => document.getElementById(NOTE); const selectNoteContainer = () => document.getElementById(NOTE_CONTAINER); -const selectRemember = () => document.getElementById(REMEMBER_TOKEN); +const selectRemember = () => document.getElementById(REMEMBER_ITEM); const selectToken = () => document.getElementById(TOKEN_BOX); export { @@ -41,6 +43,7 @@ export { selectCommentButton, selectForm, selectFormContainer, + selectMrBox, selectNote, selectNoteContainer, selectRemember, diff --git a/app/assets/javascripts/visual_review_toolbar/components/wrapper.js b/app/assets/javascripts/visual_review_toolbar/components/wrapper.js index f2eaf1d7916..fdf8ad7c41f 100644 --- a/app/assets/javascripts/visual_review_toolbar/components/wrapper.js +++ b/app/assets/javascripts/visual_review_toolbar/components/wrapper.js @@ -1,55 +1,32 @@ -import { comment } from './comment'; -import { CLEAR, FORM, FORM_CONTAINER, WHITE } from './constants'; -import { login } from './login'; -import { clearNote } from './note'; +import { CLEAR, FORM, FORM_CONTAINER, WHITE } from '../shared'; import { selectCollapseButton, selectForm, selectFormContainer, selectNoteContainer, } from './utils'; -import { commentIcon, compressIcon } from './wrapper_icons'; +import { collapseButton, commentIcon, compressIcon } from './wrapper_icons'; const form = content => ` - <form id="${FORM}"> + <form id="${FORM}" novalidate> ${content} </form> `; -const buttonAndForm = ({ content, toggleButton }) => ` +const buttonAndForm = content => ` <div id="${FORM_CONTAINER}" class="gitlab-form-open"> - ${toggleButton} + ${collapseButton} ${form(content)} </div> `; -const addCommentForm = () => { +const addForm = nextForm => { const formWrapper = selectForm(); - formWrapper.innerHTML = comment; + formWrapper.innerHTML = nextForm; }; -const addLoginForm = () => { - const formWrapper = selectForm(); - formWrapper.innerHTML = login; -}; - -function logoutUser() { - const { localStorage } = window; - - // All the browsers we support have localStorage, so let's silently fail - // and go on with the rest of the functionality. - try { - localStorage.removeItem('token'); - } catch (err) { - return; - } - - clearNote(); - addLoginForm(); -} - function toggleForm() { - const collapseButton = selectCollapseButton(); + const toggleButton = selectCollapseButton(); const currentForm = selectForm(); const formContainer = selectFormContainer(); const noteContainer = selectNoteContainer(); @@ -84,19 +61,19 @@ function toggleForm() { }, }; - const nextState = collapseButton.classList.contains('gitlab-collapse-open') ? CLOSED : OPEN; + const nextState = toggleButton.classList.contains('gitlab-collapse-open') ? CLOSED : OPEN; const currentVals = stateVals[nextState]; formContainer.classList.replace(...currentVals.containerClasses); formContainer.style.backgroundColor = currentVals.backgroundColor; formContainer.classList.toggle('gitlab-form-open'); currentForm.style.display = currentVals.display; - collapseButton.classList.replace(...currentVals.buttonClasses); - collapseButton.innerHTML = currentVals.icon; + toggleButton.classList.replace(...currentVals.buttonClasses); + toggleButton.innerHTML = currentVals.icon; if (noteContainer && noteContainer.innerText.length > 0) { noteContainer.style.display = currentVals.display; } } -export { addCommentForm, addLoginForm, buttonAndForm, logoutUser, toggleForm }; +export { addForm, buttonAndForm, toggleForm }; diff --git a/app/assets/javascripts/visual_review_toolbar/index.js b/app/assets/javascripts/visual_review_toolbar/index.js index f94eb88835a..67b3fadd772 100644 --- a/app/assets/javascripts/visual_review_toolbar/index.js +++ b/app/assets/javascripts/visual_review_toolbar/index.js @@ -1,7 +1,8 @@ import './styles/toolbar.css'; -import { buttonAndForm, note, selectContainer, REVIEW_CONTAINER } from './components'; -import { debounce, eventLookup, getInitialView, initializeState, updateWindowSize } from './store'; +import { buttonAndForm, note, selectForm, selectContainer } from './components'; +import { REVIEW_CONTAINER } from './shared'; +import { eventLookup, getInitialView, initializeGlobalListeners, initializeState } from './store'; /* @@ -20,7 +21,7 @@ import { debounce, eventLookup, getInitialView, initializeState, updateWindowSiz window.addEventListener('load', () => { initializeState(window, document); - const mainContent = buttonAndForm(getInitialView(window)); + const mainContent = buttonAndForm(getInitialView()); const container = document.createElement('div'); container.setAttribute('id', REVIEW_CONTAINER); container.insertAdjacentHTML('beforeend', note); @@ -29,8 +30,22 @@ window.addEventListener('load', () => { document.body.insertBefore(container, document.body.firstChild); selectContainer().addEventListener('click', event => { - eventLookup(event)(); + eventLookup(event.target.id)(); }); - window.addEventListener('resize', debounce(updateWindowSize.bind(null, window), 200)); + selectForm().addEventListener('submit', event => { + // this is important to prevent the form from adding data + // as URL params and inadvertently revealing secrets + event.preventDefault(); + + const id = + event.target.querySelector('.gitlab-button-wrapper') && + event.target.querySelector('.gitlab-button-wrapper').getElementsByTagName('button')[0] && + event.target.querySelector('.gitlab-button-wrapper').getElementsByTagName('button')[0].id; + + // even if this is called with false, it's ok; it will get the default no-op + eventLookup(id)(); + }); + + initializeGlobalListeners(); }); diff --git a/app/assets/javascripts/visual_review_toolbar/components/constants.js b/app/assets/javascripts/visual_review_toolbar/shared/constants.js index 07fcb179d15..a56ea378b14 100644 --- a/app/assets/javascripts/visual_review_toolbar/components/constants.js +++ b/app/assets/javascripts/visual_review_toolbar/shared/constants.js @@ -1,14 +1,17 @@ // component selectors +const CHANGE_MR_ID_BUTTON = 'gitlab-change-mr'; const COLLAPSE_BUTTON = 'gitlab-collapse'; const COMMENT_BOX = 'gitlab-comment'; const COMMENT_BUTTON = 'gitlab-comment-button'; const FORM = 'gitlab-form'; const FORM_CONTAINER = 'gitlab-form-wrapper'; -const LOGIN = 'gitlab-login'; +const LOGIN = 'gitlab-login-button'; const LOGOUT = 'gitlab-logout-button'; +const MR_ID = 'gitlab-submit-mr'; +const MR_ID_BUTTON = 'gitlab-submit-mr-button'; const NOTE = 'gitlab-validation-note'; const NOTE_CONTAINER = 'gitlab-note-wrapper'; -const REMEMBER_TOKEN = 'gitlab-remember_token'; +const REMEMBER_ITEM = 'gitlab-remember-item'; const REVIEW_CONTAINER = 'gitlab-review-container'; const TOKEN_BOX = 'gitlab-token'; @@ -21,6 +24,7 @@ const RED = 'rgba(219, 59, 33, 1)'; const WHITE = 'rgba(250, 250, 250, 1)'; export { + CHANGE_MR_ID_BUTTON, COLLAPSE_BUTTON, COMMENT_BOX, COMMENT_BUTTON, @@ -28,9 +32,11 @@ export { FORM_CONTAINER, LOGIN, LOGOUT, + MR_ID, + MR_ID_BUTTON, NOTE, NOTE_CONTAINER, - REMEMBER_TOKEN, + REMEMBER_ITEM, REVIEW_CONTAINER, TOKEN_BOX, BLACK, diff --git a/app/assets/javascripts/visual_review_toolbar/shared/index.js b/app/assets/javascripts/visual_review_toolbar/shared/index.js new file mode 100644 index 00000000000..751eae74dde --- /dev/null +++ b/app/assets/javascripts/visual_review_toolbar/shared/index.js @@ -0,0 +1,49 @@ +import { + CHANGE_MR_ID_BUTTON, + COLLAPSE_BUTTON, + COMMENT_BOX, + COMMENT_BUTTON, + FORM, + FORM_CONTAINER, + LOGIN, + LOGOUT, + MR_ID, + MR_ID_BUTTON, + NOTE, + NOTE_CONTAINER, + REMEMBER_ITEM, + REVIEW_CONTAINER, + TOKEN_BOX, + BLACK, + CLEAR, + MUTED, + RED, + WHITE, +} from './constants'; + +import { localStorage, sessionStorage } from './storage_utils'; + +export { + localStorage, + sessionStorage, + CHANGE_MR_ID_BUTTON, + COLLAPSE_BUTTON, + COMMENT_BOX, + COMMENT_BUTTON, + FORM, + FORM_CONTAINER, + LOGIN, + LOGOUT, + MR_ID, + MR_ID_BUTTON, + NOTE, + NOTE_CONTAINER, + REMEMBER_ITEM, + REVIEW_CONTAINER, + TOKEN_BOX, + BLACK, + CLEAR, + MUTED, + RED, + WHITE, +}; diff --git a/app/assets/javascripts/visual_review_toolbar/shared/storage_utils.js b/app/assets/javascripts/visual_review_toolbar/shared/storage_utils.js new file mode 100644 index 00000000000..00456d3536e --- /dev/null +++ b/app/assets/javascripts/visual_review_toolbar/shared/storage_utils.js @@ -0,0 +1,42 @@ +import { setUsingGracefulStorageFlag } from '../store/state'; + +const TEST_KEY = 'gitlab-storage-test'; + +const createStorageStub = () => { + const items = {}; + + return { + getItem(key) { + return items[key]; + }, + setItem(key, value) { + items[key] = value; + }, + removeItem(key) { + delete items[key]; + }, + }; +}; + +const hasStorageSupport = storage => { + // Support test taken from https://stackoverflow.com/a/11214467/1708147 + try { + storage.setItem(TEST_KEY, TEST_KEY); + storage.removeItem(TEST_KEY); + setUsingGracefulStorageFlag(true); + + return true; + } catch (err) { + setUsingGracefulStorageFlag(false); + return false; + } +}; + +const useGracefulStorage = storage => + // If a browser does not support local storage, let's return a graceful implementation. + hasStorageSupport(storage) ? storage : createStorageStub(); + +const localStorage = useGracefulStorage(window.localStorage); +const sessionStorage = useGracefulStorage(window.sessionStorage); + +export { localStorage, sessionStorage }; diff --git a/app/assets/javascripts/visual_review_toolbar/store/events.js b/app/assets/javascripts/visual_review_toolbar/store/events.js index 93996be8473..c9095c77ef1 100644 --- a/app/assets/javascripts/visual_review_toolbar/store/events.js +++ b/app/assets/javascripts/visual_review_toolbar/store/events.js @@ -1,20 +1,37 @@ import { + addMr, authorizeUser, + changeSelectedMr, logoutUser, postComment, + saveComment, toggleForm, +} from '../components'; + +import { + CHANGE_MR_ID_BUTTON, COLLAPSE_BUTTON, COMMENT_BUTTON, LOGIN, LOGOUT, -} from '../components'; + MR_ID_BUTTON, +} from '../shared'; import { state } from './state'; +import debounce from './utils'; const noop = () => {}; -const eventLookup = ({ target: { id } }) => { +// State needs to be bound here to be acted on +// because these are called by click events and +// as such are called with only the `event` object +const eventLookup = id => { switch (id) { + case CHANGE_MR_ID_BUTTON: + return () => { + saveComment(); + changeSelectedMr(state); + }; case COLLAPSE_BUTTON: return toggleForm; case COMMENT_BUTTON: @@ -22,7 +39,12 @@ const eventLookup = ({ target: { id } }) => { case LOGIN: return authorizeUser.bind(null, state); case LOGOUT: - return logoutUser; + return () => { + saveComment(); + logoutUser(state); + }; + case MR_ID_BUTTON: + return addMr.bind(null, state); default: return noop; } @@ -33,4 +55,19 @@ const updateWindowSize = wind => { state.innerHeight = wind.innerHeight; }; -export { eventLookup, updateWindowSize }; +const initializeGlobalListeners = () => { + window.addEventListener('resize', debounce(updateWindowSize.bind(null, window), 200)); + window.addEventListener('beforeunload', event => { + if (state.usingGracefulStorage) { + // if there is no browser storage support, reloading will lose the comment; this way, the user will be warned + // we assign the return value because it is required by Chrome see: https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onbeforeunload#Example, + event.preventDefault(); + /* eslint-disable-next-line no-param-reassign */ + event.returnValue = ''; + } + + saveComment(); + }); +}; + +export { eventLookup, initializeGlobalListeners }; diff --git a/app/assets/javascripts/visual_review_toolbar/store/index.js b/app/assets/javascripts/visual_review_toolbar/store/index.js index 7143588c0bf..07c8dd6f1d2 100644 --- a/app/assets/javascripts/visual_review_toolbar/store/index.js +++ b/app/assets/javascripts/visual_review_toolbar/store/index.js @@ -1,5 +1,11 @@ -import { eventLookup, updateWindowSize } from './events'; -import { getInitialView, initializeState } from './state'; -import debounce from './utils'; +import { eventLookup, initializeGlobalListeners } from './events'; +import { nextView, getInitialView, initializeState, setUsingGracefulStorageFlag } from './state'; -export { debounce, eventLookup, getInitialView, initializeState, updateWindowSize }; +export { + eventLookup, + getInitialView, + initializeGlobalListeners, + initializeState, + nextView, + setUsingGracefulStorageFlag, +}; diff --git a/app/assets/javascripts/visual_review_toolbar/store/state.js b/app/assets/javascripts/visual_review_toolbar/store/state.js index 22702d524b8..741a5c7d99c 100644 --- a/app/assets/javascripts/visual_review_toolbar/store/state.js +++ b/app/assets/javascripts/visual_review_toolbar/store/state.js @@ -1,8 +1,9 @@ -import { comment, login, collapseButton } from '../components'; +import { comment, login, mrForm } from '../components'; +import { localStorage, COMMENT_BOX, LOGIN, MR_ID } from '../shared'; const state = { browser: '', - href: '', + usingGracefulStorage: '', innerWidth: '', innerHeight: '', mergeRequestId: '', @@ -23,11 +24,31 @@ const getBrowserId = sUsrAg => { return aKeys[nIdx]; }; +const nextView = (appState, form = 'none') => { + const formsList = { + [COMMENT_BOX]: currentState => (currentState.token ? mrForm : login), + [LOGIN]: currentState => (currentState.mergeRequestId ? comment(currentState) : mrForm), + [MR_ID]: currentState => (currentState.token ? comment(currentState) : login), + none: currentState => { + if (!currentState.token) { + return login; + } + + if (currentState.token && !currentState.mergeRequestId) { + return mrForm; + } + + return comment(currentState); + }, + }; + + return formsList[form](appState); +}; + const initializeState = (wind, doc) => { const { innerWidth, innerHeight, - location: { href }, navigator: { platform, userAgent }, } = wind; @@ -39,7 +60,6 @@ const initializeState = (wind, doc) => { // This mutates our default state object above. It's weird but it makes the linter happy. Object.assign(state, { browser, - href, innerWidth, innerHeight, mergeRequestId, @@ -49,30 +69,27 @@ const initializeState = (wind, doc) => { projectPath, userAgent, }); -}; -function getInitialView({ localStorage }) { - const loginView = { - content: login, - toggleButton: collapseButton, - }; + return state; +}; - const commentView = { - content: comment, - toggleButton: collapseButton, - }; +const getInitialView = () => { + const token = localStorage.getItem('token'); + const mrId = localStorage.getItem('mergeRequestId'); - try { - const token = localStorage.getItem('token'); + if (token) { + state.token = token; + } - if (token) { - state.token = token; - return commentView; - } - return loginView; - } catch (err) { - return loginView; + if (mrId) { + state.mergeRequestId = mrId; } -} -export { initializeState, getInitialView, state }; + return nextView(state); +}; + +const setUsingGracefulStorageFlag = flag => { + state.usingGracefulStorage = !flag; +}; + +export { initializeState, getInitialView, nextView, setUsingGracefulStorageFlag, state }; diff --git a/app/assets/javascripts/visual_review_toolbar/styles/toolbar.css b/app/assets/javascripts/visual_review_toolbar/styles/toolbar.css index 6a7b2f52549..e5732fd5d93 100644 --- a/app/assets/javascripts/visual_review_toolbar/styles/toolbar.css +++ b/app/assets/javascripts/visual_review_toolbar/styles/toolbar.css @@ -107,10 +107,14 @@ } .gitlab-button-wrapper { - margin-top: 1rem; + margin-top: 0.5rem; display: flex; align-items: baseline; - justify-content: flex-end; + /* + this makes sure the hit enter to submit picks the correct button + on the comment view + */ + flex-direction: row-reverse; } .gitlab-collapse { @@ -155,6 +159,12 @@ text-decoration: underline; } +.gitlab-link-button { + border: none; + cursor: pointer; + padding: 0 .15rem; +} + .gitlab-message { padding: .25rem 0; margin: 0; @@ -165,7 +175,7 @@ font-size: .7rem; line-height: 1rem; color: #666; - margin-bottom: 0; + margin-bottom: .5rem; } .gitlab-input { diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/squash_before_merge.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/squash_before_merge.vue index accb9d9fef1..98f682c2e8a 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/states/squash_before_merge.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/states/squash_before_merge.vue @@ -36,7 +36,7 @@ export default { :disabled="isDisabled" type="checkbox" name="squash" - class="qa-squash-checkbox" + class="qa-squash-checkbox js-squash-checkbox" @change="$emit('input', $event.target.checked)" /> {{ __('Squash commits') }} diff --git a/app/assets/javascripts/vue_shared/components/markdown/header.vue b/app/assets/javascripts/vue_shared/components/markdown/header.vue index 56a16c9e4d6..fcf2f950501 100644 --- a/app/assets/javascripts/vue_shared/components/markdown/header.vue +++ b/app/assets/javascripts/vue_shared/components/markdown/header.vue @@ -123,7 +123,7 @@ export default { :cursor-offset="4" :tag-content="lineContent" icon="doc-code" - class="qa-suggestion-btn" + class="qa-suggestion-btn js-suggestion-btn" @click="handleSuggestDismissed" /> <gl-popover diff --git a/app/assets/javascripts/vue_shared/components/markdown/suggestion_diff.vue b/app/assets/javascripts/vue_shared/components/markdown/suggestion_diff.vue index 2eb4ec12a4a..a7cd292e01d 100644 --- a/app/assets/javascripts/vue_shared/components/markdown/suggestion_diff.vue +++ b/app/assets/javascripts/vue_shared/components/markdown/suggestion_diff.vue @@ -39,7 +39,7 @@ export default { <template> <div class="md-suggestion"> <suggestion-diff-header - class="qa-suggestion-diff-header" + class="qa-suggestion-diff-header js-suggestion-diff-header" :can-apply="suggestion.appliable && suggestion.current_user.can_apply && !disabled" :is-applied="suggestion.applied" :help-page-path="helpPagePath" diff --git a/app/assets/javascripts/vue_shared/components/markdown/suggestion_diff_header.vue b/app/assets/javascripts/vue_shared/components/markdown/suggestion_diff_header.vue index 32783b85df4..12de3671477 100644 --- a/app/assets/javascripts/vue_shared/components/markdown/suggestion_diff_header.vue +++ b/app/assets/javascripts/vue_shared/components/markdown/suggestion_diff_header.vue @@ -41,7 +41,7 @@ export default { <template> <div class="md-suggestion-header border-bottom-0 mt-2"> - <div class="qa-suggestion-diff-header font-weight-bold"> + <div class="qa-suggestion-diff-header js-suggestion-diff-header font-weight-bold"> {{ __('Suggested change') }} <a v-if="helpPagePath" :href="helpPagePath" :aria-label="__('Help')" class="js-help-btn"> <icon name="question-o" css-classes="link-highlight" /> @@ -55,7 +55,7 @@ export default { <gl-button v-else-if="canApply" v-gl-tooltip.viewport="__('This also resolves the discussion')" - class="btn-inverted qa-apply-btn" + class="btn-inverted qa-apply-btn js-apply-btn" :disabled="isApplying" variant="success" @click="applySuggestion" diff --git a/app/assets/javascripts/vue_shared/components/markdown/toolbar.vue b/app/assets/javascripts/vue_shared/components/markdown/toolbar.vue index 8ce5b615795..21c44b59520 100644 --- a/app/assets/javascripts/vue_shared/components/markdown/toolbar.vue +++ b/app/assets/javascripts/vue_shared/components/markdown/toolbar.vue @@ -1,5 +1,6 @@ <script> import { GlLink } from '@gitlab/ui'; +import { s__, sprintf } from '~/locale'; export default { components: { @@ -22,8 +23,28 @@ export default { }, }, computed: { - hasQuickActionsDocsPath() { - return this.quickActionsDocsPath !== ''; + toolbarHelpHtml() { + const mdLinkStart = `<a href="${this.markdownDocsPath}" target="_blank" rel="noopener noreferrer" tabindex="-1">`; + const actionsLinkStart = `<a href="${this.quickActionsDocsPath}" target="_blank" rel="noopener noreferrer" tabindex="-1">`; + const linkEnd = '</a>'; + + if (this.markdownDocsPath && !this.quickActionsDocsPath) { + return sprintf( + s__('Editor|%{mdLinkStart}Markdown is supported%{mdLinkEnd}'), + { mdLinkStart, mdLinkEnd: linkEnd }, + false, + ); + } else if (this.markdownDocsPath && this.quickActionsDocsPath) { + return sprintf( + s__( + 'Editor|%{mdLinkStart}Markdown%{mdLinkEnd} and %{actionsLinkStart}quick actions%{actionsLinkEnd} are supported', + ), + { mdLinkStart, mdLinkEnd: linkEnd, actionsLinkStart, actionsLinkEnd: linkEnd }, + false, + ); + } + + return null; }, }, }; @@ -32,21 +53,7 @@ export default { <template> <div class="comment-toolbar clearfix"> <div class="toolbar-text"> - <template v-if="!hasQuickActionsDocsPath && markdownDocsPath"> - <gl-link :href="markdownDocsPath" target="_blank" tabindex="-1">{{ - __('Markdown is supported') - }}</gl-link> - </template> - <template v-if="hasQuickActionsDocsPath && markdownDocsPath"> - <gl-link :href="markdownDocsPath" target="_blank" tabindex="-1">{{ - __('Markdown') - }}</gl-link> - and - <gl-link :href="quickActionsDocsPath" target="_blank" tabindex="-1">{{ - __('quick actions') - }}</gl-link> - are supported - </template> + <span v-html="toolbarHelpHtml"></span> </div> <span v-if="canAttachFile" class="uploading-container"> <span class="uploading-progress-container hide"> diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss index 61ab0476c42..6b44834cc52 100644 --- a/app/assets/stylesheets/framework/common.scss +++ b/app/assets/stylesheets/framework/common.scss @@ -441,6 +441,7 @@ img.emoji { .mw-460 { max-width: 460px; } .mw-6em { max-width: 6em; } .mw-70p { max-width: 70%; } +.mw-90p { max-width: 90%; } .min-height-0 { min-height: 0; } diff --git a/app/assets/stylesheets/framework/lists.scss b/app/assets/stylesheets/framework/lists.scss index 460d9ea9526..ecd32dcd0ce 100644 --- a/app/assets/stylesheets/framework/lists.scss +++ b/app/assets/stylesheets/framework/lists.scss @@ -285,3 +285,19 @@ ul.indent-list { max-width: 350px; } } + +.horizontal-list { + padding-left: 0; + list-style: none; + + > li { + float: left; + } + + &.list-items-separated { + > li:not(:last-child)::after { + content: '\00b7'; + margin: 0 $gl-padding-4; + } + } +} diff --git a/app/assets/stylesheets/framework/tooltips.scss b/app/assets/stylesheets/framework/tooltips.scss index 98f28987a82..edc2fb532c8 100644 --- a/app/assets/stylesheets/framework/tooltips.scss +++ b/app/assets/stylesheets/framework/tooltips.scss @@ -1,7 +1,6 @@ .tooltip-inner { - font-size: $tooltip-font-size; + font-size: $gl-font-size-small; border-radius: $border-radius-default; - line-height: 16px; + line-height: $gl-line-height; font-weight: $gl-font-weight-normal; - padding: 8px; } diff --git a/app/assets/stylesheets/framework/variables_overrides.scss b/app/assets/stylesheets/framework/variables_overrides.scss index ea96381a098..604b48e11ab 100644 --- a/app/assets/stylesheets/framework/variables_overrides.scss +++ b/app/assets/stylesheets/framework/variables_overrides.scss @@ -48,3 +48,7 @@ $spacers: ( 9: ($spacer * 8) ); $pagination-color: $gl-text-color; +$tooltip-padding-y: 0.5rem; +$tooltip-padding-x: 0.75rem; +$tooltip-arrow-height: 0.5rem; +$tooltip-arrow-width: 1rem; diff --git a/app/assets/stylesheets/performance_bar.scss b/app/assets/stylesheets/performance_bar.scss index 5a8940ffd6d..ad7d87f0bf6 100644 --- a/app/assets/stylesheets/performance_bar.scss +++ b/app/assets/stylesheets/performance_bar.scss @@ -1,6 +1,5 @@ @import 'framework/variables'; @import 'framework/variables_overrides'; -@import 'peek/views/rblineprof'; #js-peek { position: fixed; @@ -128,13 +127,3 @@ #modal-peek-pg-queries-content { color: $black; } - -.peek-rblineprof-file { - pre.duration { - width: 280px; - } - - .data { - overflow: visible; - } -} diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb index e9ec8876688..99411641874 100644 --- a/app/controllers/admin/application_settings_controller.rb +++ b/app/controllers/admin/application_settings_controller.rb @@ -106,6 +106,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController :lets_encrypt_notification_email, :lets_encrypt_terms_of_service_accepted, :domain_blacklist_file, + :raw_blob_request_limit, disabled_oauth_sign_in_sources: [], import_sources: [], repository_storages: [], diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 0c80a276fce..1d55a073f3b 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -421,7 +421,7 @@ class ApplicationController < ActionController::Base end def manifest_import_enabled? - Group.supports_nested_objects? && Gitlab::CurrentSettings.import_sources.include?('manifest') + Gitlab::CurrentSettings.import_sources.include?('manifest') end def phabricator_import_enabled? diff --git a/app/controllers/concerns/authenticates_with_two_factor.rb b/app/controllers/concerns/authenticates_with_two_factor.rb index 4926062f9ca..8c8f0b3a22e 100644 --- a/app/controllers/concerns/authenticates_with_two_factor.rb +++ b/app/controllers/concerns/authenticates_with_two_factor.rb @@ -55,7 +55,7 @@ module AuthenticatesWithTwoFactor remember_me(user) if user_params[:remember_me] == '1' user.save! - sign_in(user, message: :two_factor_authenticated) + sign_in(user, message: :two_factor_authenticated, event: :authentication) else user.increment_failed_attempts! Gitlab::AppLogger.info("Failed Login: user=#{user.username} ip=#{request.remote_ip} method=OTP") @@ -72,7 +72,7 @@ module AuthenticatesWithTwoFactor session.delete(:challenge) remember_me(user) if user_params[:remember_me] == '1' - sign_in(user, message: :two_factor_authenticated) + sign_in(user, message: :two_factor_authenticated, event: :authentication) else user.increment_failed_attempts! Gitlab::AppLogger.info("Failed Login: user=#{user.username} ip=#{request.remote_ip} method=U2F") diff --git a/app/controllers/concerns/group_tree.rb b/app/controllers/concerns/group_tree.rb index e9a7d6a3152..d076c62c707 100644 --- a/app/controllers/concerns/group_tree.rb +++ b/app/controllers/concerns/group_tree.rb @@ -32,18 +32,14 @@ module GroupTree def filtered_groups_with_ancestors(groups) filtered_groups = groups.search(params[:filter]).page(params[:page]) - if Group.supports_nested_objects? - # We find the ancestors by ID of the search results here. - # Otherwise the ancestors would also have filters applied, - # which would cause them not to be preloaded. - # - # Pagination needs to be applied before loading the ancestors to - # make sure ancestors are not cut off by pagination. - Gitlab::ObjectHierarchy.new(Group.where(id: filtered_groups.select(:id))) - .base_and_ancestors - else - filtered_groups - end + # We find the ancestors by ID of the search results here. + # Otherwise the ancestors would also have filters applied, + # which would cause them not to be preloaded. + # + # Pagination needs to be applied before loading the ancestors to + # make sure ancestors are not cut off by pagination. + Gitlab::ObjectHierarchy.new(Group.where(id: filtered_groups.select(:id))) + .base_and_ancestors end # rubocop: enable CodeReuse/ActiveRecord end diff --git a/app/controllers/concerns/sessionless_authentication.rb b/app/controllers/concerns/sessionless_authentication.rb index 590eefc6dab..4304b8565ce 100644 --- a/app/controllers/concerns/sessionless_authentication.rb +++ b/app/controllers/concerns/sessionless_authentication.rb @@ -13,7 +13,7 @@ module SessionlessAuthentication end def sessionless_user? - current_user && !session.keys.include?('warden.user.user.key') + current_user && !session.key?('warden.user.user.key') end def sessionless_sign_in(user) diff --git a/app/controllers/concerns/uploads_actions.rb b/app/controllers/concerns/uploads_actions.rb index 59f6d3452a3..f5d35379e10 100644 --- a/app/controllers/concerns/uploads_actions.rb +++ b/app/controllers/concerns/uploads_actions.rb @@ -90,7 +90,7 @@ module UploadsActions return unless uploader = build_uploader upload_paths = uploader.upload_paths(params[:filename]) - upload = Upload.find_by(uploader: uploader_class.to_s, path: upload_paths) + upload = Upload.find_by(model: model, uploader: uploader_class.to_s, path: upload_paths) upload&.build_uploader end # rubocop: enable CodeReuse/ActiveRecord diff --git a/app/controllers/concerns/with_performance_bar.rb b/app/controllers/concerns/with_performance_bar.rb index 77c3d476ac6..4e0ae3c59eb 100644 --- a/app/controllers/concerns/with_performance_bar.rb +++ b/app/controllers/concerns/with_performance_bar.rb @@ -3,10 +3,6 @@ module WithPerformanceBar extend ActiveSupport::Concern - included do - include Peek::Rblineprof::CustomControllerHelpers - end - def peek_enabled? return false unless Gitlab::PerformanceBar.enabled?(current_user) diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb index 0176962cf0a..dda321bac79 100644 --- a/app/controllers/groups_controller.rb +++ b/app/controllers/groups_controller.rb @@ -8,7 +8,7 @@ class GroupsController < Groups::ApplicationController include RecordUserLastActivity before_action do - push_frontend_feature_flag(:manual_sorting) + push_frontend_feature_flag(:manual_sorting, default_enabled: true) end respond_to :html diff --git a/app/controllers/import/github_controller.rb b/app/controllers/import/github_controller.rb index aa4aa0fbdac..ebb50fc8b10 100644 --- a/app/controllers/import/github_controller.rb +++ b/app/controllers/import/github_controller.rb @@ -10,7 +10,7 @@ class Import::GithubController < Import::BaseController rescue_from Octokit::Unauthorized, with: :provider_unauthorized def new - if github_import_configured? && logged_in_with_provider? + if !ci_cd_only? && github_import_configured? && logged_in_with_provider? go_to_provider_for_permissions elsif session[access_token_key] redirect_to status_import_url @@ -169,11 +169,15 @@ class Import::GithubController < Import::BaseController # rubocop: enable CodeReuse/ActiveRecord def provider_auth - if session[access_token_key].blank? + if !ci_cd_only? && session[access_token_key].blank? go_to_provider_for_permissions end end + def ci_cd_only? + %w[1 true].include?(params[:ci_cd_only]) + end + def client_options {} end diff --git a/app/controllers/omniauth_callbacks_controller.rb b/app/controllers/omniauth_callbacks_controller.rb index 2a8dd997d04..b1efa767154 100644 --- a/app/controllers/omniauth_callbacks_controller.rb +++ b/app/controllers/omniauth_callbacks_controller.rb @@ -139,7 +139,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController if user.two_factor_enabled? && !auth_user.bypass_two_factor? prompt_for_two_factor(user) else - sign_in_and_redirect(user) + sign_in_and_redirect(user, event: :authentication) end else fail_login(user) diff --git a/app/controllers/projects/artifacts_controller.rb b/app/controllers/projects/artifacts_controller.rb index 2ef18d900f2..da8a371acaa 100644 --- a/app/controllers/projects/artifacts_controller.rb +++ b/app/controllers/projects/artifacts_controller.rb @@ -92,7 +92,10 @@ class Projects::ArtifactsController < Projects::ApplicationController def build_from_ref return unless @ref_name - project.latest_successful_build_for(params[:job], @ref_name) + commit = project.commit(@ref_name) + return unless commit + + project.latest_successful_build_for_sha(params[:job], commit.id) end def artifacts_file diff --git a/app/controllers/projects/badges_controller.rb b/app/controllers/projects/badges_controller.rb index 09a384e89ab..66b51b17790 100644 --- a/app/controllers/projects/badges_controller.rb +++ b/app/controllers/projects/badges_controller.rb @@ -3,7 +3,8 @@ class Projects::BadgesController < Projects::ApplicationController layout 'project_settings' before_action :authorize_admin_project!, only: [:index] - before_action :no_cache_headers, except: [:index] + before_action :no_cache_headers, only: [:pipeline, :coverage] + before_action :authorize_read_build!, only: [:pipeline, :coverage] def pipeline pipeline_status = Gitlab::Badge::Pipeline::Status diff --git a/app/controllers/projects/build_artifacts_controller.rb b/app/controllers/projects/build_artifacts_controller.rb index 4274c356227..99f4524eec5 100644 --- a/app/controllers/projects/build_artifacts_controller.rb +++ b/app/controllers/projects/build_artifacts_controller.rb @@ -51,6 +51,6 @@ class Projects::BuildArtifactsController < Projects::ApplicationController def job_from_ref return unless @ref_name - project.latest_successful_build_for(params[:job], @ref_name) + project.latest_successful_build_for_ref(params[:job], @ref_name) end end diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb index 228de8bc6f3..db7ca7ef0d7 100644 --- a/app/controllers/projects/issues_controller.rb +++ b/app/controllers/projects/issues_controller.rb @@ -11,7 +11,7 @@ class Projects::IssuesController < Projects::ApplicationController include RecordUserLastActivity before_action do - push_frontend_feature_flag(:manual_sorting) + push_frontend_feature_flag(:manual_sorting, default_enabled: true) end def issue_except_actions diff --git a/app/controllers/projects/jobs_controller.rb b/app/controllers/projects/jobs_controller.rb index 02ff6e872c9..adbc0159358 100644 --- a/app/controllers/projects/jobs_controller.rb +++ b/app/controllers/projects/jobs_controller.rb @@ -94,7 +94,7 @@ class Projects::JobsController < Projects::ApplicationController def play return respond_422 unless @build.playable? - build = @build.play(current_user) + build = @build.play(current_user, play_params[:job_variables_attributes]) redirect_to build_path(build) end @@ -190,6 +190,10 @@ class Projects::JobsController < Projects::ApplicationController { query: { 'response-content-type' => 'text/plain; charset=utf-8', 'response-content-disposition' => 'inline' } } end + def play_params + params.permit(job_variables_attributes: %i[key secret_value]) + end + def trace_artifact_file @trace_artifact_file ||= build.job_artifacts_trace&.file end diff --git a/app/controllers/projects/merge_requests/application_controller.rb b/app/controllers/projects/merge_requests/application_controller.rb index dcc272aecff..006731c0e66 100644 --- a/app/controllers/projects/merge_requests/application_controller.rb +++ b/app/controllers/projects/merge_requests/application_controller.rb @@ -45,7 +45,7 @@ class Projects::MergeRequests::ApplicationController < Projects::ApplicationCont def set_pipeline_variables @pipelines = - if can?(current_user, :read_pipeline, @project) + if can?(current_user, :read_pipeline, @merge_request.source_project) @merge_request.all_pipelines else Ci::Pipeline.none diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index 2aa2508be16..f4d381244d9 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -82,7 +82,8 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo end def pipelines - @pipelines = @merge_request.all_pipelines.page(params[:page]).per(30) + set_pipeline_variables + @pipelines = @pipelines.page(params[:page]).per(30) Gitlab::PollingInterval.set_header(response, interval: 10_000) diff --git a/app/controllers/projects/raw_controller.rb b/app/controllers/projects/raw_controller.rb index 42ae5b0ef3c..3254229d9cb 100644 --- a/app/controllers/projects/raw_controller.rb +++ b/app/controllers/projects/raw_controller.rb @@ -8,10 +8,30 @@ class Projects::RawController < Projects::ApplicationController before_action :require_non_empty_project before_action :assign_ref_vars before_action :authorize_download_code! + before_action :show_rate_limit, only: [:show] def show @blob = @repository.blob_at(@commit.id, @path) send_blob(@repository, @blob, inline: (params[:inline] != 'false')) end + + private + + def show_rate_limit + limiter = ::Gitlab::ActionRateLimiter.new(action: :show_raw_controller) + + return unless limiter.throttled?([@project, @commit, @path], raw_blob_request_limit) + + limiter.log_request(request, :raw_blob_request_limit, current_user) + + flash[:alert] = _('You cannot access the raw file. Please wait a minute.') + redirect_to project_blob_path(@project, File.join(@ref, @path)) + end + + def raw_blob_request_limit + Gitlab::CurrentSettings + .current_application_settings + .raw_blob_request_limit + end end diff --git a/app/controllers/projects/repositories_controller.rb b/app/controllers/projects/repositories_controller.rb index 3b4215b766e..a51759641e4 100644 --- a/app/controllers/projects/repositories_controller.rb +++ b/app/controllers/projects/repositories_controller.rb @@ -6,6 +6,7 @@ class Projects::RepositoriesController < Projects::ApplicationController # Authorize before_action :require_non_empty_project, except: :create before_action :assign_archive_vars, only: :archive + before_action :assign_append_sha, only: :archive before_action :authorize_download_code! before_action :authorize_admin_project!, only: :create @@ -16,19 +17,64 @@ class Projects::RepositoriesController < Projects::ApplicationController end def archive - append_sha = params[:append_sha] + set_cache_headers + return if archive_not_modified? - if @ref - shortname = "#{@project.path}-#{@ref.tr('/', '-')}" - append_sha = false if @filename == shortname - end - - send_git_archive @repository, ref: @ref, path: params[:path], format: params[:format], append_sha: append_sha + send_git_archive @repository, **repo_params rescue => ex logger.error("#{self.class.name}: #{ex}") git_not_found! end + private + + def repo_params + @repo_params ||= { ref: @ref, path: params[:path], format: params[:format], append_sha: @append_sha } + end + + def set_cache_headers + expires_in cache_max_age(archive_metadata['CommitId']), public: project.public? + fresh_when(etag: archive_metadata['ArchivePath']) + end + + def archive_not_modified? + # Check response freshness (Last-Modified and ETag) + # against request If-Modified-Since and If-None-Match conditions. + request.fresh?(response) + end + + def archive_metadata + @archive_metadata ||= @repository.archive_metadata( + @ref, + '', # Where archives are stored isn't really important for ETag purposes + repo_params[:format], + path: repo_params[:path], + append_sha: @append_sha + ) + end + + def cache_max_age(commit_id) + if @ref == commit_id + # This is a link to an archive by a commit SHA. That means that the archive + # is immutable. The only reason to invalidate the cache is if the commit + # was deleted or if the user lost access to the repository. + Repository::ARCHIVE_CACHE_TIME_IMMUTABLE + else + # A branch or tag points at this archive. That means that the expected archive + # content may change over time. + Repository::ARCHIVE_CACHE_TIME + end + end + + def assign_append_sha + @append_sha = params[:append_sha] + + if @ref + shortname = "#{@project.path}-#{@ref.tr('/', '-')}" + @append_sha = false if @filename == shortname + end + end + def assign_archive_vars if params[:id] @ref, @filename = extract_ref(params[:id]) diff --git a/app/controllers/projects/triggers_controller.rb b/app/controllers/projects/triggers_controller.rb index 284e119ca06..7159d0243a3 100644 --- a/app/controllers/projects/triggers_controller.rb +++ b/app/controllers/projects/triggers_controller.rb @@ -4,7 +4,7 @@ class Projects::TriggersController < Projects::ApplicationController before_action :authorize_admin_build! before_action :authorize_manage_trigger!, except: [:index, :create] before_action :authorize_admin_trigger!, only: [:edit, :update] - before_action :trigger, only: [:take_ownership, :edit, :update, :destroy] + before_action :trigger, only: [:edit, :update, :destroy] layout 'project_settings' @@ -24,16 +24,6 @@ class Projects::TriggersController < Projects::ApplicationController redirect_to project_settings_ci_cd_path(@project, anchor: 'js-pipeline-triggers') end - def take_ownership - if trigger.update(owner: current_user) - flash[:notice] = _('Trigger was re-assigned.') - else - flash[:alert] = _('You could not take ownership of trigger.') - end - - redirect_to project_settings_ci_cd_path(@project, anchor: 'js-pipeline-triggers') - end - def edit end diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 37ffd28bf9e..d4ff72c2314 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -284,6 +284,18 @@ class ProjectsController < Projects::ApplicationController end # rubocop: enable CodeReuse/ActiveRecord + def resolve + @project = Project.find(params[:id]) + + if can?(current_user, :read_project, @project) + redirect_to @project + else + render_404 + end + end + + private + # Render project landing depending of which features are available # So if page is not available in the list it renders the next page # @@ -453,14 +465,4 @@ class ProjectsController < Projects::ApplicationController def present_project @project = @project.present(current_user: current_user) end - - def resolve - @project = Project.find(params[:id]) - - if can?(current_user, :read_project, @project) - redirect_to @project - else - render_404 - end - end end diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb index 8c674be58c5..13741548687 100644 --- a/app/controllers/search_controller.rb +++ b/app/controllers/search_controller.rb @@ -31,6 +31,8 @@ class SearchController < ApplicationController render_commits if @scope == 'commits' eager_load_user_status if @scope == 'users' + increment_navbar_searches_counter + check_single_commit_result end @@ -70,4 +72,10 @@ class SearchController < ApplicationController redirect_to project_commit_path(@project, only_commit) if found_by_commit_sha end end + + def increment_navbar_searches_counter + return if params[:nav_source] != 'navbar' + + Gitlab::UsageDataCounters::SearchCounter.increment_navbar_searches_count + end end diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index 7604b31467a..1880bead3ee 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -26,6 +26,17 @@ class SessionsController < Devise::SessionsController after_action :log_failed_login, if: -> { action_name == 'new' && failed_login? } helper_method :captcha_enabled? + # protect_from_forgery is already prepended in ApplicationController but + # authenticate_with_two_factor which signs in the user is prepended before + # that here. + # We need to make sure CSRF token is verified before authenticating the user + # because Devise.clean_up_csrf_token_on_authentication is set to true by + # default to avoid CSRF token fixation attacks. Authenticating the user first + # would cause the CSRF token to be cleared and then + # RequestForgeryProtection#verify_authenticity_token would fail because of + # token mismatch. + protect_from_forgery with: :exception, prepend: true + CAPTCHA_HEADER = 'X-GitLab-Show-Login-Captcha'.freeze def new diff --git a/app/finders/group_descendants_finder.rb b/app/finders/group_descendants_finder.rb index ec340f38450..4e489a9c930 100644 --- a/app/finders/group_descendants_finder.rb +++ b/app/finders/group_descendants_finder.rb @@ -132,8 +132,6 @@ class GroupDescendantsFinder end def subgroups - return Group.none unless Group.supports_nested_objects? - # When filtering subgroups, we want to find all matches within the tree of # descendants to show to the user groups = if params[:filter] diff --git a/app/finders/group_members_finder.rb b/app/finders/group_members_finder.rb index eebc67cfa9e..33ec6a715f9 100644 --- a/app/finders/group_members_finder.rb +++ b/app/finders/group_members_finder.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -class GroupMembersFinder +class GroupMembersFinder < UnionFinder def initialize(group) @group = group end @@ -8,18 +8,18 @@ class GroupMembersFinder # rubocop: disable CodeReuse/ActiveRecord def execute(include_descendants: false) group_members = @group.members - wheres = [] + relations = [] return group_members unless @group.parent || include_descendants - wheres << "members.id IN (#{group_members.select(:id).to_sql})" + relations << group_members if @group.parent parents_members = GroupMember.non_request .where(source_id: @group.ancestors.select(:id)) .where.not(user_id: @group.users.select(:id)) - wheres << "members.id IN (#{parents_members.select(:id).to_sql})" + relations << parents_members end if include_descendants @@ -27,10 +27,10 @@ class GroupMembersFinder .where(source_id: @group.descendants.select(:id)) .where.not(user_id: @group.users.select(:id)) - wheres << "members.id IN (#{descendant_members.select(:id).to_sql})" + relations << descendant_members end - GroupMember.where(wheres.join(' OR ')) + find_union(relations, GroupMember) end # rubocop: enable CodeReuse/ActiveRecord end diff --git a/app/finders/issuable_finder.rb b/app/finders/issuable_finder.rb index f4fbeacfaba..1773ac2d508 100644 --- a/app/finders/issuable_finder.rb +++ b/app/finders/issuable_finder.rb @@ -320,7 +320,6 @@ class IssuableFinder def use_cte_for_search? strong_memoize(:use_cte_for_search) do next false unless search - next false unless Gitlab::Database.postgresql? # Only simple unsorted & simple sorts can use CTE next false if params[:sort].present? && !params[:sort].in?(klass.simple_sorts.keys) diff --git a/app/finders/members_finder.rb b/app/finders/members_finder.rb index 917de249104..f730b015c0a 100644 --- a/app/finders/members_finder.rb +++ b/app/finders/members_finder.rb @@ -59,35 +59,16 @@ class MembersFinder def distinct_on(union) # We're interested in a list of members without duplicates by user_id. # We prefer project members over group members, project members should go first. - if Gitlab::Database.postgresql? - <<~SQL - SELECT DISTINCT ON (user_id, invite_email) member_union.* - FROM (#{union.to_sql}) AS member_union - ORDER BY user_id, - invite_email, - CASE - WHEN type = 'ProjectMember' THEN 1 - WHEN type = 'GroupMember' THEN 2 - ELSE 3 - END - SQL - else - # Older versions of MySQL do not support window functions (and DISTINCT ON is postgres-specific). - <<~SQL - SELECT t1.* - FROM (#{union.to_sql}) AS t1 - JOIN ( - SELECT - COALESCE(user_id, -1) AS user_id, - COALESCE(invite_email, 'NULL') AS invite_email, - MIN(CASE WHEN type = 'ProjectMember' THEN 1 WHEN type = 'GroupMember' THEN 2 ELSE 3 END) AS type_number - FROM - (#{union.to_sql}) AS t3 - GROUP BY COALESCE(user_id, -1), COALESCE(invite_email, 'NULL') - ) AS t2 ON COALESCE(t1.user_id, -1) = t2.user_id - AND COALESCE(t1.invite_email, 'NULL') = t2.invite_email - AND CASE WHEN t1.type = 'ProjectMember' THEN 1 WHEN t1.type = 'GroupMember' THEN 2 ELSE 3 END = t2.type_number - SQL - end + <<~SQL + SELECT DISTINCT ON (user_id, invite_email) member_union.* + FROM (#{union.to_sql}) AS member_union + ORDER BY user_id, + invite_email, + CASE + WHEN type = 'ProjectMember' THEN 1 + WHEN type = 'GroupMember' THEN 2 + ELSE 3 + END + SQL end end diff --git a/app/graphql/types/group_type.rb b/app/graphql/types/group_type.rb index 530aecc2bf9..66b41919914 100644 --- a/app/graphql/types/group_type.rb +++ b/app/graphql/types/group_type.rb @@ -14,10 +14,8 @@ module Types group.avatar_url(only_path: false) end - if ::Group.supports_nested_objects? - field :parent, GroupType, - null: true, - resolve: -> (obj, _args, _ctx) { Gitlab::Graphql::Loaders::BatchModelLoader.new(Group, obj.parent_id).find } - end + field :parent, GroupType, + null: true, + resolve: -> (obj, _args, _ctx) { Gitlab::Graphql::Loaders::BatchModelLoader.new(Group, obj.parent_id).find } end end diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb index 4bf9b708401..3847a35fbab 100644 --- a/app/helpers/application_settings_helper.rb +++ b/app/helpers/application_settings_helper.rb @@ -177,6 +177,7 @@ module ApplicationSettingsHelper :domain_blacklist_enabled, :domain_blacklist_raw, :domain_whitelist_raw, + :outbound_local_requests_whitelist_raw, :dsa_key_restriction, :ecdsa_key_restriction, :ed25519_key_restriction, diff --git a/app/helpers/avatars_helper.rb b/app/helpers/avatars_helper.rb index 5906ddabee4..81ff359556d 100644 --- a/app/helpers/avatars_helper.rb +++ b/app/helpers/avatars_helper.rb @@ -52,7 +52,7 @@ module AvatarsHelper user: commit_or_event.author, user_name: commit_or_event.author_name, user_email: commit_or_event.author_email, - css_class: 'd-none d-sm-inline' + css_class: 'd-none d-sm-inline-block' })) end diff --git a/app/helpers/dashboard_helper.rb b/app/helpers/dashboard_helper.rb index 42732eb93dd..d71af08a656 100644 --- a/app/helpers/dashboard_helper.rb +++ b/app/helpers/dashboard_helper.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true module DashboardHelper + include IconsHelper + def assigned_issues_dashboard_path issues_dashboard_path(assignee_username: current_user.username) end @@ -25,6 +27,19 @@ module DashboardHelper false end + def feature_entry(title, href: nil, enabled: true) + enabled_text = enabled ? 'on' : 'off' + label = "#{title}: status #{enabled_text}" + link_or_title = href && enabled ? tag.a(title, href: href) : title + + tag.p(aria: { label: label }) do + concat(link_or_title) + concat(tag.span(class: ['light', 'float-right']) do + concat(boolean_to_icon(enabled)) + end) + end + end + private def get_dashboard_nav_links diff --git a/app/helpers/groups_helper.rb b/app/helpers/groups_helper.rb index 5aed7e313e6..160f9ac4793 100644 --- a/app/helpers/groups_helper.rb +++ b/app/helpers/groups_helper.rb @@ -127,10 +127,6 @@ module GroupsHelper groups.to_json end - def supports_nested_groups? - Group.supports_nested_objects? - end - private def get_group_sidebar_links diff --git a/app/helpers/labels_helper.rb b/app/helpers/labels_helper.rb index db4f29cd996..2ed016beea4 100644 --- a/app/helpers/labels_helper.rb +++ b/app/helpers/labels_helper.rb @@ -4,11 +4,10 @@ module LabelsHelper extend self include ActionView::Helpers::TagHelper - def show_label_issuables_link?(label, issuables_type, current_user: nil, project: nil) + def show_label_issuables_link?(label, issuables_type, current_user: nil) return true unless label.project_label? - return true unless project - project.feature_available?(issuables_type, current_user) + label.project.feature_available?(issuables_type, current_user) end # Link to a Label diff --git a/app/helpers/sorting_helper.rb b/app/helpers/sorting_helper.rb index d5e5b472115..15f35645c78 100644 --- a/app/helpers/sorting_helper.rb +++ b/app/helpers/sorting_helper.rb @@ -210,7 +210,7 @@ module SortingHelper end def sort_direction_button(reverse_url, reverse_sort, sort_value) - link_class = 'btn btn-default has-tooltip reverse-sort-btn qa-reverse-sort' + link_class = 'btn btn-default has-tooltip reverse-sort-btn qa-reverse-sort rspec-reverse-sort' icon = sort_direction_icon(sort_value) url = reverse_url diff --git a/app/helpers/submodule_helper.rb b/app/helpers/submodule_helper.rb index 9a281065b90..e683e2959d1 100644 --- a/app/helpers/submodule_helper.rb +++ b/app/helpers/submodule_helper.rb @@ -13,6 +13,8 @@ module SubmoduleHelper end def submodule_links_for_url(submodule_item_id, url, repository) + return [nil, nil] unless url + if url == '.' || url == './' url = File.join(Gitlab.config.gitlab.url, repository.project.full_path) end diff --git a/app/helpers/system_note_helper.rb b/app/helpers/system_note_helper.rb index ac4e8f54260..3efae0a653c 100644 --- a/app/helpers/system_note_helper.rb +++ b/app/helpers/system_note_helper.rb @@ -21,6 +21,7 @@ module SystemNoteHelper 'discussion' => 'comment', 'moved' => 'arrow-right', 'outdated' => 'pencil-square', + 'pinned_embed' => 'thumbtack', 'duplicate' => 'issue-duplicate', 'locked' => 'lock', 'unlocked' => 'lock-open', diff --git a/app/helpers/wiki_helper.rb b/app/helpers/wiki_helper.rb index edd48f82729..dd8fde2a697 100644 --- a/app/helpers/wiki_helper.rb +++ b/app/helpers/wiki_helper.rb @@ -50,7 +50,7 @@ module WikiHelper def wiki_sort_controls(project, sort, direction) sort ||= ProjectWiki::TITLE_ORDER - link_class = 'btn btn-default has-tooltip reverse-sort-btn qa-reverse-sort' + link_class = 'btn btn-default has-tooltip reverse-sort-btn qa-reverse-sort rspec-reverse-sort' reversed_direction = direction == 'desc' ? 'asc' : 'desc' icon_class = direction == 'desc' ? 'highest' : 'lowest' diff --git a/app/mailers/emails/members.rb b/app/mailers/emails/members.rb index 2bfa59774d7..76fa7236ab1 100644 --- a/app/mailers/emails/members.rb +++ b/app/mailers/emails/members.rb @@ -9,11 +9,11 @@ module Emails helper_method :member_source, :member end - def member_access_requested_email(member_source_type, member_id, recipient_notification_email) + def member_access_requested_email(member_source_type, member_id, recipient_id) @member_source_type = member_source_type @member_id = member_id - mail(to: recipient_notification_email, + mail(to: recipient(recipient_id, notification_group), subject: subject("Request to join the #{member_source.human_name} #{member_source.model_name.singular}")) end @@ -21,16 +21,15 @@ module Emails @member_source_type = member_source_type @member_id = member_id - mail(to: member.user.notification_email, + mail(to: recipient(member.user, notification_group), subject: subject("Access to the #{member_source.human_name} #{member_source.model_name.singular} was granted")) end def member_access_denied_email(member_source_type, source_id, user_id) @member_source_type = member_source_type @member_source = member_source_class.find(source_id) - requester = User.find(user_id) - mail(to: requester.notification_email, + mail(to: recipient(user_id, notification_group), subject: subject("Access to the #{member_source.human_name} #{member_source.model_name.singular} was denied")) end @@ -48,7 +47,7 @@ module Emails @member_id = member_id return unless member.created_by - mail(to: member.created_by.notification_email, + mail(to: recipient(member.created_by, notification_group), subject: subject('Invitation accepted')) end @@ -59,7 +58,7 @@ module Emails @member_source = member_source_class.find(source_id) @invite_email = invite_email - mail(to: recipient(created_by_id, member_source_type == 'Project' ? @member_source.group : @member_source), + mail(to: recipient(created_by_id, notification_group), subject: subject('Invitation declined')) end @@ -71,6 +70,10 @@ module Emails @member_source ||= member.source end + def notification_group + @member_source_type.casecmp?('project') ? member_source.group : member_source + end + private def member_source_class diff --git a/app/mailers/notify.rb b/app/mailers/notify.rb index 8ef20a03541..5d292094a05 100644 --- a/app/mailers/notify.rb +++ b/app/mailers/notify.rb @@ -71,14 +71,18 @@ class Notify < BaseMailer address.format end - # Look up a User by their ID and return their email address + # Look up a User's notification email for a particular context. + # Can look up by their ID or can accept a User object. # - # recipient_id - User ID + # recipient - User object OR a User ID # notification_group - The parent group of the notification # # Returns a String containing the User's email address. - def recipient(recipient_id, notification_group = nil) - User.find(recipient_id).notification_email_for(notification_group) + def recipient(recipient, notification_group = nil) + user = recipient if recipient.is_a?(User) + user ||= User.find(recipient) + + user.notification_email_for(notification_group) end # Formats arguments into a String suitable for use as an email subject diff --git a/app/mailers/previews/notify_preview.rb b/app/mailers/previews/notify_preview.rb index 80e0a17c312..b3fab930922 100644 --- a/app/mailers/previews/notify_preview.rb +++ b/app/mailers/previews/notify_preview.rb @@ -105,11 +105,11 @@ class NotifyPreview < ActionMailer::Preview end def member_access_granted_email - Notify.member_access_granted_email('project', user.id).message + Notify.member_access_granted_email(member.source_type, member.id).message end def member_access_requested_email - Notify.member_access_requested_email('group', user.id, 'some@example.com').message + Notify.member_access_requested_email('group', user.id, user.id).message end def member_invite_accepted_email @@ -183,6 +183,10 @@ class NotifyPreview < ActionMailer::Preview @user ||= User.last end + def member + @member ||= Member.last + end + def create_note(params) Notes::CreateService.new(project, user, params).execute end diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index 8e558487c1c..a769a8f07fd 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -41,6 +41,11 @@ class ApplicationSetting < ApplicationRecord validates :uuid, presence: true + validates :outbound_local_requests_whitelist, + length: { maximum: 1_000, message: N_('is too long (maximum is 1000 entries)') } + + validates :outbound_local_requests_whitelist, qualified_domain_array: true, allow_blank: true + validates :session_expire_delay, presence: true, numericality: { only_integer: true, greater_than_or_equal_to: 0 } diff --git a/app/models/application_setting_implementation.rb b/app/models/application_setting_implementation.rb index df4caed175d..1e612bd0e78 100644 --- a/app/models/application_setting_implementation.rb +++ b/app/models/application_setting_implementation.rb @@ -2,6 +2,7 @@ module ApplicationSettingImplementation extend ActiveSupport::Concern + include Gitlab::Utils::StrongMemoize DOMAIN_LIST_SEPARATOR = %r{\s*[,;]\s* # comma or semicolon, optionally surrounded by whitespace | # or @@ -96,7 +97,9 @@ module ApplicationSettingImplementation diff_max_patch_bytes: Gitlab::Git::Diff::DEFAULT_MAX_PATCH_BYTES, commit_email_hostname: default_commit_email_hostname, protected_ci_variables: false, - local_markdown_version: 0 + local_markdown_version: 0, + outbound_local_requests_whitelist: [], + raw_blob_request_limit: 300 } end @@ -131,31 +134,52 @@ module ApplicationSettingImplementation end def domain_whitelist_raw - self.domain_whitelist&.join("\n") + array_to_string(self.domain_whitelist) end def domain_blacklist_raw - self.domain_blacklist&.join("\n") + array_to_string(self.domain_blacklist) end def domain_whitelist_raw=(values) - self.domain_whitelist = [] - self.domain_whitelist = values.split(DOMAIN_LIST_SEPARATOR) - self.domain_whitelist.reject! { |d| d.empty? } - self.domain_whitelist + self.domain_whitelist = domain_strings_to_array(values) end def domain_blacklist_raw=(values) - self.domain_blacklist = [] - self.domain_blacklist = values.split(DOMAIN_LIST_SEPARATOR) - self.domain_blacklist.reject! { |d| d.empty? } - self.domain_blacklist + self.domain_blacklist = domain_strings_to_array(values) end def domain_blacklist_file=(file) self.domain_blacklist_raw = file.read end + def outbound_local_requests_whitelist_raw + array_to_string(self.outbound_local_requests_whitelist) + end + + def outbound_local_requests_whitelist_raw=(values) + self.outbound_local_requests_whitelist = domain_strings_to_array(values) + end + + def outbound_local_requests_whitelist_arrays + strong_memoize(:outbound_local_requests_whitelist_arrays) do + ip_whitelist = [] + domain_whitelist = [] + + self.outbound_local_requests_whitelist.each do |str| + ip_obj = Gitlab::Utils.string_to_ip_object(str) + + if ip_obj + ip_whitelist << ip_obj + else + domain_whitelist << str + end + end + + [ip_whitelist, domain_whitelist] + end + end + def repository_storages Array(read_attribute(:repository_storages)) end @@ -255,6 +279,17 @@ module ApplicationSettingImplementation private + def array_to_string(arr) + arr&.join("\n") + end + + def domain_strings_to_array(values) + values + .split(DOMAIN_LIST_SEPARATOR) + .reject(&:empty?) + .uniq + end + def ensure_uuid! return if uuid? diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index da70cb9a9a7..07813e03f3a 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -40,6 +40,7 @@ module Ci has_many :trace_chunks, class_name: 'Ci::BuildTraceChunk', foreign_key: :build_id has_many :job_artifacts, class_name: 'Ci::JobArtifact', foreign_key: :job_id, dependent: :destroy, inverse_of: :job # rubocop:disable Cop/ActiveRecordDependent + has_many :job_variables, class_name: 'Ci::JobVariable', foreign_key: :job_id Ci::JobArtifact.file_types.each do |key, value| has_one :"job_artifacts_#{key}", -> { where(file_type: value) }, class_name: 'Ci::JobArtifact', inverse_of: :job, foreign_key: :job_id @@ -48,6 +49,7 @@ module Ci has_one :runner_session, class_name: 'Ci::BuildRunnerSession', validate: true, inverse_of: :build accepts_nested_attributes_for :runner_session + accepts_nested_attributes_for :job_variables delegate :url, to: :runner_session, prefix: true, allow_nil: true delegate :terminal_specification, to: :runner_session, allow_nil: true @@ -331,10 +333,10 @@ module Ci end # rubocop: disable CodeReuse/ServiceClass - def play(current_user) + def play(current_user, job_variables_attributes = nil) Ci::PlayBuildService .new(project, current_user) - .execute(self) + .execute(self, job_variables_attributes) end # rubocop: enable CodeReuse/ServiceClass @@ -432,6 +434,7 @@ module Ci Gitlab::Ci::Variables::Collection.new .concat(persisted_variables) .concat(scoped_variables) + .concat(job_variables) .concat(persisted_environment_variables) .to_runner_variables end diff --git a/app/models/ci/job_variable.rb b/app/models/ci/job_variable.rb new file mode 100644 index 00000000000..862a0bc1299 --- /dev/null +++ b/app/models/ci/job_variable.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +module Ci + class JobVariable < ApplicationRecord + extend Gitlab::Ci::Model + include NewHasVariable + + belongs_to :job, class_name: "Ci::Build", foreign_key: :job_id + + alias_attribute :secret_value, :value + + validates :key, uniqueness: { scope: :job_id } + end +end diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index c2eb51ba100..1c76f401690 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -229,10 +229,12 @@ module Ci # # ref - The name (or names) of the branch(es)/tag(s) to limit the list of # pipelines to. + # sha - The commit SHA (or mutliple SHAs) to limit the list of pipelines to. # limit - This limits a backlog search, default to 100. - def self.newest_first(ref: nil, limit: 100) + def self.newest_first(ref: nil, sha: nil, limit: 100) relation = order(id: :desc) relation = relation.where(ref: ref) if ref + relation = relation.where(sha: sha) if sha if limit ids = relation.limit(limit).select(:id) @@ -246,10 +248,14 @@ module Ci newest_first(ref: ref).pluck(:status).first end - def self.latest_successful_for(ref) + def self.latest_successful_for_ref(ref) newest_first(ref: ref).success.take end + def self.latest_successful_for_sha(sha) + newest_first(sha: sha).success.take + end + def self.latest_successful_for_refs(refs) relation = newest_first(ref: refs).success diff --git a/app/models/commit.rb b/app/models/commit.rb index be37fa2e76f..0889ce7e287 100644 --- a/app/models/commit.rb +++ b/app/models/commit.rb @@ -346,7 +346,7 @@ class Commit if commits_in_merge_request.present? message_body << "" - commits_in_merge_request.reverse.each do |commit_in_merge| + commits_in_merge_request.reverse_each do |commit_in_merge| message_body << "#{commit_in_merge.short_id} #{commit_in_merge.title}" end end diff --git a/app/models/concerns/descendant.rb b/app/models/concerns/descendant.rb deleted file mode 100644 index 4c436522122..00000000000 --- a/app/models/concerns/descendant.rb +++ /dev/null @@ -1,11 +0,0 @@ -# frozen_string_literal: true - -module Descendant - extend ActiveSupport::Concern - - class_methods do - def supports_nested_objects? - Gitlab::Database.postgresql? - end - end -end diff --git a/app/models/concerns/new_has_variable.rb b/app/models/concerns/new_has_variable.rb new file mode 100644 index 00000000000..429bf496872 --- /dev/null +++ b/app/models/concerns/new_has_variable.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +module NewHasVariable + extend ActiveSupport::Concern + include HasVariable + + included do + attr_encrypted :value, + mode: :per_attribute_iv, + algorithm: 'aes-256-gcm', + key: Settings.attr_encrypted_db_key_base_32, + insecure_mode: false + end +end diff --git a/app/models/concerns/protected_ref.rb b/app/models/concerns/protected_ref.rb index af387c99f3d..0648b4a78e1 100644 --- a/app/models/concerns/protected_ref.rb +++ b/app/models/concerns/protected_ref.rb @@ -47,7 +47,7 @@ module ProtectedRef def access_levels_for_ref(ref, action:, protected_refs: nil) self.matching(ref, protected_refs: protected_refs) - .map(&:"#{action}_access_levels").flatten + .flat_map(&:"#{action}_access_levels") end # Returns all protected refs that match the given ref name. diff --git a/app/models/concerns/relative_positioning.rb b/app/models/concerns/relative_positioning.rb index e4fe46d722a..9cd7b8d6258 100644 --- a/app/models/concerns/relative_positioning.rb +++ b/app/models/concerns/relative_positioning.rb @@ -1,5 +1,26 @@ # frozen_string_literal: true +# This module makes it possible to handle items as a list, where the order of items can be easily altered +# Requirements: +# +# - Only works for ActiveRecord models +# - relative_position integer field must present on the model +# - This module uses GROUP BY: the model should have a parent relation, example: project -> issues, project is the parent relation (issues table has a parent_id column) +# +# Setup like this in the body of your class: +# +# include RelativePositioning +# +# # base query used for the position calculation +# def self.relative_positioning_query_base(issue) +# where(deleted: false) +# end +# +# # column that should be used in GROUP BY +# def self.relative_positioning_parent_column +# :project_id +# end +# module RelativePositioning extend ActiveSupport::Concern @@ -93,7 +114,7 @@ module RelativePositioning return move_after(before) unless after return move_before(after) unless before - # If there is no place to insert an issue we need to create one by moving the before issue closer + # If there is no place to insert an item we need to create one by moving the before item closer # to its predecessor. This process will recursively move all the predecessors until we have a place if (after.relative_position - before.relative_position) < 2 before.move_before @@ -108,11 +129,11 @@ module RelativePositioning pos_after = before.next_relative_position if before.shift_after? - issue_to_move = self.class.in_parents(parent_ids).find_by!(relative_position: pos_after) - issue_to_move.move_after - @positionable_neighbours = [issue_to_move] # rubocop:disable Gitlab/ModuleWithInstanceVariables + item_to_move = self.class.relative_positioning_query_base(self).find_by!(relative_position: pos_after) + item_to_move.move_after + @positionable_neighbours = [item_to_move] # rubocop:disable Gitlab/ModuleWithInstanceVariables - pos_after = issue_to_move.relative_position + pos_after = item_to_move.relative_position end self.relative_position = self.class.position_between(pos_before, pos_after) @@ -123,11 +144,11 @@ module RelativePositioning pos_before = after.prev_relative_position if after.shift_before? - issue_to_move = self.class.in_parents(parent_ids).find_by!(relative_position: pos_before) - issue_to_move.move_before - @positionable_neighbours = [issue_to_move] # rubocop:disable Gitlab/ModuleWithInstanceVariables + item_to_move = self.class.relative_positioning_query_base(self).find_by!(relative_position: pos_before) + item_to_move.move_before + @positionable_neighbours = [item_to_move] # rubocop:disable Gitlab/ModuleWithInstanceVariables - pos_before = issue_to_move.relative_position + pos_before = item_to_move.relative_position end self.relative_position = self.class.position_between(pos_before, pos_after) @@ -141,13 +162,13 @@ module RelativePositioning self.relative_position = self.class.position_between(min_relative_position || START_POSITION, MIN_POSITION) end - # Indicates if there is an issue that should be shifted to free the place + # Indicates if there is an item that should be shifted to free the place def shift_after? next_pos = next_relative_position next_pos && (next_pos - relative_position) == 1 end - # Indicates if there is an issue that should be shifted to free the place + # Indicates if there is an item that should be shifted to free the place def shift_before? prev_pos = prev_relative_position prev_pos && (relative_position - prev_pos) == 1 @@ -159,7 +180,7 @@ module RelativePositioning def save_positionable_neighbours return unless @positionable_neighbours - status = @positionable_neighbours.all? { |issue| issue.save(touch: false) } + status = @positionable_neighbours.all? { |item| item.save(touch: false) } @positionable_neighbours = nil status @@ -170,16 +191,15 @@ module RelativePositioning # When calculating across projects, this is much more efficient than # MAX(relative_position) without the GROUP BY, due to index usage: # https://gitlab.com/gitlab-org/gitlab-ce/issues/54276#note_119340977 - relation = self.class - .in_parents(parent_ids) + relation = self.class.relative_positioning_query_base(self) .order(Gitlab::Database.nulls_last_order('position', 'DESC')) + .group(self.class.relative_positioning_parent_column) .limit(1) - .group(self.class.parent_column) relation = yield relation if block_given? relation - .pluck(self.class.parent_column, Arel.sql("#{calculation}(relative_position) AS position")) + .pluck(self.class.relative_positioning_parent_column, Arel.sql("#{calculation}(relative_position) AS position")) .first&. last end diff --git a/app/models/container_repository.rb b/app/models/container_repository.rb index 39e12ac2b06..facd81dde80 100644 --- a/app/models/container_repository.rb +++ b/app/models/container_repository.rb @@ -86,4 +86,9 @@ class ContainerRepository < ApplicationRecord def self.build_root_repository(project) self.new(project: project, name: '') end + + def self.find_by_path!(path) + self.find_by!(project: path.repository_project, + name: path.repository_name) + end end diff --git a/app/models/deployment_metrics.rb b/app/models/deployment_metrics.rb index cfe762ca25e..2056c8bc59c 100644 --- a/app/models/deployment_metrics.rb +++ b/app/models/deployment_metrics.rb @@ -44,18 +44,7 @@ class DeploymentMetrics end end - # TODO remove fallback case to deployment_platform_cluster. - # Otherwise we will continue to pay the performance penalty described in - # https://gitlab.com/gitlab-org/gitlab-ce/issues/63475 - # - # Removal issue: https://gitlab.com/gitlab-org/gitlab-ce/issues/64105 def cluster_prometheus - cluster_with_fallback = cluster || deployment_platform_cluster - - cluster_with_fallback.application_prometheus if cluster_with_fallback&.application_prometheus_available? - end - - def deployment_platform_cluster - deployment.environment.deployment_platform&.cluster + cluster.application_prometheus if cluster&.application_prometheus_available? end end diff --git a/app/models/group.rb b/app/models/group.rb index 26ce2957e9b..74eb556b1b5 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -10,7 +10,6 @@ class Group < Namespace include Referable include SelectForProjectAuthorization include LoadedInGroupList - include Descendant include GroupDescendant include TokenAuthenticatable include WithUploads @@ -388,7 +387,7 @@ class Group < Namespace variables = Ci::GroupVariable.where(group: list_of_ids) variables = variables.unprotected unless project.protected_for?(ref) variables = variables.group_by(&:group_id) - list_of_ids.reverse.map { |group| variables[group.id] }.compact.flatten + list_of_ids.reverse.flat_map { |group| variables[group.id] }.compact end def group_member(user) diff --git a/app/models/issue.rb b/app/models/issue.rb index 8c5dd5e382e..164858dc432 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -91,11 +91,11 @@ class Issue < ApplicationRecord end end - class << self - alias_method :in_parents, :in_projects + def self.relative_positioning_query_base(issue) + in_projects(issue.parent_ids) end - def self.parent_column + def self.relative_positioning_parent_column :project_id end diff --git a/app/models/label.rb b/app/models/label.rb index b83e0862bab..25de26b8384 100644 --- a/app/models/label.rb +++ b/app/models/label.rb @@ -33,7 +33,7 @@ class Label < ApplicationRecord default_scope { order(title: :asc) } - scope :templates, -> { where(template: true) } + scope :templates, -> { where(template: true, type: [Label.name, nil]) } scope :with_title, ->(title) { where(title: title) } scope :with_lists_and_board, -> { joins(lists: :board).merge(List.movable) } scope :on_project_boards, ->(project_id) { with_lists_and_board.where(boards: { project_id: project_id }) } @@ -137,6 +137,10 @@ class Label < ApplicationRecord where(id: ids) end + def self.on_project_board?(project_id, label_id) + on_project_boards(project_id).where(id: label_id).exists? + end + def open_issues_count(user = nil) issues_count(user, state: 'opened') end diff --git a/app/models/members/group_member.rb b/app/models/members/group_member.rb index 4cba69069bb..f6b19317c50 100644 --- a/app/models/members/group_member.rb +++ b/app/models/members/group_member.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class GroupMember < Member + include FromUnion + SOURCE_TYPE = 'Namespace'.freeze belongs_to :group, foreign_key: 'source_id' diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 68e6e48fb7d..8ade91933a4 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -1249,15 +1249,8 @@ class MergeRequest < ApplicationRecord end def all_commits - # MySQL doesn't support LIMIT in a subquery. - diffs_relation = if Gitlab::Database.postgresql? - merge_request_diffs.recent - else - merge_request_diffs - end - MergeRequestDiffCommit - .where(merge_request_diff: diffs_relation) + .where(merge_request_diff: merge_request_diffs.recent) .limit(10_000) end diff --git a/app/models/milestone.rb b/app/models/milestone.rb index 37c129e843a..2ad2838111e 100644 --- a/app/models/milestone.rb +++ b/app/models/milestone.rb @@ -149,29 +149,10 @@ class Milestone < ApplicationRecord end def self.upcoming_ids(projects, groups) - rel = unscoped - .for_projects_and_groups(projects, groups) - .active.where('milestones.due_date > CURRENT_DATE') - - if Gitlab::Database.postgresql? - rel.order(:project_id, :group_id, :due_date).select('DISTINCT ON (project_id, group_id) id') - else - # We need to use MySQL's NULL-safe comparison operator `<=>` here - # because one of `project_id` or `group_id` is always NULL - join_clause = <<~HEREDOC - LEFT OUTER JOIN milestones earlier_milestones - ON milestones.project_id <=> earlier_milestones.project_id - AND milestones.group_id <=> earlier_milestones.group_id - AND milestones.due_date > earlier_milestones.due_date - AND earlier_milestones.due_date > CURRENT_DATE - AND earlier_milestones.state = 'active' - HEREDOC - - rel - .joins(join_clause) - .where('earlier_milestones.id IS NULL') - .select(:id) - end + unscoped + .for_projects_and_groups(projects, groups) + .active.where('milestones.due_date > CURRENT_DATE') + .order(:project_id, :group_id, :due_date).select('DISTINCT ON (project_id, group_id) id') end def participants diff --git a/app/models/namespace.rb b/app/models/namespace.rb index b8d7348268a..058350b16ce 100644 --- a/app/models/namespace.rb +++ b/app/models/namespace.rb @@ -332,8 +332,6 @@ class Namespace < ApplicationRecord end def force_share_with_group_lock_on_descendants - return unless Group.supports_nested_objects? - # We can't use `descendants.update_all` since Rails will throw away the WITH # RECURSIVE statement. We also can't use WHERE EXISTS since we can't use # different table aliases, hence we're just using WHERE IN. Since we have a diff --git a/app/models/note.rb b/app/models/note.rb index 5c31cff9816..3f182c1f099 100644 --- a/app/models/note.rb +++ b/app/models/note.rb @@ -292,7 +292,7 @@ class Note < ApplicationRecord end def special_role=(role) - raise "Role is undefined, #{role} not found in #{SpecialRole.values}" unless SpecialRole.values.include?(role) + raise "Role is undefined, #{role} not found in #{SpecialRole.values}" unless SpecialRole.value?(role) @special_role = role end diff --git a/app/models/project.rb b/app/models/project.rb index 8030c645e2e..cca7da8c49a 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -719,16 +719,27 @@ class Project < ApplicationRecord repository.commits_by(oids: oids) end - # ref can't be HEAD, can only be branch/tag name or SHA - def latest_successful_build_for(job_name, ref = default_branch) - latest_pipeline = ci_pipelines.latest_successful_for(ref) + # ref can't be HEAD, can only be branch/tag name + def latest_successful_build_for_ref(job_name, ref = default_branch) + return unless ref + + latest_pipeline = ci_pipelines.latest_successful_for_ref(ref) return unless latest_pipeline latest_pipeline.builds.latest.with_artifacts_archive.find_by(name: job_name) end - def latest_successful_build_for!(job_name, ref = default_branch) - latest_successful_build_for(job_name, ref) || raise(ActiveRecord::RecordNotFound.new("Couldn't find job #{job_name}")) + def latest_successful_build_for_sha(job_name, sha) + return unless sha + + latest_pipeline = ci_pipelines.latest_successful_for_sha(sha) + return unless latest_pipeline + + latest_pipeline.builds.latest.with_artifacts_archive.find_by(name: job_name) + end + + def latest_successful_build_for_ref!(job_name, ref = default_branch) + latest_successful_build_for_ref(job_name, ref) || raise(ActiveRecord::RecordNotFound.new("Couldn't find job #{job_name}")) end def merge_base_commit(first_commit_id, second_commit_id) @@ -1503,12 +1514,12 @@ class Project < ApplicationRecord end @latest_successful_pipeline_for_default_branch = - ci_pipelines.latest_successful_for(default_branch) + ci_pipelines.latest_successful_for_ref(default_branch) end def latest_successful_pipeline_for(ref = nil) if ref && ref != default_branch - ci_pipelines.latest_successful_for(ref) + ci_pipelines.latest_successful_for_ref(ref) else latest_successful_pipeline_for_default_branch end @@ -1862,16 +1873,24 @@ class Project < ApplicationRecord end def append_or_update_attribute(name, value) - old_values = public_send(name.to_s) # rubocop:disable GitlabSecurity/PublicSend + if Project.reflect_on_association(name).try(:macro) == :has_many + # if this is 1-to-N relation, update the parent object + value.each do |item| + item.update!( + Project.reflect_on_association(name).foreign_key => id) + end - if Project.reflect_on_association(name).try(:macro) == :has_many && old_values.any? - update_attribute(name, old_values + value) + # force to drop relation cache + public_send(name).reset # rubocop:disable GitlabSecurity/PublicSend + + # succeeded + true else + # if this is another relation or attribute, update just object update_attribute(name, value) end - - rescue ActiveRecord::RecordNotSaved => e - handle_update_attribute_error(e, value) + rescue ActiveRecord::RecordInvalid => e + raise e, "Failed to set #{name}: #{e.message}" end # Tries to set repository as read_only, checking for existing Git transfers in progress beforehand @@ -2260,18 +2279,6 @@ class Project < ApplicationRecord ContainerRepository.build_root_repository(self).has_tags? end - def handle_update_attribute_error(ex, value) - if ex.message.start_with?('Failed to replace') - if value.respond_to?(:each) - invalid = value.detect(&:invalid?) - - raise ex, ([ex.message] + invalid.errors.full_messages).join(' ') if invalid - end - end - - raise ex - end - def fetch_branch_allows_collaboration(user, branch_name = nil) return false unless user diff --git a/app/models/project_auto_devops.rb b/app/models/project_auto_devops.rb index f39f54f0434..e11d0c48b4b 100644 --- a/app/models/project_auto_devops.rb +++ b/app/models/project_auto_devops.rb @@ -1,10 +1,6 @@ # frozen_string_literal: true class ProjectAutoDevops < ApplicationRecord - include IgnorableColumn - - ignore_column :domain - belongs_to :project, inverse_of: :auto_devops enum deploy_strategy: { diff --git a/app/models/project_services/chat_message/pipeline_message.rb b/app/models/project_services/chat_message/pipeline_message.rb index 62aec4351db..4edf263433f 100644 --- a/app/models/project_services/chat_message/pipeline_message.rb +++ b/app/models/project_services/chat_message/pipeline_message.rb @@ -1,24 +1,47 @@ # frozen_string_literal: true +require 'slack-notifier' module ChatMessage class PipelineMessage < BaseMessage + MAX_VISIBLE_JOBS = 10 + + attr_reader :user attr_reader :ref_type attr_reader :ref attr_reader :status + attr_reader :detailed_status attr_reader :duration + attr_reader :finished_at attr_reader :pipeline_id + attr_reader :failed_stages + attr_reader :failed_jobs + + attr_reader :project + attr_reader :commit + attr_reader :committer + attr_reader :pipeline def initialize(data) super + @user = data[:user] @user_name = data.dig(:user, :username) || 'API' pipeline_attributes = data[:object_attributes] @ref_type = pipeline_attributes[:tag] ? 'tag' : 'branch' @ref = pipeline_attributes[:ref] @status = pipeline_attributes[:status] + @detailed_status = pipeline_attributes[:detailed_status] @duration = pipeline_attributes[:duration].to_i + @finished_at = pipeline_attributes[:finished_at] ? Time.parse(pipeline_attributes[:finished_at]).to_i : nil @pipeline_id = pipeline_attributes[:id] + @failed_jobs = Array(data[:builds]).select { |b| b[:status] == 'failed' }.reverse # Show failed jobs from oldest to newest + @failed_stages = @failed_jobs.map { |j| j[:stage] }.uniq + + @project = Project.find(data[:project][:id]) + @commit = project.commit_by(oid: data[:commit][:id]) + @committer = commit.committer + @pipeline = Ci::Pipeline.find(pipeline_id) end def pretext @@ -28,38 +51,145 @@ module ChatMessage def attachments return message if markdown - [{ text: format(message), color: attachment_color }] + return [{ text: format(message), color: attachment_color }] unless fancy_notifications? + + [{ + fallback: format(message), + color: attachment_color, + author_name: user_combined_name, + author_icon: user_avatar, + author_link: author_url, + title: s_("ChatMessage|Pipeline #%{pipeline_id} %{humanized_status} in %{duration}") % + { + pipeline_id: pipeline_id, + humanized_status: humanized_status, + duration: pretty_duration(duration) + }, + title_link: pipeline_url, + fields: attachments_fields, + footer: project.name, + footer_icon: project.avatar_url, + ts: finished_at + }] end def activity { - title: "Pipeline #{pipeline_link} of #{ref_type} #{branch_link} by #{user_combined_name} #{humanized_status}", - subtitle: "in #{project_link}", - text: "in #{pretty_duration(duration)}", + title: s_("ChatMessage|Pipeline %{pipeline_link} of %{ref_type} %{branch_link} by %{user_combined_name} %{humanized_status}") % + { + pipeline_link: pipeline_link, + ref_type: ref_type, + branch_link: branch_link, + user_combined_name: user_combined_name, + humanized_status: humanized_status + }, + subtitle: s_("ChatMessage|in %{project_link}") % { project_link: project_link }, + text: s_("ChatMessage|in %{duration}") % { duration: pretty_duration(duration) }, image: user_avatar || '' } end private + def fancy_notifications? + Feature.enabled?(:fancy_pipeline_slack_notifications, default_enabled: true) + end + + def failed_stages_field + { + title: s_("ChatMessage|Failed stage").pluralize(failed_stages.length), + value: Slack::Notifier::LinkFormatter.format(failed_stages_links), + short: true + } + end + + def failed_jobs_field + { + title: s_("ChatMessage|Failed job").pluralize(failed_jobs.length), + value: Slack::Notifier::LinkFormatter.format(failed_jobs_links), + short: true + } + end + + def yaml_error_field + { + title: s_("ChatMessage|Invalid CI config YAML file"), + value: pipeline.yaml_errors, + short: false + } + end + + def attachments_fields + fields = [ + { + title: ref_type == "tag" ? s_("ChatMessage|Tag") : s_("ChatMessage|Branch"), + value: Slack::Notifier::LinkFormatter.format(ref_name_link), + short: true + }, + { + title: s_("ChatMessage|Commit"), + value: Slack::Notifier::LinkFormatter.format(commit_link), + short: true + } + ] + + fields << failed_stages_field if failed_stages.any? + fields << failed_jobs_field if failed_jobs.any? + fields << yaml_error_field if pipeline.has_yaml_errors? + + fields + end + def message - "#{project_link}: Pipeline #{pipeline_link} of #{ref_type} #{branch_link} by #{user_combined_name} #{humanized_status} in #{pretty_duration(duration)}" + s_("ChatMessage|%{project_link}: Pipeline %{pipeline_link} of %{ref_type} %{branch_link} by %{user_combined_name} %{humanized_status} in %{duration}") % + { + project_link: project_link, + pipeline_link: pipeline_link, + ref_type: ref_type, + branch_link: branch_link, + user_combined_name: user_combined_name, + humanized_status: humanized_status, + duration: pretty_duration(duration) + } end def humanized_status - case status - when 'success' - 'passed' + if fancy_notifications? + case status + when 'success' + detailed_status == "passed with warnings" ? s_("ChatMessage|has passed with warnings") : s_("ChatMessage|has passed") + when 'failed' + s_("ChatMessage|has failed") + else + status + end else - status + case status + when 'success' + s_("ChatMessage|passed") + when 'failed' + s_("ChatMessage|failed") + else + status + end end end def attachment_color - if status == 'success' - 'good' + if fancy_notifications? + case status + when 'success' + detailed_status == 'passed with warnings' ? 'warning' : 'good' + else + 'danger' + end else - 'danger' + case status + when 'success' + 'good' + else + 'danger' + end end end @@ -71,16 +201,83 @@ module ChatMessage "[#{ref}](#{branch_url})" end + def project_url + project.web_url + end + def project_link - "[#{project_name}](#{project_url})" + "[#{project.name}](#{project_url})" + end + + def pipeline_failed_jobs_url + "#{project_url}/pipelines/#{pipeline_id}/failures" end def pipeline_url - "#{project_url}/pipelines/#{pipeline_id}" + if fancy_notifications? && failed_jobs.any? + pipeline_failed_jobs_url + else + "#{project_url}/pipelines/#{pipeline_id}" + end end def pipeline_link "[##{pipeline_id}](#{pipeline_url})" end + + def job_url(job) + "#{project_url}/-/jobs/#{job[:id]}" + end + + def job_link(job) + "[#{job[:name]}](#{job_url(job)})" + end + + def failed_jobs_links + failed = failed_jobs.slice(0, MAX_VISIBLE_JOBS) + truncated = failed_jobs.slice(MAX_VISIBLE_JOBS, failed_jobs.size) + + failed_links = failed.map { |job| job_link(job) } + + unless truncated.blank? + failed_links << s_("ChatMessage|and [%{count} more](%{pipeline_failed_jobs_url})") % { + count: truncated.size, + pipeline_failed_jobs_url: pipeline_failed_jobs_url + } + end + + failed_links.join(I18n.translate(:'support.array.words_connector')) + end + + def stage_link(stage) + # All stages link to the pipeline page + "[#{stage}](#{pipeline_url})" + end + + def failed_stages_links + failed_stages.map { |s| stage_link(s) }.join(I18n.translate(:'support.array.words_connector')) + end + + def commit_url + Gitlab::UrlBuilder.build(commit) + end + + def commit_link + "[#{commit.title}](#{commit_url})" + end + + def commits_page_url + "#{project_url}/commits/#{ref}" + end + + def ref_name_link + "[#{ref}](#{commits_page_url})" + end + + def author_url + return unless user && committer + + Gitlab::UrlBuilder.build(committer) + end end end diff --git a/app/models/project_services/jira_service.rb b/app/models/project_services/jira_service.rb index 7ab79242cc3..d08fcd8954d 100644 --- a/app/models/project_services/jira_service.rb +++ b/app/models/project_services/jira_service.rb @@ -31,7 +31,7 @@ class JiraService < IssueTrackerService # {PROJECT-KEY}-{NUMBER} Examples: JIRA-1, PROJECT-1 def self.reference_pattern(only_long: true) - @reference_pattern ||= /(?<issue>\b([A-Z][A-Z0-9_]+-)\d+)/ + @reference_pattern ||= /(?<issue>\b#{Gitlab::Regex.jira_issue_key_regex})/ end def initialize_properties diff --git a/app/models/redirect_route.rb b/app/models/redirect_route.rb index 2e4769364c6..22f60802257 100644 --- a/app/models/redirect_route.rb +++ b/app/models/redirect_route.rb @@ -11,11 +11,7 @@ class RedirectRoute < ApplicationRecord uniqueness: { case_sensitive: false } scope :matching_path_and_descendants, -> (path) do - wheres = if Gitlab::Database.postgresql? - 'LOWER(redirect_routes.path) = LOWER(?) OR LOWER(redirect_routes.path) LIKE LOWER(?)' - else - 'redirect_routes.path = ? OR redirect_routes.path LIKE ?' - end + wheres = 'LOWER(redirect_routes.path) = LOWER(?) OR LOWER(redirect_routes.path) LIKE LOWER(?)' where(wheres, path, "#{sanitize_sql_like(path)}/%") end diff --git a/app/models/repository.rb b/app/models/repository.rb index 187382ad182..a89f573e3d6 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -7,6 +7,9 @@ class Repository REF_KEEP_AROUND = 'keep-around'.freeze REF_ENVIRONMENTS = 'environments'.freeze + ARCHIVE_CACHE_TIME = 60 # Cache archives referred to by a (mutable) ref for 1 minute + ARCHIVE_CACHE_TIME_IMMUTABLE = 3600 # Cache archives referred to by an immutable reference for 1 hour + RESERVED_REFS_NAMES = %W[ heads tags diff --git a/app/models/system_note_metadata.rb b/app/models/system_note_metadata.rb index 55da37c9545..9a2640db9ca 100644 --- a/app/models/system_note_metadata.rb +++ b/app/models/system_note_metadata.rb @@ -16,7 +16,7 @@ class SystemNoteMetadata < ApplicationRecord 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 due_date + outdated tag due_date pinned_embed ].freeze validates :note, presence: true diff --git a/app/models/user_preference.rb b/app/models/user_preference.rb index f1326f4c8cb..b236250c24e 100644 --- a/app/models/user_preference.rb +++ b/app/models/user_preference.rb @@ -26,7 +26,7 @@ class UserPreference < ApplicationRecord def set_notes_filter(filter_id, issuable) # No need to update the column if the value is already set. - if filter_id && NOTES_FILTERS.values.include?(filter_id) + if filter_id && NOTES_FILTERS.value?(filter_id) field = notes_filter_field_for(issuable) self[field] = filter_id diff --git a/app/policies/group_policy.rb b/app/policies/group_policy.rb index 0add8bfad31..84b1873c05d 100644 --- a/app/policies/group_policy.rb +++ b/app/policies/group_policy.rb @@ -16,8 +16,6 @@ class GroupPolicy < BasePolicy condition(:maintainer) { access_level >= GroupMember::MAINTAINER } condition(:reporter) { access_level >= GroupMember::REPORTER } - condition(:nested_groups_supported, scope: :global) { Group.supports_nested_objects? } - condition(:has_parent, scope: :subject) { @subject.has_parent? } condition(:share_with_group_locked, scope: :subject) { @subject.share_with_group_lock? } condition(:parent_share_with_group_locked, scope: :subject) { @subject.parent&.share_with_group_lock? } @@ -108,8 +106,8 @@ class GroupPolicy < BasePolicy enable :read_nested_project_resources end - rule { owner & nested_groups_supported }.enable :create_subgroup - rule { maintainer & maintainer_can_create_group & nested_groups_supported }.enable :create_subgroup + rule { owner }.enable :create_subgroup + rule { maintainer & maintainer_can_create_group }.enable :create_subgroup rule { public_group | logged_in_viewable }.enable :view_globally diff --git a/app/serializers/issue_entity.rb b/app/serializers/issue_entity.rb index 36e601f45c5..82139855760 100644 --- a/app/serializers/issue_entity.rb +++ b/app/serializers/issue_entity.rb @@ -16,9 +16,14 @@ class IssueEntity < IssuableEntity expose :discussion_locked expose :assignees, using: API::Entities::UserBasic expose :due_date - expose :moved_to_id expose :project_id + expose :moved_to_id do |issue| + if issue.moved_to_id.present? && can?(request.current_user, :read_issue, issue.moved_to) + issue.moved_to_id + end + end + expose :web_url do |issue| project_issue_path(issue.project, issue) end diff --git a/app/serializers/stage_entity.rb b/app/serializers/stage_entity.rb index 029dd3d0684..0b0454c5282 100644 --- a/app/serializers/stage_entity.rb +++ b/app/serializers/stage_entity.rb @@ -59,14 +59,14 @@ class StageEntity < Grape::Entity end def latest_statuses - HasStatus::ORDERED_STATUSES.map do |ordered_status| + HasStatus::ORDERED_STATUSES.flat_map do |ordered_status| grouped_statuses.fetch(ordered_status, []) - end.flatten + end end def retried_statuses - HasStatus::ORDERED_STATUSES.map do |ordered_status| + HasStatus::ORDERED_STATUSES.flat_map do |ordered_status| grouped_retried_statuses.fetch(ordered_status, []) - end.flatten + end end end diff --git a/app/services/ci/play_build_service.rb b/app/services/ci/play_build_service.rb index eb0b070657d..9f922ffde81 100644 --- a/app/services/ci/play_build_service.rb +++ b/app/services/ci/play_build_service.rb @@ -2,7 +2,7 @@ module Ci class PlayBuildService < ::BaseService - def execute(build) + def execute(build, job_variables_attributes = nil) unless can?(current_user, :update_build, build) raise Gitlab::Access::AccessDeniedError end @@ -10,7 +10,7 @@ module Ci # Try to enqueue the build, otherwise create a duplicate. # if build.enqueue - build.tap { |action| action.update(user: current_user) } + build.tap { |action| action.update(user: current_user, job_variables_attributes: job_variables_attributes || []) } else Ci::Build.retry(build, current_user) end diff --git a/app/services/ci/process_pipeline_service.rb b/app/services/ci/process_pipeline_service.rb index aaf56048b5c..207cc5017d0 100644 --- a/app/services/ci/process_pipeline_service.rb +++ b/app/services/ci/process_pipeline_service.rb @@ -10,13 +10,13 @@ module Ci update_retried new_builds = - stage_indexes_of_created_processables.map do |index| + stage_indexes_of_created_processables.flat_map do |index| process_stage(index) end @pipeline.update_status - new_builds.flatten.any? + new_builds.any? end private diff --git a/app/services/clusters/refresh_service.rb b/app/services/clusters/refresh_service.rb deleted file mode 100644 index 3752a306793..00000000000 --- a/app/services/clusters/refresh_service.rb +++ /dev/null @@ -1,40 +0,0 @@ -# frozen_string_literal: true - -module Clusters - class RefreshService - def self.create_or_update_namespaces_for_cluster(cluster) - projects_with_missing_kubernetes_namespaces_for_cluster(cluster).each do |project| - create_or_update_namespace(cluster, project) - end - end - - def self.create_or_update_namespaces_for_project(project) - clusters_with_missing_kubernetes_namespaces_for_project(project).each do |cluster| - create_or_update_namespace(cluster, project) - end - end - - def self.projects_with_missing_kubernetes_namespaces_for_cluster(cluster) - cluster.all_projects.missing_kubernetes_namespace(cluster.kubernetes_namespaces) - end - - private_class_method :projects_with_missing_kubernetes_namespaces_for_cluster - - def self.clusters_with_missing_kubernetes_namespaces_for_project(project) - project.clusters.managed.missing_kubernetes_namespace(project.kubernetes_namespaces) - end - - private_class_method :clusters_with_missing_kubernetes_namespaces_for_project - - def self.create_or_update_namespace(cluster, project) - kubernetes_namespace = cluster.find_or_initialize_kubernetes_namespace_for_project(project) - - ::Clusters::Gcp::Kubernetes::CreateOrUpdateNamespaceService.new( - cluster: cluster, - kubernetes_namespace: kubernetes_namespace - ).execute - end - - private_class_method :create_or_update_namespace - end -end diff --git a/app/services/cohorts_service.rb b/app/services/cohorts_service.rb index 6d466c2fc9c..97fbb70f350 100644 --- a/app/services/cohorts_service.rb +++ b/app/services/cohorts_service.rb @@ -95,10 +95,6 @@ class CohortsService # rubocop: enable CodeReuse/ActiveRecord def column_to_date(column) - if Gitlab::Database.postgresql? - "CAST(DATE_TRUNC('month', #{column}) AS date)" - else - "STR_TO_DATE(DATE_FORMAT(#{column}, '%Y-%m-01'), '%Y-%m-%d')" - end + "CAST(DATE_TRUNC('month', #{column}) AS date)" end end diff --git a/app/services/groups/nested_create_service.rb b/app/services/groups/nested_create_service.rb index 01bd685712b..a51ac9aa593 100644 --- a/app/services/groups/nested_create_service.rb +++ b/app/services/groups/nested_create_service.rb @@ -18,10 +18,6 @@ module Groups return namespace end - if group_path.include?('/') && !Group.supports_nested_objects? - raise 'Nested groups are not supported on MySQL' - end - create_group_path end diff --git a/app/services/groups/transfer_service.rb b/app/services/groups/transfer_service.rb index 98e7c311572..fe7e07ef9f0 100644 --- a/app/services/groups/transfer_service.rb +++ b/app/services/groups/transfer_service.rb @@ -43,7 +43,6 @@ module Groups def ensure_allowed_transfer raise_transfer_error(:group_is_already_root) if group_is_already_root? - raise_transfer_error(:database_not_supported) unless Group.supports_nested_objects? raise_transfer_error(:same_parent_as_current) if same_parent? raise_transfer_error(:invalid_policies) unless valid_policies? raise_transfer_error(:namespace_with_same_path) if namespace_with_same_path? diff --git a/app/services/issuable_base_service.rb b/app/services/issuable_base_service.rb index db673cace81..77c2224ee3b 100644 --- a/app/services/issuable_base_service.rb +++ b/app/services/issuable_base_service.rb @@ -358,6 +358,7 @@ class IssuableBaseService < BaseService assignees: issuable.assignees.to_a } associations[:total_time_spent] = issuable.total_time_spent if issuable.respond_to?(:total_time_spent) + associations[:description] = issuable.description associations end diff --git a/app/services/issues/update_service.rb b/app/services/issues/update_service.rb index 7cd825aa967..c8f4412c9f2 100644 --- a/app/services/issues/update_service.rb +++ b/app/services/issues/update_service.rb @@ -61,6 +61,8 @@ module Issues if added_mentions.present? notification_service.async.new_mentions_in_issue(issue, added_mentions, current_user) end + + ZoomNotesService.new(issue, project, current_user, old_description: old_associations[:description]).execute end def handle_task_changes(issuable) diff --git a/app/services/members/destroy_service.rb b/app/services/members/destroy_service.rb index c8d5e563cd8..0164760920f 100644 --- a/app/services/members/destroy_service.rb +++ b/app/services/members/destroy_service.rb @@ -31,7 +31,7 @@ module Members return unless member.is_a?(GroupMember) && member.user && member.group delete_project_members(member) - delete_subgroup_members(member) if Group.supports_nested_objects? + delete_subgroup_members(member) end def delete_project_members(member) diff --git a/app/services/merge_requests/build_service.rb b/app/services/merge_requests/build_service.rb index 109c964e577..b28f80939ae 100644 --- a/app/services/merge_requests/build_service.rb +++ b/app/services/merge_requests/build_service.rb @@ -11,15 +11,18 @@ module MergeRequests # https://gitlab.com/gitlab-org/gitlab-ce/issues/53658 merge_quick_actions_into_params!(merge_request, only: [:target_branch]) merge_request.merge_params['force_remove_source_branch'] = params.delete(:force_remove_source_branch) if params.has_key?(:force_remove_source_branch) - merge_request.assign_attributes(params) + # Assign the projects first so we can use policies for `filter_params` merge_request.author = current_user + merge_request.source_project = find_source_project + merge_request.target_project = find_target_project + + filter_params(merge_request) + merge_request.assign_attributes(params.to_h.compact) + merge_request.compare_commits = [] - merge_request.source_project = find_source_project - merge_request.target_project = find_target_project - merge_request.target_branch = find_target_branch - merge_request.can_be_created = projects_and_branches_valid? - ensure_milestone_available(merge_request) + merge_request.target_branch = find_target_branch + merge_request.can_be_created = projects_and_branches_valid? # compare branches only if branches are valid, otherwise # compare_branches may raise an error @@ -50,12 +53,14 @@ module MergeRequests to: :merge_request def find_source_project + source_project = project_from_params(:source_project) return source_project if source_project.present? && can?(current_user, :create_merge_request_from, source_project) project end def find_target_project + target_project = project_from_params(:target_project) return target_project if target_project.present? && can?(current_user, :create_merge_request_in, target_project) target_project = project.default_merge_request_target @@ -65,6 +70,17 @@ module MergeRequests project end + def project_from_params(param_name) + project_from_params = params.delete(param_name) + + id_param_name = :"#{param_name}_id" + if project_from_params.nil? && params[id_param_name] + project_from_params = Project.find_by_id(params.delete(id_param_name)) + end + + project_from_params + end + def find_target_branch target_branch || target_project.default_branch end diff --git a/app/services/merge_requests/push_options_handler_service.rb b/app/services/merge_requests/push_options_handler_service.rb index 6d70b5106c7..b210004e6e1 100644 --- a/app/services/merge_requests/push_options_handler_service.rb +++ b/app/services/merge_requests/push_options_handler_service.rb @@ -118,7 +118,14 @@ module MergeRequests end def base_params - params = {} + params = { + title: push_options[:title], + description: push_options[:description], + target_branch: push_options[:target], + force_remove_source_branch: push_options[:remove_source_branch] + } + + params.compact! if push_options.key?(:merge_when_pipeline_succeeds) params.merge!( @@ -127,14 +134,6 @@ module MergeRequests ) end - if push_options.key?(:remove_source_branch) - params[:force_remove_source_branch] = push_options[:remove_source_branch] - end - - if push_options.key?(:target) - params[:target_branch] = push_options[:target] - end - params end diff --git a/app/services/metrics/dashboard/base_service.rb b/app/services/metrics/dashboard/base_service.rb new file mode 100644 index 00000000000..b331bf51874 --- /dev/null +++ b/app/services/metrics/dashboard/base_service.rb @@ -0,0 +1,70 @@ +# frozen_string_literal: true + +# Searches a projects repository for a metrics dashboard and formats the output. +# Expects any custom dashboards will be located in `.gitlab/dashboards` +module Metrics + module Dashboard + class BaseService < ::BaseService + PROCESSING_ERROR = Gitlab::Metrics::Dashboard::Stages::BaseStage::DashboardProcessingError + NOT_FOUND_ERROR = Gitlab::Template::Finders::RepoTemplateFinder::FileNotFoundError + + def get_dashboard + return error('Insufficient permissions.', :unauthorized) unless allowed? + + success(dashboard: process_dashboard) + rescue NOT_FOUND_ERROR + error("#{dashboard_path} could not be found.", :not_found) + rescue PROCESSING_ERROR => e + error(e.message, :unprocessable_entity) + end + + # Summary of all known dashboards for the service. + # @return [Array<Hash>] ex) [{ path: String, default: Boolean }] + def self.all_dashboard_paths(_project) + raise NotImplementedError + end + + # Returns an un-processed dashboard from the cache. + def raw_dashboard + Gitlab::Metrics::Dashboard::Cache.fetch(cache_key) { get_raw_dashboard } + end + + private + + # Determines whether users should be able to view + # dashboards at all. + def allowed? + Ability.allowed?(current_user, :read_environment, project) + end + + # Returns a new dashboard Hash, supplemented with DB info + def process_dashboard + Gitlab::Metrics::Dashboard::Processor + .new(project, params[:environment], raw_dashboard) + .process(insert_project_metrics: insert_project_metrics?) + end + + # @return [String] Relative filepath of the dashboard yml + def dashboard_path + params[:dashboard_path] + end + + # @return [Hash] an unmodified dashboard + def get_raw_dashboard + raise NotImplementedError + end + + # @return [String] + def cache_key + raise NotImplementedError + end + + # Determines whether custom metrics should be included + # in the processed output. + # @return [Boolean] + def insert_project_metrics? + false + end + end + end +end diff --git a/app/services/metrics/dashboard/default_embed_service.rb b/app/services/metrics/dashboard/default_embed_service.rb new file mode 100644 index 00000000000..0967c5bcfeb --- /dev/null +++ b/app/services/metrics/dashboard/default_embed_service.rb @@ -0,0 +1,63 @@ +# frozen_string_literal: true + +# Responsible for returning a filtered system dashboard +# containing only the default embedded metrics. In future, +# this class may be updated to support filtering to +# alternate metrics/panels. +# +# Why isn't this filtering in a processing stage? By filtering +# here, we ensure the dynamically-determined dashboard is cached. +# +# Use Gitlab::Metrics::Dashboard::Finder to retrive dashboards. +module Metrics + module Dashboard + class DefaultEmbedService < ::Metrics::Dashboard::BaseService + # For the default filtering for embedded metrics, + # uses the 'id' key in dashboard-yml definition for + # identification. + DEFAULT_EMBEDDED_METRICS_IDENTIFIERS = %w( + system_metrics_kubernetes_container_memory_total + system_metrics_kubernetes_container_cores_total + ).freeze + + # Returns a new dashboard with only the matching + # metrics from the system dashboard, stripped of groups. + # @return [Hash] + def raw_dashboard + panels = panel_groups.each_with_object([]) do |group, panels| + matched_panels = group['panels'].select { |panel| matching_panel?(panel) } + + panels.concat(matched_panels) + end + + { 'panel_groups' => [{ 'panels' => panels }] } + end + + def cache_key + "dynamic_metrics_dashboard_#{metric_identifiers.join('_')}" + end + + private + + # Returns an array of the panels groups on the + # system dashboard + def panel_groups + ::Metrics::Dashboard::SystemDashboardService + .new(project, nil) + .raw_dashboard['panel_groups'] + end + + # Identifies a panel as "matching" if any metric ids in + # the panel is in the list of identifiers to collect. + def matching_panel?(panel) + panel['metrics'].any? do |metric| + metric_identifiers.include?(metric['id']) + end + end + + def metric_identifiers + DEFAULT_EMBEDDED_METRICS_IDENTIFIERS + end + end + end +end diff --git a/app/services/metrics/dashboard/project_dashboard_service.rb b/app/services/metrics/dashboard/project_dashboard_service.rb new file mode 100644 index 00000000000..756d387c0e6 --- /dev/null +++ b/app/services/metrics/dashboard/project_dashboard_service.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +# Searches a projects repository for a metrics dashboard and formats the output. +# Expects any custom dashboards will be located in `.gitlab/dashboards` +# Use Gitlab::Metrics::Dashboard::Finder to retrive dashboards. +module Metrics + module Dashboard + class ProjectDashboardService < ::Metrics::Dashboard::BaseService + DASHBOARD_ROOT = ".gitlab/dashboards" + + class << self + def all_dashboard_paths(project) + file_finder(project) + .list_files_for(DASHBOARD_ROOT) + .map do |filepath| + { + path: filepath, + display_name: name_for_path(filepath), + default: false + } + end + end + + def file_finder(project) + Gitlab::Template::Finders::RepoTemplateFinder.new(project, DASHBOARD_ROOT, '.yml') + end + + # Grabs the filepath after the base directory. + def name_for_path(filepath) + filepath.delete_prefix("#{DASHBOARD_ROOT}/") + end + end + + private + + # Searches the project repo for a custom-defined dashboard. + def get_raw_dashboard + yml = self.class.file_finder(project).read(dashboard_path) + + YAML.safe_load(yml) + end + + def cache_key + "project_#{project.id}_metrics_dashboard_#{dashboard_path}" + end + end + end +end diff --git a/app/services/metrics/dashboard/system_dashboard_service.rb b/app/services/metrics/dashboard/system_dashboard_service.rb new file mode 100644 index 00000000000..fcd71aadb03 --- /dev/null +++ b/app/services/metrics/dashboard/system_dashboard_service.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +# Fetches the system metrics dashboard and formats the output. +# Use Gitlab::Metrics::Dashboard::Finder to retrive dashboards. +module Metrics + module Dashboard + class SystemDashboardService < ::Metrics::Dashboard::BaseService + SYSTEM_DASHBOARD_PATH = 'config/prometheus/common_metrics.yml' + SYSTEM_DASHBOARD_NAME = 'Default' + + class << self + def all_dashboard_paths(_project) + [{ + path: SYSTEM_DASHBOARD_PATH, + display_name: SYSTEM_DASHBOARD_NAME, + default: true + }] + end + + def system_dashboard?(filepath) + filepath == SYSTEM_DASHBOARD_PATH + end + end + + private + + def dashboard_path + SYSTEM_DASHBOARD_PATH + end + + # Returns the base metrics shipped with every GitLab service. + def get_raw_dashboard + yml = File.read(Rails.root.join(dashboard_path)) + + YAML.safe_load(yml) + end + + def cache_key + "metrics_dashboard_#{dashboard_path}" + end + + def insert_project_metrics? + true + end + end + end +end diff --git a/app/services/notes/create_service.rb b/app/services/notes/create_service.rb index 1b46f6d8a72..194c4a43dbc 100644 --- a/app/services/notes/create_service.rb +++ b/app/services/notes/create_service.rb @@ -21,7 +21,7 @@ module Notes if quick_actions_service.supported?(note) options = { merge_request_diff_head_sha: merge_request_diff_head_sha } - content, update_params = quick_actions_service.execute(note, options) + content, update_params, message = quick_actions_service.execute(note, options) only_commands = content.empty? @@ -52,7 +52,7 @@ module Notes # We must add the error after we call #save because errors are reset # when #save is called if only_commands - note.errors.add(:commands_only, 'Commands applied') + note.errors.add(:commands_only, message.presence || _('Commands did not apply')) end end diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb index a55771ed538..21fab22e0d4 100644 --- a/app/services/notification_service.rb +++ b/app/services/notification_service.rb @@ -595,7 +595,7 @@ class NotificationService end def deliver_access_request_email(recipient, member) - mailer.member_access_requested_email(member.real_source_type, member.id, recipient.user.notification_email).deliver_later + mailer.member_access_requested_email(member.real_source_type, member.id, recipient.user.id).deliver_later end def fallback_to_group_owners_maintainers?(recipients, member) diff --git a/app/services/projects/base_move_relations_service.rb b/app/services/projects/base_move_relations_service.rb index 24dec1f3a45..3a159cef58b 100644 --- a/app/services/projects/base_move_relations_service.rb +++ b/app/services/projects/base_move_relations_service.rb @@ -10,17 +10,5 @@ module Projects true end - - private - - # rubocop: disable CodeReuse/ActiveRecord - def prepare_relation(relation, id_param = :id) - if Gitlab::Database.postgresql? - relation - else - relation.model.where("#{id_param}": relation.pluck(id_param)) - end - end - # rubocop: enable CodeReuse/ActiveRecord end end diff --git a/app/services/projects/destroy_service.rb b/app/services/projects/destroy_service.rb index b805a7f1211..a1279bfb3a3 100644 --- a/app/services/projects/destroy_service.rb +++ b/app/services/projects/destroy_service.rb @@ -210,11 +210,20 @@ module Projects end def flush_caches(project) - project.repository.before_delete + ignore_git_errors(repo_path) { project.repository.before_delete } - Repository.new(wiki_path, project, disk_path: repo_path).before_delete + ignore_git_errors(wiki_path) { Repository.new(wiki_path, project, disk_path: repo_path).before_delete } Projects::ForksCountService.new(project).delete_cache end + + # If we get a Gitaly error, the repository may be corrupted. We can + # ignore these errors since we're going to trash the repositories + # anyway. + def ignore_git_errors(disk_path, &block) + yield + rescue Gitlab::Git::CommandError => e + Gitlab::GitLogger.warn(class: self.class.name, project_id: project.id, disk_path: disk_path, message: e.to_s) + end end end diff --git a/app/services/projects/fetch_statistics_increment_service.rb b/app/services/projects/fetch_statistics_increment_service.rb index 8644e6bf313..b150fd2d9f1 100644 --- a/app/services/projects/fetch_statistics_increment_service.rb +++ b/app/services/projects/fetch_statistics_increment_service.rb @@ -12,14 +12,9 @@ module Projects increment_fetch_count_sql = <<~SQL INSERT INTO #{table_name} (project_id, date, fetch_count) VALUES (#{project.id}, '#{Date.today}', 1) + ON CONFLICT (project_id, date) DO UPDATE SET fetch_count = #{table_name}.fetch_count + 1 SQL - increment_fetch_count_sql += if Gitlab::Database.postgresql? - "ON CONFLICT (project_id, date) DO UPDATE SET fetch_count = #{table_name}.fetch_count + 1" - else - "ON DUPLICATE KEY UPDATE fetch_count = #{table_name}.fetch_count + 1" - end - ActiveRecord::Base.connection.execute(increment_fetch_count_sql) end diff --git a/app/services/projects/move_deploy_keys_projects_service.rb b/app/services/projects/move_deploy_keys_projects_service.rb index b6a3af8c7b8..01419563538 100644 --- a/app/services/projects/move_deploy_keys_projects_service.rb +++ b/app/services/projects/move_deploy_keys_projects_service.rb @@ -16,8 +16,7 @@ module Projects private def move_deploy_keys_projects - prepare_relation(non_existent_deploy_keys_projects) - .update_all(project_id: @project.id) + non_existent_deploy_keys_projects.update_all(project_id: @project.id) end # rubocop: disable CodeReuse/ActiveRecord diff --git a/app/services/projects/move_lfs_objects_projects_service.rb b/app/services/projects/move_lfs_objects_projects_service.rb index 308a54ad06e..10e19014db4 100644 --- a/app/services/projects/move_lfs_objects_projects_service.rb +++ b/app/services/projects/move_lfs_objects_projects_service.rb @@ -16,8 +16,7 @@ module Projects private def move_lfs_objects_projects - prepare_relation(non_existent_lfs_objects_projects) - .update_all(project_id: @project.lfs_storage_project.id) + non_existent_lfs_objects_projects.update_all(project_id: @project.lfs_storage_project.id) end def remove_remaining_lfs_objects_project diff --git a/app/services/projects/move_notification_settings_service.rb b/app/services/projects/move_notification_settings_service.rb index e740c44bd26..65a888fe26b 100644 --- a/app/services/projects/move_notification_settings_service.rb +++ b/app/services/projects/move_notification_settings_service.rb @@ -16,8 +16,7 @@ module Projects private def move_notification_settings - prepare_relation(non_existent_notifications) - .update_all(source_id: @project.id) + non_existent_notifications.update_all(source_id: @project.id) end # Remove remaining notification settings from source_project diff --git a/app/services/projects/move_project_authorizations_service.rb b/app/services/projects/move_project_authorizations_service.rb index 2985ba89014..c95ad60ab5e 100644 --- a/app/services/projects/move_project_authorizations_service.rb +++ b/app/services/projects/move_project_authorizations_service.rb @@ -21,8 +21,7 @@ module Projects private def move_project_authorizations - prepare_relation(non_existent_authorization, :user_id) - .update_all(project_id: @project.id) + non_existent_authorization.update_all(project_id: @project.id) end def remove_remaining_authorizations diff --git a/app/services/projects/move_project_group_links_service.rb b/app/services/projects/move_project_group_links_service.rb index cf4b291c761..d1aa9af2bcb 100644 --- a/app/services/projects/move_project_group_links_service.rb +++ b/app/services/projects/move_project_group_links_service.rb @@ -20,8 +20,7 @@ module Projects private def move_group_links - prepare_relation(non_existent_group_links) - .update_all(project_id: @project.id) + non_existent_group_links.update_all(project_id: @project.id) end # Remove remaining project group links from source_project diff --git a/app/services/projects/move_project_members_service.rb b/app/services/projects/move_project_members_service.rb index faf389241d2..de4e7e5a1e3 100644 --- a/app/services/projects/move_project_members_service.rb +++ b/app/services/projects/move_project_members_service.rb @@ -20,7 +20,7 @@ module Projects private def move_project_members - prepare_relation(non_existent_members).update_all(source_id: @project.id) + non_existent_members.update_all(source_id: @project.id) end def remove_remaining_members diff --git a/app/services/quick_actions/interpret_service.rb b/app/services/quick_actions/interpret_service.rb index 8ff73522e5f..7f944e25887 100644 --- a/app/services/quick_actions/interpret_service.rb +++ b/app/services/quick_actions/interpret_service.rb @@ -31,17 +31,19 @@ module QuickActions end # Takes a text and interprets the commands that are extracted from it. - # Returns the content without commands, and hash of changes to be applied to a record. + # Returns the content without commands, a hash of changes to be applied to a record + # and a string containing the execution_message to show to the user. def execute(content, quick_action_target, only: nil) - return [content, {}] unless current_user.can?(:use_quick_actions) + return [content, {}, ''] unless current_user.can?(:use_quick_actions) @quick_action_target = quick_action_target @updates = {} + @execution_message = {} content, commands = extractor.extract_commands(content, only: only) extract_updates(commands) - [content, @updates] + [content, @updates, execution_messages_for(commands)] end # Takes a text and interprets the commands that are extracted from it. @@ -119,8 +121,12 @@ module QuickActions labels_params.scan(/"([^"]+)"|([^ ]+)/).flatten.compact end - def find_label_references(labels_param) - find_labels(labels_param).map(&:to_reference) + def find_label_references(labels_param, format = :id) + labels_to_reference(find_labels(labels_param), format) + end + + def labels_to_reference(labels, format = :id) + labels.map { |l| l.to_reference(format: format) } end def find_label_ids(labels_param) @@ -128,11 +134,24 @@ module QuickActions end def explain_commands(commands) + map_commands(commands, :explain) + end + + def execution_messages_for(commands) + map_commands(commands, :execute_message).join(' ') + end + + def map_commands(commands, method) commands.map do |name, arg| definition = self.class.definition_by_name(name) next unless definition - definition.explain(self, arg) + case method + when :explain + definition.explain(self, arg) + when :execute_message + @execution_message[name.to_sym] || definition.execute_message(self, arg) + end end.compact end diff --git a/app/services/system_note_service.rb b/app/services/system_note_service.rb index e4564bc9b00..e30debbbe75 100644 --- a/app/services/system_note_service.rb +++ b/app/services/system_note_service.rb @@ -597,6 +597,14 @@ module SystemNoteService note_text =~ /\A#{cross_reference_note_prefix}/i end + def zoom_link_added(issue, project, author) + create_note(NoteSummary.new(issue, project, author, _('a Zoom call was added to this issue'), action: 'pinned_embed')) + end + + def zoom_link_removed(issue, project, author) + create_note(NoteSummary.new(issue, project, author, _('a Zoom call was removed from this issue'), action: 'pinned_embed')) + end + private # rubocop: disable CodeReuse/ActiveRecord diff --git a/app/services/users/refresh_authorized_projects_service.rb b/app/services/users/refresh_authorized_projects_service.rb index 4a26d2be2af..ae67b4f5256 100644 --- a/app/services/users/refresh_authorized_projects_service.rb +++ b/app/services/users/refresh_authorized_projects_service.rb @@ -102,13 +102,7 @@ module Users end def fresh_authorizations - klass = if Group.supports_nested_objects? - Gitlab::ProjectAuthorizations::WithNestedGroups - else - Gitlab::ProjectAuthorizations::WithoutNestedGroups - end - - klass.new(user).calculate + Gitlab::ProjectAuthorizations.new(user).calculate end end end diff --git a/app/services/zoom_notes_service.rb b/app/services/zoom_notes_service.rb new file mode 100644 index 00000000000..983a7fcacd1 --- /dev/null +++ b/app/services/zoom_notes_service.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +class ZoomNotesService + def initialize(issue, project, current_user, old_description: nil) + @issue = issue + @project = project + @current_user = current_user + @old_description = old_description + end + + def execute + return if @issue.description == @old_description + + if zoom_link_added? + zoom_link_added_notification + elsif zoom_link_removed? + zoom_link_removed_notification + end + end + + private + + def zoom_link_added? + has_zoom_link?(@issue.description) && !has_zoom_link?(@old_description) + end + + def zoom_link_removed? + !has_zoom_link?(@issue.description) && has_zoom_link?(@old_description) + end + + def has_zoom_link?(text) + Gitlab::ZoomLinkExtractor.new(text).match? + end + + def zoom_link_added_notification + SystemNoteService.zoom_link_added(@issue, @project, @current_user) + end + + def zoom_link_removed_notification + SystemNoteService.zoom_link_removed(@issue, @project, @current_user) + end +end diff --git a/app/uploaders/records_uploads.rb b/app/uploaders/records_uploads.rb index 3b2a9d2f80e..967fcdc704e 100644 --- a/app/uploaders/records_uploads.rb +++ b/app/uploaders/records_uploads.rb @@ -27,7 +27,7 @@ module RecordsUploads end def readd_upload - uploads.where(path: upload_path).delete_all + uploads.where(model: model, path: upload_path).delete_all upload.delete if upload self.upload = build_upload.tap(&:save!) diff --git a/app/views/admin/application_settings/_outbound.html.haml b/app/views/admin/application_settings/_outbound.html.haml index d16304ed338..e58bb526c11 100644 --- a/app/views/admin/application_settings/_outbound.html.haml +++ b/app/views/admin/application_settings/_outbound.html.haml @@ -9,6 +9,13 @@ Allow requests to the local network from hooks and services .form-group + = f.label :outbound_local_requests_whitelist_raw, class: 'label-bold' do + = _('Whitelist to allow requests to the local network from hooks and services') + = f.text_area :outbound_local_requests_whitelist_raw, placeholder: "example.com, 192.168.1.1", class: 'form-control', rows: 8 + %span.form-text.text-muted + = _('Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are disabled. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The whitelist can hold a maximum of 4000 entries. Domains should use IDNA encoding. Ex: domain.com, 192.168.1.1, 127.0.0.0/28.') + + .form-group .form-check = f.check_box :dns_rebinding_protection_enabled, class: 'form-check-input' = f.label :dns_rebinding_protection_enabled, class: 'form-check-label' do diff --git a/app/views/admin/application_settings/_performance.html.haml b/app/views/admin/application_settings/_performance.html.haml index 7821a83530f..b52171afc69 100644 --- a/app/views/admin/application_settings/_performance.html.haml +++ b/app/views/admin/application_settings/_performance.html.haml @@ -15,4 +15,10 @@ AuthorizedKeysCommand. Click on the help icon for more details. = link_to icon('question-circle'), help_page_path('administration/operations/fast_ssh_key_lookup') + .form-group + = f.label :raw_blob_request_limit, _('Raw blob request rate limit per minute'), class: 'label-bold' + = f.number_field :raw_blob_request_limit, class: 'form-control' + .form-text.text-muted + = _('Highest number of requests per minute for each raw path, default to 300. To disable throttling set to 0.') + = f.submit 'Save changes', class: "btn btn-success" diff --git a/app/views/admin/broadcast_messages/_form.html.haml b/app/views/admin/broadcast_messages/_form.html.haml index c8ee87c6212..962234d3aea 100644 --- a/app/views/admin/broadcast_messages/_form.html.haml +++ b/app/views/admin/broadcast_messages/_form.html.haml @@ -17,19 +17,27 @@ required: true, dir: 'auto', data: { preview_path: preview_admin_broadcast_messages_path } - .form-group.row.js-toggle-colors-container - .col-sm-10.offset-sm-2 - = link_to 'Customize colors', '#', class: 'js-toggle-colors-link' - .form-group.row.js-toggle-colors-container.toggle-colors.hide + .form-group.row .col-sm-2.col-form-label - = f.label :color, "Background Color" + = f.label :color, _("Background color") .col-sm-10 - = f.color_field :color, class: "form-control" + .input-group + .input-group-prepend + .input-group-text.label-color-preview{ :style => 'background-color: ' + @broadcast_message.color + '; color: ' + @broadcast_message.font } + = ' '.html_safe + = f.text_field :color, class: "form-control" + .form-text.text-muted + = _('Choose any color.') + %br + = _("Or you can choose one of the suggested colors below") + + = render_suggested_colors + .form-group.row.js-toggle-colors-container.toggle-colors.hide .col-sm-2.col-form-label = f.label :font, "Font Color" .col-sm-10 - = f.color_field :font, class: "form-control" + = f.color_field :font, class: "form-control text-font-color" .form-group.row .col-sm-2.col-form-label = f.label :starts_at, _("Starts at (UTC)") diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml index 581f6ae0714..c29ecb43fe6 100644 --- a/app/views/admin/dashboard/index.html.haml +++ b/app/views/admin/dashboard/index.html.haml @@ -76,51 +76,17 @@ .info-well .well-segment.admin-well.admin-well-features %h4 Features - - sign_up = "Sign up" - %p{ "aria-label" => "#{sign_up}: status " + (allow_signup? ? "on" : "off") } - = sign_up - %span.light.float-right - = boolean_to_icon allow_signup? - - ldap = "LDAP" - %p{ "aria-label" => "#{ldap}: status " + (Gitlab.config.ldap.enabled ? "on" : "off") } - = ldap - %span.light.float-right - = boolean_to_icon Gitlab.config.ldap.enabled - - gravatar = "Gravatar" - %p{ "aria-label" => "#{gravatar}: status " + (gravatar_enabled? ? "on" : "off") } - = gravatar - %span.light.float-right - = boolean_to_icon gravatar_enabled? - - omniauth = "OmniAuth" - %p{ "aria-label" => "#{omniauth}: status " + (Gitlab::Auth.omniauth_enabled? ? "on" : "off") } - = omniauth - %span.light.float-right - = boolean_to_icon Gitlab::Auth.omniauth_enabled? - - reply_email = "Reply by email" - %p{ "aria-label" => "#{reply_email}: status " + (Gitlab::IncomingEmail.enabled? ? "on" : "off") } - = reply_email - %span.light.float-right - = boolean_to_icon Gitlab::IncomingEmail.enabled? + = feature_entry(_('Sign up'), href: admin_application_settings_path(anchor: 'js-signup-settings')) + = feature_entry(_('LDAP'), enabled: Gitlab.config.ldap.enabled) + = feature_entry(_('Gravatar'), href: admin_application_settings_path(anchor: 'js-account-settings'), enabled: gravatar_enabled?) + = feature_entry(_('OmniAuth'), href: admin_application_settings_path(anchor: 'js-signin-settings'), enabled: Gitlab::Auth.omniauth_enabled?) + = feature_entry(_('Reply by email'), enabled: Gitlab::IncomingEmail.enabled?) = render_if_exists 'admin/dashboard/elastic_and_geo' - - container_reg = "Container Registry" - %p{ "aria-label" => "#{container_reg}: status " + (Gitlab.config.registry.enabled ? "on" : "off") } - = container_reg - %span.light.float-right - = boolean_to_icon Gitlab.config.registry.enabled - - gitlab_pages = 'GitLab Pages' - - gitlab_pages_enabled = Gitlab.config.pages.enabled - %p{ "aria-label" => "#{gitlab_pages}: status " + (gitlab_pages_enabled ? "on" : "off") } - = gitlab_pages - %span.light.float-right - = boolean_to_icon gitlab_pages_enabled - - gitlab_shared_runners = 'Shared Runners' - - gitlab_shared_runners_enabled = Gitlab.config.gitlab_ci.shared_runners_enabled - %p{ "aria-label" => "#{gitlab_shared_runners}: status " + (gitlab_shared_runners_enabled ? "on" : "off") } - = gitlab_shared_runners - %span.light.float-right - = boolean_to_icon gitlab_shared_runners_enabled + = feature_entry(_('Container Registry'), href: ci_cd_admin_application_settings_path(anchor: 'js-registry-settings'), enabled: Gitlab.config.registry.enabled) + = feature_entry(_('Gitlab Pages'), href: help_instance_configuration_url, enabled: Gitlab.config.pages.enabled) + = feature_entry(_('Shared Runners'), href: admin_runners_path, enabled: Gitlab.config.gitlab_ci.shared_runners_enabled) .col-md-4 .info-well .well-segment.admin-well @@ -130,7 +96,8 @@ .float-right = version_status_badge %p - GitLab + %a{ href: admin_application_settings_path } + GitLab %span.float-right = Gitlab::VERSION = "(#{Gitlab.revision})" diff --git a/app/views/clusters/clusters/_namespace.html.haml b/app/views/clusters/clusters/_namespace.html.haml new file mode 100644 index 00000000000..0c64819ad62 --- /dev/null +++ b/app/views/clusters/clusters/_namespace.html.haml @@ -0,0 +1,14 @@ +- managed_namespace_help_text = s_('ClusterIntegration|Choose a prefix to be used for your namespaces. Defaults to your project path.') +- non_managed_namespace_help_text = s_('ClusterIntegration|The namespace associated with your project. This will be used for deploy boards, pod logs, and Web terminals.') +- managed_namespace_help_link = link_to _('More information'), help_page_path('user/project/clusters/index.md', + anchor: 'gitlab-managed-clusters'), target: '_blank' + +.js-namespace-prefixed + = platform_field.text_field :namespace, + label: s_('ClusterIntegration|Project namespace prefix (optional, unique)'), label_class: 'label-bold', + help: '%{help_text} %{help_link}'.html_safe % { help_text: managed_namespace_help_text, help_link: managed_namespace_help_link } +.js-namespace.hidden + = platform_field.text_field :namespace, + label: s_('ClusterIntegration|Project namespace (optional, unique)'), label_class: 'label-bold', + help: '%{help_text}'.html_safe % { help_text: non_managed_namespace_help_text }, + disabled: true diff --git a/app/views/clusters/clusters/user/_form.html.haml b/app/views/clusters/clusters/user/_form.html.haml index f2fc5ac93fb..1d212553c3b 100644 --- a/app/views/clusters/clusters/user/_form.html.haml +++ b/app/views/clusters/clusters/user/_form.html.haml @@ -34,10 +34,6 @@ autocomplete: 'off', label_class: 'label-bold', help: '%{help_text} %{help_link}'.html_safe % { help_text: token_help_text, help_link: more_info_link } - - if @user_cluster.allow_user_defined_namespace? - = platform_kubernetes_field.text_field :namespace, - label: s_('ClusterIntegration|Project namespace (optional, unique)'), label_class: 'label-bold' - = platform_kubernetes_field.form_group :authorization_type, { help: '%{help_text} %{help_link}'.html_safe % { help_text: rbac_help_text, help_link: rbac_help_link } } do = platform_kubernetes_field.check_box :authorization_type, @@ -46,10 +42,15 @@ .form-group = field.check_box :managed, { label: s_('ClusterIntegration|GitLab-managed cluster'), + class: 'js-gl-managed', label_class: 'label-bold' } .form-text.text-muted = s_('ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster.') = link_to _('More information'), help_page_path('user/project/clusters/index.md', anchor: 'gitlab-managed-clusters'), target: '_blank' + = field.fields_for :platform_kubernetes, @user_cluster.platform_kubernetes do |platform_kubernetes_field| + - if @user_cluster.allow_user_defined_namespace? + = render('clusters/clusters/namespace', platform_field: platform_kubernetes_field) + .form-group = field.submit s_('ClusterIntegration|Add Kubernetes cluster'), class: 'btn btn-success' diff --git a/app/views/clusters/platforms/kubernetes/_form.html.haml b/app/views/clusters/platforms/kubernetes/_form.html.haml index f2e44462226..e50c573bd90 100644 --- a/app/views/clusters/platforms/kubernetes/_form.html.haml +++ b/app/views/clusters/platforms/kubernetes/_form.html.haml @@ -36,10 +36,6 @@ label: s_('ClusterIntegration|Service Token'), label_class: 'label-bold', input_group_class: 'gl-field-error-anchor', append: show_token_btn + copy_token_btn - - if cluster.allow_user_defined_namespace? - = platform_field.text_field :namespace, label: s_('ClusterIntegration|Project namespace (optional, unique)'), - label_class: 'label-bold' - = platform_field.form_group :authorization_type do = platform_field.check_box :authorization_type, { disabled: true, label: s_('ClusterIntegration|RBAC-enabled cluster'), label_class: 'label-bold', inline: true }, 'rbac', 'abac' @@ -49,10 +45,14 @@ .form-group = field.check_box :managed, { label: s_('ClusterIntegration|GitLab-managed cluster'), + class: 'js-gl-managed', label_class: 'label-bold' } .form-text.text-muted = s_('ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster.') = link_to _('More information'), help_page_path('user/project/clusters/index.md', anchor: 'gitlab-managed-clusters'), target: '_blank' + - if cluster.allow_user_defined_namespace? + = render('clusters/clusters/namespace', platform_field: platform_field) + .form-group = field.submit s_('ClusterIntegration|Save changes'), class: 'btn btn-success' diff --git a/app/views/groups/settings/_advanced.html.haml b/app/views/groups/settings/_advanced.html.haml index 5d211d0e186..d1eb6478997 100644 --- a/app/views/groups/settings/_advanced.html.haml +++ b/app/views/groups/settings/_advanced.html.haml @@ -23,20 +23,19 @@ = f.submit 'Change group path', class: 'btn btn-warning' -- if supports_nested_groups? - .sub-section - %h4.warning-title Transfer group - = form_for @group, url: transfer_group_path(@group), method: :put do |f| - .form-group - = dropdown_tag('Select parent group', options: { toggle_class: 'js-groups-dropdown', title: 'Parent Group', filter: true, dropdown_class: 'dropdown-open-top dropdown-group-transfer', placeholder: 'Search groups', data: { data: parent_group_options(@group) } }) - = hidden_field_tag 'new_parent_group_id' +.sub-section + %h4.warning-title Transfer group + = form_for @group, url: transfer_group_path(@group), method: :put do |f| + .form-group + = dropdown_tag('Select parent group', options: { toggle_class: 'js-groups-dropdown', title: 'Parent Group', filter: true, dropdown_class: 'dropdown-open-top dropdown-group-transfer', placeholder: 'Search groups', data: { data: parent_group_options(@group) } }) + = hidden_field_tag 'new_parent_group_id' - %ul - %li Be careful. Changing a group's parent can have unintended #{link_to 'side effects', 'https://docs.gitlab.com/ce/user/project/index.html#redirects-when-changing-repository-paths', target: 'blank'}. - %li You can only transfer the group to a group you manage. - %li You will need to update your local repositories to point to the new location. - %li If the parent group's visibility is lower than the group current visibility, visibility levels for subgroups and projects will be changed to match the new parent group's visibility. - = f.submit 'Transfer group', class: 'btn btn-warning' + %ul + %li Be careful. Changing a group's parent can have unintended #{link_to 'side effects', 'https://docs.gitlab.com/ce/user/project/index.html#redirects-when-changing-repository-paths', target: 'blank'}. + %li You can only transfer the group to a group you manage. + %li You will need to update your local repositories to point to the new location. + %li If the parent group's visibility is lower than the group current visibility, visibility levels for subgroups and projects will be changed to match the new parent group's visibility. + = f.submit 'Transfer group', class: 'btn btn-warning' .sub-section %h4.danger-title= _('Remove group') diff --git a/app/views/layouts/_search.html.haml b/app/views/layouts/_search.html.haml index c62dce880c0..bc900992cb0 100644 --- a/app/views/layouts/_search.html.haml +++ b/app/views/layouts/_search.html.haml @@ -13,7 +13,8 @@ tabindex: '1', autocomplete: 'off', data: { issues_path: issues_dashboard_path, - mr_path: merge_requests_dashboard_path }, + mr_path: merge_requests_dashboard_path, + qa_selector: 'search_term_field' }, aria: { label: _('Search or jump to…') } %button.hidden.js-dropdown-search-toggle{ type: 'button', data: { toggle: 'dropdown' } } .dropdown-menu.dropdown-select.js-dashboard-search-options @@ -45,5 +46,6 @@ - if @snippet || @snippets = hidden_field_tag :snippets, true = hidden_field_tag :repository_ref, @ref + = hidden_field_tag :nav_source, 'navbar' = button_tag 'Go' if ENV['RAILS_ENV'] == 'test' .search-autocomplete-opts.hide{ :'data-autocomplete-path' => search_autocomplete_path, :'data-autocomplete-project-id' => @project.try(:id), :'data-autocomplete-project-ref' => @ref } diff --git a/app/views/layouts/nav/sidebar/_admin.html.haml b/app/views/layouts/nav/sidebar/_admin.html.haml index 87133c7ba22..cb39c830170 100644 --- a/app/views/layouts/nav/sidebar/_admin.html.haml +++ b/app/views/layouts/nav/sidebar/_admin.html.haml @@ -236,7 +236,7 @@ %span = _('General') = nav_link(path: 'application_settings#integrations') do - = link_to integrations_admin_application_settings_path, title: _('Integrations') do + = link_to integrations_admin_application_settings_path, title: _('Integrations'), data: { qa_selector: 'integration_settings_link' } do %span = _('Integrations') = nav_link(path: 'application_settings#repository') do diff --git a/app/views/layouts/nav/sidebar/_group.html.haml b/app/views/layouts/nav/sidebar/_group.html.haml index 4b5ccc33716..48c9f19f89f 100644 --- a/app/views/layouts/nav/sidebar/_group.html.haml +++ b/app/views/layouts/nav/sidebar/_group.html.haml @@ -36,8 +36,6 @@ %span = _('Activity') - = render_if_exists 'groups/sidebar/security_dashboard' # EE-specific - - if group_sidebar_link?(:contribution_analytics) = nav_link(path: 'analytics#show') do = link_to group_analytics_path(@group), title: _('Contribution Analytics'), data: { placement: 'right' } do @@ -105,6 +103,8 @@ = _('Merge Requests') %span.badge.badge-pill.count.merge_counter.js-merge-counter.fly-out-badge= number_with_delimiter(merge_requests_count) + = render_if_exists "layouts/nav/ee/security_link" # EE-specific + - if group_sidebar_link?(:kubernetes) = nav_link(controller: [:clusters]) do = link_to group_clusters_path(@group) do diff --git a/app/views/layouts/nav/sidebar/_project.html.haml b/app/views/layouts/nav/sidebar/_project.html.haml index a9af5ba5008..02ecf816e90 100644 --- a/app/views/layouts/nav/sidebar/_project.html.haml +++ b/app/views/layouts/nav/sidebar/_project.html.haml @@ -9,7 +9,7 @@ = @project.name %ul.sidebar-top-level-items = nav_link(path: sidebar_projects_paths, html_options: { class: 'home' }) do - = link_to project_path(@project), class: 'shortcuts-project qa-link-project' do + = link_to project_path(@project), class: 'shortcuts-project rspec-project-link', data: { qa_selector: 'project_link' } do .nav-icon-container = sprite_icon('home') %span.nav-item-name @@ -26,7 +26,7 @@ %span= _('Details') = nav_link(path: 'projects#activity') do - = link_to activity_project_path(@project), title: _('Activity'), class: 'shortcuts-project-activity qa-activity-link' do + = link_to activity_project_path(@project), title: _('Activity'), class: 'shortcuts-project-activity', data: { qa_selector: 'activity_link' } do %span= _('Activity') - if project_nav_tab?(:releases) @@ -34,10 +34,6 @@ = link_to project_releases_path(@project), title: _('Releases'), class: 'shortcuts-project-releases' do %span= _('Releases') - = render_if_exists 'projects/sidebar/security_dashboard' - - = render_if_exists 'projects/sidebar/dependencies' - - if can?(current_user, :read_cycle_analytics, @project) = nav_link(path: 'cycle_analytics#show') do = link_to project_cycle_analytics_path(@project), title: _('Cycle Analytics'), class: 'shortcuts-project-cycle-analytics' do @@ -150,7 +146,7 @@ - if project_nav_tab? :merge_requests = nav_link(controller: @project.issues_enabled? ? :merge_requests : [:merge_requests, :labels, :milestones]) do - = link_to project_merge_requests_path(@project), class: 'shortcuts-merge_requests qa-merge-requests-link' do + = link_to project_merge_requests_path(@project), class: 'shortcuts-merge_requests', data: { qa_selector: 'merge_requests_link' } do .nav-icon-container = sprite_icon('git-merge') %span.nav-item-name#js-onboarding-mr-link @@ -167,7 +163,7 @@ - if project_nav_tab? :pipelines = nav_link(controller: [:pipelines, :builds, :jobs, :pipeline_schedules, :artifacts]) do - = link_to project_pipelines_path(@project), class: 'shortcuts-pipelines qa-link-pipelines' do + = link_to project_pipelines_path(@project), class: 'shortcuts-pipelines qa-link-pipelines rspec-link-pipelines' do .nav-icon-container = sprite_icon('rocket') %span.nav-item-name#js-onboarding-pipelines-link @@ -203,6 +199,8 @@ %span = _('Charts') + = render_if_exists 'layouts/nav/sidebar/project_security_link' # EE-specific + - if project_nav_tab? :operations = nav_link(controller: sidebar_operations_paths) do = link_to sidebar_operations_link_path, class: 'shortcuts-operations qa-link-operations' do @@ -274,25 +272,12 @@ = render_if_exists 'layouts/nav/sidebar/project_feature_flags_link' - - if project_nav_tab? :container_registry - = nav_link(controller: %w[projects/registry/repositories]) do - = link_to project_container_registry_index_path(@project), class: 'shortcuts-container-registry' do - .nav-icon-container - = sprite_icon('disk') - %span.nav-item-name - = _('Registry') - %ul.sidebar-sub-level-items.is-fly-out-only - = nav_link(controller: %w[projects/registry/repositories], html_options: { class: "fly-out-top-item" } ) do - = link_to project_container_registry_index_path(@project) do - %strong.fly-out-top-item-name - = _('Registry') - = render_if_exists 'layouts/nav/sidebar/project_packages_link' - if project_nav_tab? :wiki - wiki_url = project_wiki_path(@project, :home) = nav_link(controller: :wikis) do - = link_to wiki_url, class: 'shortcuts-wiki qa-wiki-link' do + = link_to wiki_url, class: 'shortcuts-wiki', data: { qa_selector: 'wiki_link' } do .nav-icon-container = sprite_icon('book') %span.nav-item-name diff --git a/app/views/layouts/nav/sidebar/_project_packages_link.html.haml b/app/views/layouts/nav/sidebar/_project_packages_link.html.haml new file mode 100644 index 00000000000..0fdfc6cd2ab --- /dev/null +++ b/app/views/layouts/nav/sidebar/_project_packages_link.html.haml @@ -0,0 +1,16 @@ +- if project_nav_tab? :container_registry + = nav_link controller: :repositories do + = link_to project_container_registry_index_path(@project) do + .nav-icon-container + = sprite_icon('package') + %span.nav-item-name + = _('Packages') + %ul.sidebar-sub-level-items + = nav_link(controller: :repositories, html_options: { class: "fly-out-top-item" } ) do + = link_to project_container_registry_index_path(@project) do + %strong.fly-out-top-item-name + = _('Packages') + %li.divider.fly-out-top-item + = nav_link controller: :repositories do + = link_to project_container_registry_index_path(@project), class: 'shortcuts-container-registry', title: _('Container Registry') do + %span= _('Container Registry') diff --git a/app/views/notify/new_merge_request_email.html.haml b/app/views/notify/new_merge_request_email.html.haml index 2ddea0b9f16..8fecdc6e8a6 100644 --- a/app/views/notify/new_merge_request_email.html.haml +++ b/app/views/notify/new_merge_request_email.html.haml @@ -5,7 +5,7 @@ .branch = merge_path_description(@merge_request, 'to') .author - Author #{@merge_request.author_name} + Author: #{@merge_request.author_name} .assignee = assignees_label(@merge_request) .approvers diff --git a/app/views/peek/_bar.html.haml b/app/views/peek/_bar.html.haml index 89d3b931f88..5228930293c 100644 --- a/app/views/peek/_bar.html.haml +++ b/app/views/peek/_bar.html.haml @@ -2,6 +2,5 @@ #js-peek{ data: { env: Peek.env, request_id: Peek.request_id, - peek_url: "#{peek_routes_path}/results", - profile_url: url_for(safe_params.merge(lineprofiler: 'true')) }, + peek_url: "#{peek_routes_path}/results" }, class: Peek.env } diff --git a/app/views/peek/views/_gc.html.haml b/app/views/peek/views/_gc.html.haml deleted file mode 100644 index 2a586261ce1..00000000000 --- a/app/views/peek/views/_gc.html.haml +++ /dev/null @@ -1,7 +0,0 @@ -- local_assigns.fetch(:view) - -%span.bold - %span{ title: _('Invoke Time'), data: { defer_to: "#{view.defer_key}-gc_time" } }... - \/ - %span{ title: _('Invoke Count'), data: { defer_to: "#{view.defer_key}-invokes" } }... -gc diff --git a/app/views/peek/views/_redis.html.haml b/app/views/peek/views/_redis.html.haml deleted file mode 100644 index f7fba6c95fc..00000000000 --- a/app/views/peek/views/_redis.html.haml +++ /dev/null @@ -1,7 +0,0 @@ -- local_assigns.fetch(:view) - -%span.bold - %span{ data: { defer_to: "#{view.defer_key}-duration" } }... - \/ - %span{ data: { defer_to: "#{view.defer_key}-calls" } }... -redis diff --git a/app/views/peek/views/_sidekiq.html.haml b/app/views/peek/views/_sidekiq.html.haml deleted file mode 100644 index 7efbc05890d..00000000000 --- a/app/views/peek/views/_sidekiq.html.haml +++ /dev/null @@ -1,7 +0,0 @@ -- local_assigns.fetch(:view) - -%span.bold - %span{ data: { defer_to: "#{view.defer_key}-duration" } }... - \/ - %span{ data: { defer_to: "#{view.defer_key}-calls" } }... -sidekiq diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml index e36d5192a29..ffb90bbd354 100644 --- a/app/views/profiles/show.html.haml +++ b/app/views/profiles/show.html.haml @@ -89,10 +89,10 @@ .col-lg-8 .row - if @user.read_only_attribute?(:name) - = f.text_field :name, required: true, readonly: true, wrapper: { class: 'col-md-9 qa-full-name' }, + = f.text_field :name, required: true, readonly: true, wrapper: { class: 'col-md-9 qa-full-name rspec-full-name' }, help: s_("Profiles|Your name was automatically set based on your %{provider_label} account, so people you know can recognize you") % { provider_label: attribute_provider_label(:name) } - else - = f.text_field :name, label: s_('Profiles|Full name'), required: true, title: s_("Profiles|Using emojis in names seems fun, but please try to set a status message instead"), wrapper: { class: 'col-md-9 qa-full-name' }, help: s_("Profiles|Enter your name, so people you know can recognize you") + = f.text_field :name, label: s_('Profiles|Full name'), required: true, title: s_("Profiles|Using emojis in names seems fun, but please try to set a status message instead"), wrapper: { class: 'col-md-9 qa-full-name rspec-full-name' }, help: s_("Profiles|Enter your name, so people you know can recognize you") = f.text_field :id, readonly: true, label: s_('Profiles|User ID'), wrapper: { class: 'col-md-3' } = render_if_exists 'profiles/email_settings', form: f diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml index 3403564992e..763cc764144 100644 --- a/app/views/projects/edit.html.haml +++ b/app/views/projects/edit.html.haml @@ -23,7 +23,7 @@ .js-project-permissions-form = f.submit _('Save changes'), class: "btn btn-success" -%section.qa-merge-request-settings.settings.merge-requests-feature.no-animate#js-merge-request-settings{ class: [('expanded' if expanded), ('hidden' if @project.project_feature.send(:merge_requests_access_level) == 0)] } +%section.qa-merge-request-settings.rspec-merge-request-settings.settings.merge-requests-feature.no-animate#js-merge-request-settings{ class: [('expanded' if expanded), ('hidden' if @project.project_feature.send(:merge_requests_access_level) == 0)] } .settings-header %h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only= _('Merge requests') %button.btn.btn-default.js-settings-toggle{ type: 'button' }= expanded ? _('Collapse') : _('Expand') @@ -35,7 +35,7 @@ = form_for [@project.namespace.becomes(Namespace), @project], remote: true, html: { multipart: true, class: "merge-request-settings-form js-mr-settings-form" }, authenticity_token: true do |f| %input{ name: 'update_section', type: 'hidden', value: 'js-merge-request-settings' } = render 'projects/merge_request_settings', form: f - = f.submit _('Save changes'), class: "btn btn-success qa-save-merge-request-changes" + = f.submit _('Save changes'), class: "btn btn-success qa-save-merge-request-changes rspec-save-merge-request-changes" = render_if_exists 'projects/merge_request_approvals_settings', expanded: expanded diff --git a/app/views/projects/jobs/show.html.haml b/app/views/projects/jobs/show.html.haml index 81a53f22f67..c7fab87a593 100644 --- a/app/views/projects/jobs/show.html.haml +++ b/app/views/projects/jobs/show.html.haml @@ -11,4 +11,5 @@ deployment_help_url: help_page_path('user/project/clusters/index.html', anchor: 'troubleshooting-failed-deployment-jobs'), runner_help_url: help_page_path('ci/runners/README.html', anchor: 'setting-maximum-job-timeout-for-a-runner'), runner_settings_url: project_runners_path(@build.project, anchor: 'js-runners-settings'), + variables_settings_url: project_variables_path(@build.project, anchor: 'js-cicd-variables-settings'), build_options: javascript_build_options } } diff --git a/app/views/projects/merge_requests/show.html.haml b/app/views/projects/merge_requests/show.html.haml index 2084ca6f905..2c5c5141bf0 100644 --- a/app/views/projects/merge_requests/show.html.haml +++ b/app/views/projects/merge_requests/show.html.haml @@ -32,7 +32,7 @@ .merge-request-tabs-holder{ class: ("js-tabs-affix" unless ENV['RAILS_ENV'] == 'test') } .merge-request-tabs-container %ul.merge-request-tabs.nav-tabs.nav.nav-links - %li.notes-tab.qa-notes-tab + %li.notes-tab{ data: { qa_selector: 'notes_tab'} } = tab_link_for @merge_request, :show, force_link: @commit.present? do = _("Discussion") %span.badge.badge-pill= @merge_request.related_notes.user.count diff --git a/app/views/projects/mirrors/_disabled_mirror_badge.html.haml b/app/views/projects/mirrors/_disabled_mirror_badge.html.haml index 356cb43f07f..9c11b650f75 100644 --- a/app/views/projects/mirrors/_disabled_mirror_badge.html.haml +++ b/app/views/projects/mirrors/_disabled_mirror_badge.html.haml @@ -1 +1 @@ -.badge.badge-warning.qa-disabled-mirror-badge{ data: { toggle: 'tooltip', html: 'true' }, title: _('Disabled mirrors can only be enabled by instance owners. It is recommended that you delete them.') }= _('Disabled') +.badge.badge-warning.qa-disabled-mirror-badge.rspec-disabled-mirror-badge{ data: { toggle: 'tooltip', html: 'true' }, title: _('Disabled mirrors can only be enabled by instance owners. It is recommended that you delete them.') }= _('Disabled') diff --git a/app/views/projects/mirrors/_mirror_repos.html.haml b/app/views/projects/mirrors/_mirror_repos.html.haml index e68fa5d08c7..280ec6d715b 100644 --- a/app/views/projects/mirrors/_mirror_repos.html.haml +++ b/app/views/projects/mirrors/_mirror_repos.html.haml @@ -50,7 +50,7 @@ = render_if_exists 'projects/mirrors/table_pull_row' - @project.remote_mirrors.each_with_index do |mirror, index| - next if mirror.new_record? - %tr.qa-mirrored-repository-row{ class: ('bg-secondary' if mirror.disabled?) } + %tr.qa-mirrored-repository-row.rspec-mirrored-repository-row{ class: ('bg-secondary' if mirror.disabled?) } %td.qa-mirror-repository-url= mirror.safe_url %td= _('Push') %td.qa-mirror-last-update-at= mirror.last_update_at.present? ? time_ago_with_tooltip(mirror.last_update_at) : _('Never') @@ -64,4 +64,4 @@ - if mirror.ssh_key_auth? = clipboard_button(text: mirror.ssh_public_key, class: 'btn btn-default', title: _('Copy SSH public key')) = render 'shared/remote_mirror_update_button', remote_mirror: mirror - %button.js-delete-mirror.qa-delete-mirror.btn.btn-danger{ type: 'button', data: { mirror_id: mirror.id, toggle: 'tooltip', container: 'body' }, title: _('Remove') }= icon('trash-o') + %button.js-delete-mirror.qa-delete-mirror.rspec-delete-mirror.btn.btn-danger{ type: 'button', data: { mirror_id: mirror.id, toggle: 'tooltip', container: 'body' }, title: _('Remove') }= icon('trash-o') diff --git a/app/views/projects/protected_branches/_create_protected_branch.html.haml b/app/views/projects/protected_branches/_create_protected_branch.html.haml index 24b53555cdc..ee359a01e74 100644 --- a/app/views/projects/protected_branches/_create_protected_branch.html.haml +++ b/app/views/projects/protected_branches/_create_protected_branch.html.haml @@ -2,13 +2,13 @@ .merge_access_levels-container = dropdown_tag('Select', options: { toggle_class: 'js-allowed-to-merge qa-allowed-to-merge-select wide', - dropdown_class: 'dropdown-menu-selectable qa-allowed-to-merge-dropdown capitalize-header', + dropdown_class: 'dropdown-menu-selectable qa-allowed-to-merge-dropdown rspec-allowed-to-merge-dropdown capitalize-header', data: { field_name: 'protected_branch[merge_access_levels_attributes][0][access_level]', input_id: 'merge_access_levels_attributes' }}) - content_for :push_access_levels do .push_access_levels-container = dropdown_tag('Select', options: { toggle_class: 'js-allowed-to-push qa-allowed-to-push-select wide', - dropdown_class: 'dropdown-menu-selectable qa-allowed-to-push-dropdown capitalize-header', + dropdown_class: 'dropdown-menu-selectable qa-allowed-to-push-dropdown rspec-allowed-to-push-dropdown capitalize-header', data: { field_name: 'protected_branch[push_access_levels_attributes][0][access_level]', input_id: 'push_access_levels_attributes' }}) = render 'projects/protected_branches/shared/create_protected_branch' diff --git a/app/views/projects/settings/ci_cd/_autodevops_form.html.haml b/app/views/projects/settings/ci_cd/_autodevops_form.html.haml index fe74dc122c3..04b77fb987a 100644 --- a/app/views/projects/settings/ci_cd/_autodevops_form.html.haml +++ b/app/views/projects/settings/ci_cd/_autodevops_form.html.haml @@ -8,7 +8,7 @@ .card.auto-devops-card .card-body .form-check - = form.check_box :enabled, class: 'form-check-input js-toggle-extra-settings', checked: auto_devops_enabled + = form.check_box :enabled, class: 'form-check-input js-toggle-extra-settings', checked: auto_devops_enabled, data: { qa_selector: 'enable_autodevops_checkbox' } = form.label :enabled, class: 'form-check-label' do %strong= s_('CICD|Default to Auto DevOps pipeline') - if auto_devops_enabled @@ -42,4 +42,4 @@ = s_('CICD|Automatic deployment to staging, manual deployment to production') = link_to icon('question-circle'), help_page_path('topics/autodevops/index.md', anchor: 'incremental-rollout-to-production'), target: '_blank' - = f.submit _('Save changes'), class: "btn btn-success prepend-top-15" + = f.submit _('Save changes'), class: "btn btn-success prepend-top-15", data: { qa_selector: 'save_changes_button' } diff --git a/app/views/projects/settings/ci_cd/show.html.haml b/app/views/projects/settings/ci_cd/show.html.haml index 5e3e1076c2c..87000e8270b 100644 --- a/app/views/projects/settings/ci_cd/show.html.haml +++ b/app/views/projects/settings/ci_cd/show.html.haml @@ -16,7 +16,7 @@ .settings-content = render 'form' -%section.qa-autodevops-settings.settings#autodevops-settings.no-animate{ class: ('expanded' if expanded) } +%section.settings#autodevops-settings.no-animate{ class: ('expanded' if expanded), data: { qa_selector: 'autodevops_settings_content' } } .settings-header %h4 = s_('CICD|Auto DevOps') @@ -30,7 +30,7 @@ = render_if_exists 'projects/settings/ci_cd/protected_environments', expanded: expanded -%section.qa-runners-settings.settings.no-animate#js-runners-settings{ class: ('expanded' if expanded) } +%section.settings.no-animate#js-runners-settings{ class: ('expanded' if expanded), data: { qa_selector: 'runners_settings_content' } } .settings-header %h4 = _("Runners") @@ -41,7 +41,7 @@ .settings-content = render 'projects/runners/index' -%section.qa-variables-settings.settings.no-animate{ class: ('expanded' if expanded) } +%section.qa-variables-settings.settings.no-animate#js-cicd-variables-settings{ class: ('expanded' if expanded), data: { qa_selector: 'variables_settings_content' } } .settings-header = render 'ci/variables/header', expanded: expanded .settings-content diff --git a/app/views/projects/tags/show.html.haml b/app/views/projects/tags/show.html.haml index 02f6ef02843..78cce58938e 100644 --- a/app/views/projects/tags/show.html.haml +++ b/app/views/projects/tags/show.html.haml @@ -4,7 +4,7 @@ - page_title @tag.name, s_('TagsPage|Tags') %div{ class: container_class } - .top-area.multi-line + .top-area.multi-line.flex-wrap .nav-text .title %span.item-title.ref-name diff --git a/app/views/projects/triggers/_trigger.html.haml b/app/views/projects/triggers/_trigger.html.haml index 31a598ccd5e..9899cf9c6de 100644 --- a/app/views/projects/triggers/_trigger.html.haml +++ b/app/views/projects/triggers/_trigger.html.haml @@ -33,10 +33,7 @@ Never %td.text-right.trigger-actions - - take_ownership_confirmation = "By taking ownership you will bind this trigger to your user account. With this the trigger will have access to all your projects as if it was you. Are you sure?" - revoke_trigger_confirmation = "By revoking a trigger you will break any processes making use of it. Are you sure?" - - if trigger.owner != current_user && can?(current_user, :manage_trigger, trigger) - = link_to 'Take ownership', take_ownership_project_trigger_path(@project, trigger), data: { confirm: take_ownership_confirmation }, method: :post, class: "btn btn-default btn-sm btn-trigger-take-ownership" - if can?(current_user, :admin_trigger, trigger) = link_to edit_project_trigger_path(@project, trigger), method: :get, title: "Edit", class: "btn btn-default btn-sm" do %i.fa.fa-pencil diff --git a/app/views/projects/wikis/_form.html.haml b/app/views/projects/wikis/_form.html.haml index 5bb69563b51..66a614b0197 100644 --- a/app/views/projects/wikis/_form.html.haml +++ b/app/views/projects/wikis/_form.html.haml @@ -51,6 +51,6 @@ .float-right = link_to _("Cancel"), project_wiki_path(@project, @page), class: 'btn btn-cancel btn-grouped' - else - = f.submit s_("Wiki|Create page"), class: 'btn-success btn qa-create-page-button' + = f.submit s_("Wiki|Create page"), class: 'btn-success btn qa-create-page-button rspec-create-page-button' .float-right = link_to _("Cancel"), project_wiki_path(@project, :home), class: 'btn btn-cancel' diff --git a/app/views/search/_category.html.haml b/app/views/search/_category.html.haml index ee7d89a9bd8..18613ff4c16 100644 --- a/app/views/search/_category.html.haml +++ b/app/views/search/_category.html.haml @@ -12,7 +12,7 @@ %ul.nav-links.search-filter.scrolling-tabs.nav.nav-tabs - if @project - if project_search_tabs?(:blobs) - %li{ class: active_when(@scope == 'blobs') } + %li{ class: active_when(@scope == 'blobs'), data: { qa_selector: 'code_tab' } } = link_to search_filter_path(scope: 'blobs') do = _("Code") %span.badge.badge-pill diff --git a/app/views/search/results/_blob_data.html.haml b/app/views/search/results/_blob_data.html.haml index 143e9f91ca3..36b6ea7bd37 100644 --- a/app/views/search/results/_blob_data.html.haml +++ b/app/views/search/results/_blob_data.html.haml @@ -1,10 +1,10 @@ -.blob-result +.blob-result{ data: { qa_selector: 'result_item_content' } } .file-holder - .js-file-title.file-title + .js-file-title.file-title{ data: { qa_selector: 'file_title_content' } } = link_to blob_link do %i.fa.fa-file %strong = search_blob_title(project, file_name) - if blob.data - .file-content.code.term + .file-content.code.term{ data: { qa_selector: 'file_text_content' } } = render 'shared/file_highlight', blob: blob, first_line_number: blob.startline diff --git a/app/views/shared/_label_row.html.haml b/app/views/shared/_label_row.html.haml index af11ce94ec5..b05d903fabe 100644 --- a/app/views/shared/_label_row.html.haml +++ b/app/views/shared/_label_row.html.haml @@ -1,7 +1,7 @@ - force_priority = local_assigns.fetch(:force_priority, false) - subject_or_group_defined = defined?(@project) || defined?(@group) -- show_label_issues_link = subject_or_group_defined && show_label_issuables_link?(label, :issues, project: @project) -- show_label_merge_requests_link = subject_or_group_defined && show_label_issuables_link?(label, :merge_requests, project: @project) +- show_label_issues_link = subject_or_group_defined && show_label_issuables_link?(label, :issues) +- show_label_merge_requests_link = subject_or_group_defined && show_label_issuables_link?(label, :merge_requests) .label-name = render_label(label, tooltip: false) diff --git a/app/views/shared/_remote_mirror_update_button.html.haml b/app/views/shared/_remote_mirror_update_button.html.haml index 8da2ae5111a..4b39c8b06e9 100644 --- a/app/views/shared/_remote_mirror_update_button.html.haml +++ b/app/views/shared/_remote_mirror_update_button.html.haml @@ -2,5 +2,5 @@ %button.btn.disabled{ type: 'button', data: { toggle: 'tooltip', container: 'body' }, title: _('Updating') } = icon("refresh spin") - elsif remote_mirror.enabled? - = link_to update_now_project_mirror_path(@project, sync_remote: true), method: :post, class: "btn qa-update-now-button", data: { toggle: 'tooltip', container: 'body' }, title: _('Update now') do + = link_to update_now_project_mirror_path(@project, sync_remote: true), method: :post, class: "btn qa-update-now-button rspec-update-now-button", data: { toggle: 'tooltip', container: 'body' }, title: _('Update now') do = icon("refresh") diff --git a/app/views/shared/_sidebar_toggle_button.html.haml b/app/views/shared/_sidebar_toggle_button.html.haml index d499bc0a253..c7546073e5c 100644 --- a/app/views/shared/_sidebar_toggle_button.html.haml +++ b/app/views/shared/_sidebar_toggle_button.html.haml @@ -1,4 +1,4 @@ -%a.toggle-sidebar-button.js-toggle-sidebar.qa-toggle-sidebar{ role: "button", type: "button", title: "Toggle sidebar" } +%a.toggle-sidebar-button.js-toggle-sidebar.qa-toggle-sidebar.rspec-toggle-sidebar{ role: "button", type: "button", title: "Toggle sidebar" } = sprite_icon('angle-double-left', css_class: 'icon-angle-double-left') = sprite_icon('angle-double-right', css_class: 'icon-angle-double-right') %span.collapse-text= _("Collapse sidebar") diff --git a/app/views/shared/form_elements/_description.html.haml b/app/views/shared/form_elements/_description.html.haml index b11cb8a3076..be78fd0ccfb 100644 --- a/app/views/shared/form_elements/_description.html.haml +++ b/app/views/shared/form_elements/_description.html.haml @@ -15,7 +15,7 @@ = render layout: 'projects/md_preview', locals: { url: preview_url, referenced_users: true } do = render 'projects/zen', f: form, attr: :description, - classes: 'note-textarea qa-issuable-form-description', + classes: 'note-textarea qa-issuable-form-description rspec-issuable-form-description', placeholder: "Write a comment or drag your files here…", supports_quick_actions: supports_quick_actions = render 'shared/notes/hints', supports_quick_actions: supports_quick_actions diff --git a/app/views/shared/issuable/_sort_dropdown.html.haml b/app/views/shared/issuable/_sort_dropdown.html.haml index 403e001bfe8..df0523595f5 100644 --- a/app/views/shared/issuable/_sort_dropdown.html.haml +++ b/app/views/shared/issuable/_sort_dropdown.html.haml @@ -1,7 +1,7 @@ - sort_value = @sort - sort_title = issuable_sort_option_title(sort_value) - viewing_issues = controller.controller_name == 'issues' || controller.action_name == 'issues' -- manual_sorting = viewing_issues && controller.controller_name != 'dashboard' && Feature.enabled?(:manual_sorting) +- manual_sorting = viewing_issues && controller.controller_name != 'dashboard' && Feature.enabled?(:manual_sorting, default_enabled: true) .dropdown.inline.prepend-left-10.issue-sort-dropdown .btn-group{ role: 'group' } diff --git a/app/views/shared/notes/_hints.html.haml b/app/views/shared/notes/_hints.html.haml index fae7d6526e8..72ede50dd8c 100644 --- a/app/views/shared/notes/_hints.html.haml +++ b/app/views/shared/notes/_hints.html.haml @@ -1,14 +1,13 @@ - supports_quick_actions = local_assigns.fetch(:supports_quick_actions, false) .comment-toolbar.clearfix .toolbar-text - = link_to _('Markdown'), help_page_path('user/markdown'), target: '_blank', tabindex: -1 + - md_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer" tabindex="-1">'.html_safe % { url: help_page_path('user/markdown') } + - actions_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer" tabindex="-1">'.html_safe % { url: help_page_path('user/project/quick_actions') } + - link_end = '</a>'.html_safe - if supports_quick_actions - and - = link_to _('quick actions'), help_page_path('user/project/quick_actions'), target: '_blank', tabindex: -1 - are + = s_('Editor|%{mdLinkStart}Markdown%{mdLinkEnd} and %{actionsLinkStart}quick actions%{actionsLinkEnd} are supported').html_safe % { mdLinkStart: md_link_start, mdLinkEnd: link_end, actionsLinkStart: actions_link_start, actionsLinkEnd: link_end } - else - is - supported + = s_('Editor|%{mdLinkStart}Markdown is supported%{mdLinkEnd}').html_safe % { mdLinkStart: md_link_start, mdLinkEnd: link_end } %span.uploading-container %span.uploading-progress-container.hide diff --git a/app/views/shared/projects/_project.html.haml b/app/views/shared/projects/_project.html.haml index c4d1bdad2c4..f40a9cffb29 100644 --- a/app/views/shared/projects/_project.html.haml +++ b/app/views/shared/projects/_project.html.haml @@ -89,4 +89,6 @@ %span.icon-wrapper.pipeline-status = render 'ci/status/icon', status: project.commit.last_pipeline.detailed_status(current_user), type: 'commit', tooltip_placement: 'top', path: pipeline_path .updated-note - %span #{_('Updated')} #{updated_tooltip} + %span + = _('Updated') + = updated_tooltip diff --git a/app/workers/background_migration_worker.rb b/app/workers/background_migration_worker.rb index 688b600649a..b83412b5e6e 100644 --- a/app/workers/background_migration_worker.rb +++ b/app/workers/background_migration_worker.rb @@ -76,8 +76,6 @@ class BackgroundMigrationWorker # class_name - The name of the background migration that we might want to # run. def healthy_database? - return true unless Gitlab::Database.postgresql? - !Postgresql::ReplicationSlot.lag_too_great? end diff --git a/app/workers/cluster_configure_worker.rb b/app/workers/cluster_configure_worker.rb index 6f64b7ea0ab..b0e551d4e03 100644 --- a/app/workers/cluster_configure_worker.rb +++ b/app/workers/cluster_configure_worker.rb @@ -5,10 +5,6 @@ class ClusterConfigureWorker include ClusterQueue def perform(cluster_id) - Clusters::Cluster.managed.find_by_id(cluster_id).try do |cluster| - if cluster.project_type? - Clusters::RefreshService.create_or_update_namespaces_for_cluster(cluster) - end - end + # Scheduled for removal in https://gitlab.com/gitlab-org/gitlab-ce/issues/59319 end end diff --git a/app/workers/cluster_project_configure_worker.rb b/app/workers/cluster_project_configure_worker.rb index 497e57c0d0b..8f48eca4d86 100644 --- a/app/workers/cluster_project_configure_worker.rb +++ b/app/workers/cluster_project_configure_worker.rb @@ -5,8 +5,6 @@ class ClusterProjectConfigureWorker include ClusterQueue def perform(project_id) - project = Project.find(project_id) - - ::Clusters::RefreshService.create_or_update_namespaces_for_project(project) + # Scheduled for removal in https://gitlab.com/gitlab-org/gitlab-ce/issues/59319 end end diff --git a/bin/secpick b/bin/secpick index d01304285b6..8a61356a088 100755 --- a/bin/secpick +++ b/bin/secpick @@ -45,7 +45,7 @@ module Secpick def git_commands ["git fetch #{@options[:remote]} #{stable_branch}", - "git checkout -B #{source_branch} #{@options[:remote]}/#{stable_branch}", + "git checkout -B #{source_branch} #{@options[:remote]}/#{stable_branch} --no-track", "git cherry-pick #{@options[:sha]}", "git push #{@options[:remote]} #{source_branch}", "git checkout #{original_branch}"] diff --git a/changelogs/unreleased/11090-export-design-management-lfs-data.yml b/changelogs/unreleased/11090-export-design-management-lfs-data.yml new file mode 100644 index 00000000000..36b773124d7 --- /dev/null +++ b/changelogs/unreleased/11090-export-design-management-lfs-data.yml @@ -0,0 +1,5 @@ +--- +title: Add support for exporting repository type data for LFS objects +merge_request: 30830 +author: +type: changed diff --git a/changelogs/unreleased/19186-redirect-wiki-git-route-to-wiki.yml b/changelogs/unreleased/19186-redirect-wiki-git-route-to-wiki.yml new file mode 100644 index 00000000000..705621d06f7 --- /dev/null +++ b/changelogs/unreleased/19186-redirect-wiki-git-route-to-wiki.yml @@ -0,0 +1,5 @@ +--- +title: Redirect from a project wiki git route to the project wiki home +merge_request: 31085 +author: +type: added diff --git a/changelogs/unreleased/32495-improve-slack-notification-on-pipeline-status.yml b/changelogs/unreleased/32495-improve-slack-notification-on-pipeline-status.yml new file mode 100644 index 00000000000..b7b39303c2e --- /dev/null +++ b/changelogs/unreleased/32495-improve-slack-notification-on-pipeline-status.yml @@ -0,0 +1,5 @@ +--- +title: Improve pipeline status Slack notifications +merge_request: 27683 +author: +type: added diff --git a/changelogs/unreleased/48717-rate-limit-raw-controller-show.yml b/changelogs/unreleased/48717-rate-limit-raw-controller-show.yml new file mode 100644 index 00000000000..38ee95a7553 --- /dev/null +++ b/changelogs/unreleased/48717-rate-limit-raw-controller-show.yml @@ -0,0 +1,5 @@ +--- +title: Add Rate Request Limiter to RawController#show endpoint +merge_request: 30635 +author: +type: added diff --git a/changelogs/unreleased/56100-make-quick-action-commands-applied-banner-more-useful.yml b/changelogs/unreleased/56100-make-quick-action-commands-applied-banner-more-useful.yml new file mode 100644 index 00000000000..a2fa07c6ed2 --- /dev/null +++ b/changelogs/unreleased/56100-make-quick-action-commands-applied-banner-more-useful.yml @@ -0,0 +1,5 @@ +--- +title: Make quick action commands applied banner more useful +merge_request: 26672 +author: Jacopo Beschi @jacopo-beschi +type: added diff --git a/changelogs/unreleased/59325-units-are-not-shown-on-the-performance-dashboard-2.yml b/changelogs/unreleased/59325-units-are-not-shown-on-the-performance-dashboard-2.yml new file mode 100644 index 00000000000..38cfa0f273e --- /dev/null +++ b/changelogs/unreleased/59325-units-are-not-shown-on-the-performance-dashboard-2.yml @@ -0,0 +1,5 @@ +--- +title: 'fix: updates to include units for the y axis label' +merge_request: 30330 +author: +type: fixed diff --git a/changelogs/unreleased/61787-the-colour-selector-for-broadcast-messages-should-provide-a-few-default-options-with-descriptive-labels-like.yml b/changelogs/unreleased/61787-the-colour-selector-for-broadcast-messages-should-provide-a-few-default-options-with-descriptive-labels-like.yml new file mode 100644 index 00000000000..ec6e9c5aff8 --- /dev/null +++ b/changelogs/unreleased/61787-the-colour-selector-for-broadcast-messages-should-provide-a-few-default-options-with-descriptive-labels-like.yml @@ -0,0 +1,5 @@ +--- +title: add color selector to broadcast messages form +merge_request: 30988 +author: +type: other diff --git a/changelogs/unreleased/63547-add-system-notes-for-when-a-zoom-call-was-added-removed-from-an-issue.yml b/changelogs/unreleased/63547-add-system-notes-for-when-a-zoom-call-was-added-removed-from-an-issue.yml new file mode 100644 index 00000000000..387c01dc135 --- /dev/null +++ b/changelogs/unreleased/63547-add-system-notes-for-when-a-zoom-call-was-added-removed-from-an-issue.yml @@ -0,0 +1,5 @@ +--- +title: Add system notes for when a Zoom call was added/removed from an issue +merge_request: 30857 +author: Jacopo Beschi @jacopo-beschi +type: added diff --git a/changelogs/unreleased/63568-access-email-notifications-custom-email.yml b/changelogs/unreleased/63568-access-email-notifications-custom-email.yml new file mode 100644 index 00000000000..ece6442d7cf --- /dev/null +++ b/changelogs/unreleased/63568-access-email-notifications-custom-email.yml @@ -0,0 +1,5 @@ +--- +title: Respect group notification email when sending group access notifications +merge_request: 31089 +author: +type: fixed diff --git a/changelogs/unreleased/63730-fix-500-status-labels-pd.yml b/changelogs/unreleased/63730-fix-500-status-labels-pd.yml new file mode 100644 index 00000000000..a1e2ae0e5df --- /dev/null +++ b/changelogs/unreleased/63730-fix-500-status-labels-pd.yml @@ -0,0 +1,5 @@ +--- +title: Fix admin labels page when there are invalid records +merge_request: 30885 +author: +type: fixed diff --git a/changelogs/unreleased/64180-membersfinder-contains-slow-database-query-with-or-conditions.yml b/changelogs/unreleased/64180-membersfinder-contains-slow-database-query-with-or-conditions.yml new file mode 100644 index 00000000000..f86c63a15b6 --- /dev/null +++ b/changelogs/unreleased/64180-membersfinder-contains-slow-database-query-with-or-conditions.yml @@ -0,0 +1,5 @@ +--- +title: Improve MembersFinder query performance using UNION +merge_request: 30451 +author: Jacopo Beschi @jacopo-beschi +type: performance diff --git a/changelogs/unreleased/64190-add-mr-form.yml b/changelogs/unreleased/64190-add-mr-form.yml new file mode 100644 index 00000000000..08340d01fd8 --- /dev/null +++ b/changelogs/unreleased/64190-add-mr-form.yml @@ -0,0 +1,5 @@ +--- +title: Add MR form to Visual Review (EE) runtime configuration +merge_request: 30481 +author: +type: changed diff --git a/changelogs/unreleased/64257-warden_set_user_fix.yml b/changelogs/unreleased/64257-warden_set_user_fix.yml new file mode 100644 index 00000000000..7b6818876fb --- /dev/null +++ b/changelogs/unreleased/64257-warden_set_user_fix.yml @@ -0,0 +1,5 @@ +--- +title: Ensure Warden triggers after_authentication callback +merge_request: 31138 +author: +type: fixed diff --git a/changelogs/unreleased/64746-Commit-authors-avatar-sretched-in-commit-view-if-no-image-is-loaded.yml b/changelogs/unreleased/64746-Commit-authors-avatar-sretched-in-commit-view-if-no-image-is-loaded.yml new file mode 100644 index 00000000000..fb0f4cedc62 --- /dev/null +++ b/changelogs/unreleased/64746-Commit-authors-avatar-sretched-in-commit-view-if-no-image-is-loaded.yml @@ -0,0 +1,5 @@ +--- +title: Fixed distorted avatars when resource not reachable +merge_request: 30904 +author: Marc Schwede +type: other diff --git a/changelogs/unreleased/64763-fix-tags-page-layout.yml b/changelogs/unreleased/64763-fix-tags-page-layout.yml new file mode 100644 index 00000000000..db6b1f31506 --- /dev/null +++ b/changelogs/unreleased/64763-fix-tags-page-layout.yml @@ -0,0 +1,5 @@ +--- +title: Fix tag page layout +merge_request: +author: +type: fixed diff --git a/changelogs/unreleased/64972-fix-unicorn-workers-metric.yml b/changelogs/unreleased/64972-fix-unicorn-workers-metric.yml new file mode 100644 index 00000000000..f80111f0bd9 --- /dev/null +++ b/changelogs/unreleased/64972-fix-unicorn-workers-metric.yml @@ -0,0 +1,5 @@ +--- +title: Fix pid discovery for Unicorn processes in `PidProvider` +merge_request: 31056 +author: +type: fixed diff --git a/changelogs/unreleased/65019-auto-devops-dind-tls-fix.yml b/changelogs/unreleased/65019-auto-devops-dind-tls-fix.yml new file mode 100644 index 00000000000..3eea3e551ce --- /dev/null +++ b/changelogs/unreleased/65019-auto-devops-dind-tls-fix.yml @@ -0,0 +1,5 @@ +--- +title: Set DOCKER_TLS_CERTDIR in Auto Dev-Ops CI template to fix jobs using Docker-in-Docker +merge_request: 31078 +author: +type: fixed diff --git a/changelogs/unreleased/65019-job-templates-dind-tls-fix.yml b/changelogs/unreleased/65019-job-templates-dind-tls-fix.yml new file mode 100644 index 00000000000..c7c02486d61 --- /dev/null +++ b/changelogs/unreleased/65019-job-templates-dind-tls-fix.yml @@ -0,0 +1,5 @@ +--- +title: Set DOCKER_TLS_CERTDIR in CI job templates to fix Docker-in-Docker service +merge_request: 31080 +author: +type: fixed diff --git a/changelogs/unreleased/65088-incorrect-message-interpolation-on-project-listing.yml b/changelogs/unreleased/65088-incorrect-message-interpolation-on-project-listing.yml new file mode 100644 index 00000000000..dd74b8443bc --- /dev/null +++ b/changelogs/unreleased/65088-incorrect-message-interpolation-on-project-listing.yml @@ -0,0 +1,5 @@ +--- +title: Fix incorrect use of message interpolation +merge_request: 31121 +author: +type: fixed diff --git a/changelogs/unreleased/ab-add-index-on-environments.yml b/changelogs/unreleased/ab-add-index-on-environments.yml new file mode 100644 index 00000000000..6c7641912f4 --- /dev/null +++ b/changelogs/unreleased/ab-add-index-on-environments.yml @@ -0,0 +1,5 @@ +--- +title: Create index on environments by state +merge_request: 31231 +author: +type: performance diff --git a/changelogs/unreleased/ab-count-strategies.yml b/changelogs/unreleased/ab-count-strategies.yml new file mode 100644 index 00000000000..bd95ff45d6f --- /dev/null +++ b/changelogs/unreleased/ab-count-strategies.yml @@ -0,0 +1,5 @@ +--- +title: Use tablesample approximate counting by default. +merge_request: 31048 +author: +type: performance diff --git a/changelogs/unreleased/add-caching-to-archive-endpoint.yml b/changelogs/unreleased/add-caching-to-archive-endpoint.yml new file mode 100644 index 00000000000..770ec16e804 --- /dev/null +++ b/changelogs/unreleased/add-caching-to-archive-endpoint.yml @@ -0,0 +1,5 @@ +--- +title: Return an ETag header for the archive endpoint +merge_request: 30581 +author: +type: added diff --git a/changelogs/unreleased/add-git-blame-api.yml b/changelogs/unreleased/add-git-blame-api.yml new file mode 100644 index 00000000000..cdb77041433 --- /dev/null +++ b/changelogs/unreleased/add-git-blame-api.yml @@ -0,0 +1,5 @@ +--- +title: Add git blame to GitLab API +merge_request: 30675 +author: Oleg Zubchenko +type: added diff --git a/changelogs/unreleased/add-outbound-requests-whitelist-for-local-networks.yml b/changelogs/unreleased/add-outbound-requests-whitelist-for-local-networks.yml new file mode 100644 index 00000000000..9b50175f536 --- /dev/null +++ b/changelogs/unreleased/add-outbound-requests-whitelist-for-local-networks.yml @@ -0,0 +1,5 @@ +--- +title: Add Outbound requests whitelist for local networks +merge_request: 30350 +author: Istvan Szalai +type: added diff --git a/changelogs/unreleased/ce-xanf-add-links-to-admin-area.yml b/changelogs/unreleased/ce-xanf-add-links-to-admin-area.yml new file mode 100644 index 00000000000..9eb692c948b --- /dev/null +++ b/changelogs/unreleased/ce-xanf-add-links-to-admin-area.yml @@ -0,0 +1,5 @@ +--- +title: Add links to relevant configuration areas in admin area overview +merge_request: 29306 +author: +type: added diff --git a/changelogs/unreleased/delete-designs-v2.yml b/changelogs/unreleased/delete-designs-v2.yml new file mode 100644 index 00000000000..a678e4f93b9 --- /dev/null +++ b/changelogs/unreleased/delete-designs-v2.yml @@ -0,0 +1,4 @@ +--- +title: Adds event enum column to DesignsVersions join table +merge_request: 30745 +type: added diff --git a/changelogs/unreleased/dm-submodule-links-nil.yml b/changelogs/unreleased/dm-submodule-links-nil.yml new file mode 100644 index 00000000000..c09ca41d01d --- /dev/null +++ b/changelogs/unreleased/dm-submodule-links-nil.yml @@ -0,0 +1,5 @@ +--- +title: Fix error rendering submodules in MR diffs when there is no .gitmodules +merge_request: 31162 +author: +type: fixed diff --git a/changelogs/unreleased/extract_auto_deploy_into_base_image.yml b/changelogs/unreleased/extract_auto_deploy_into_base_image.yml new file mode 100644 index 00000000000..ff0d1f3bd71 --- /dev/null +++ b/changelogs/unreleased/extract_auto_deploy_into_base_image.yml @@ -0,0 +1,5 @@ +--- +title: Extract Auto DevOps deploy functions into a base image +merge_request: 30404 +author: +type: changed diff --git a/changelogs/unreleased/fj-navbar-searches-usage-ping-counter.yml b/changelogs/unreleased/fj-navbar-searches-usage-ping-counter.yml new file mode 100644 index 00000000000..ab7c1697fd6 --- /dev/null +++ b/changelogs/unreleased/fj-navbar-searches-usage-ping-counter.yml @@ -0,0 +1,5 @@ +--- +title: Added navbar searches usage ping counter +merge_request: 30953 +author: +type: changed diff --git a/changelogs/unreleased/je-separate-namespace-fe.yml b/changelogs/unreleased/je-separate-namespace-fe.yml new file mode 100644 index 00000000000..fb6be071eb6 --- /dev/null +++ b/changelogs/unreleased/je-separate-namespace-fe.yml @@ -0,0 +1,5 @@ +--- +title: Update namespace label for GitLab-managed clusters +merge_request: 30935 +author: +type: added diff --git a/changelogs/unreleased/jivanvl-add-chart-empty-state.yml b/changelogs/unreleased/jivanvl-add-chart-empty-state.yml new file mode 100644 index 00000000000..7b81ee82582 --- /dev/null +++ b/changelogs/unreleased/jivanvl-add-chart-empty-state.yml @@ -0,0 +1,5 @@ +--- +title: Add empty chart component +merge_request: 30682 +author: +type: fixed diff --git a/changelogs/unreleased/label-descr-push-opts.yml b/changelogs/unreleased/label-descr-push-opts.yml new file mode 100644 index 00000000000..9b01cfdaed2 --- /dev/null +++ b/changelogs/unreleased/label-descr-push-opts.yml @@ -0,0 +1,5 @@ +--- +title: Support setting of merge request title and description using git push options +merge_request: 31068 +author: +type: added diff --git a/changelogs/unreleased/mc-feature-manual-job-variables.yml b/changelogs/unreleased/mc-feature-manual-job-variables.yml new file mode 100644 index 00000000000..a71cabfe303 --- /dev/null +++ b/changelogs/unreleased/mc-feature-manual-job-variables.yml @@ -0,0 +1,5 @@ +--- +title: Allow specifying variables when running manual jobs +merge_request: 30485 +author: +type: added diff --git a/changelogs/unreleased/mh-editor-indents.yml b/changelogs/unreleased/mh-editor-indents.yml new file mode 100644 index 00000000000..a282c0f505d --- /dev/null +++ b/changelogs/unreleased/mh-editor-indents.yml @@ -0,0 +1,5 @@ +--- +title: Markdown editors now have indentation shortcuts and auto-indentation +merge_request: 28914 +author: +type: added diff --git a/changelogs/unreleased/optimise-import-performance.yml b/changelogs/unreleased/optimise-import-performance.yml new file mode 100644 index 00000000000..c63f44d5109 --- /dev/null +++ b/changelogs/unreleased/optimise-import-performance.yml @@ -0,0 +1,5 @@ +--- +title: Optimise import performance +merge_request: 31045 +author: +type: performance diff --git a/changelogs/unreleased/remove-line-profile-from-performance-bar.yml b/changelogs/unreleased/remove-line-profile-from-performance-bar.yml new file mode 100644 index 00000000000..c1c7450fbbd --- /dev/null +++ b/changelogs/unreleased/remove-line-profile-from-performance-bar.yml @@ -0,0 +1,5 @@ +--- +title: Remove line profiler from performance bar +merge_request: +author: +type: removed diff --git a/changelogs/unreleased/remove_deployment_metrics_deployment_platform_fallback.yml b/changelogs/unreleased/remove_deployment_metrics_deployment_platform_fallback.yml new file mode 100644 index 00000000000..d32cbd1d8e0 --- /dev/null +++ b/changelogs/unreleased/remove_deployment_metrics_deployment_platform_fallback.yml @@ -0,0 +1,6 @@ +--- +title: Remove incorrect fallback when determining which cluster to use when retrieving + MR performance metrics +merge_request: 31126 +author: +type: changed diff --git a/changelogs/unreleased/security-60551-fix-upload-scope.yml b/changelogs/unreleased/security-60551-fix-upload-scope.yml new file mode 100644 index 00000000000..7d7096833a7 --- /dev/null +++ b/changelogs/unreleased/security-60551-fix-upload-scope.yml @@ -0,0 +1,5 @@ +--- +title: Queries for Upload should be scoped by model +merge_request: +author: +type: security diff --git a/changelogs/unreleased/sh-add-cmaps-for-pdfjs.yml b/changelogs/unreleased/sh-add-cmaps-for-pdfjs.yml new file mode 100644 index 00000000000..f4686484e33 --- /dev/null +++ b/changelogs/unreleased/sh-add-cmaps-for-pdfjs.yml @@ -0,0 +1,5 @@ +--- +title: Make pdf.js render CJK characters +merge_request: 31220 +author: +type: fixed diff --git a/changelogs/unreleased/sh-add-rugged-to-peek.yml b/changelogs/unreleased/sh-add-rugged-to-peek.yml new file mode 100644 index 00000000000..8a030f3daf2 --- /dev/null +++ b/changelogs/unreleased/sh-add-rugged-to-peek.yml @@ -0,0 +1,5 @@ +--- +title: Add Rugged calls to performance bar +merge_request: 30983 +author: +type: other diff --git a/changelogs/unreleased/sh-fix-gitaly-access-control.yml b/changelogs/unreleased/sh-fix-gitaly-access-control.yml new file mode 100644 index 00000000000..bdd33f3ff45 --- /dev/null +++ b/changelogs/unreleased/sh-fix-gitaly-access-control.yml @@ -0,0 +1,5 @@ +--- +title: Fix exception handling in Gitaly autodetection +merge_request: 31285 +author: +type: fixed diff --git a/changelogs/unreleased/sh-fix-pdfjs-page-ordering.yml b/changelogs/unreleased/sh-fix-pdfjs-page-ordering.yml new file mode 100644 index 00000000000..84161c51905 --- /dev/null +++ b/changelogs/unreleased/sh-fix-pdfjs-page-ordering.yml @@ -0,0 +1,5 @@ +--- +title: Fix pdf.js rendering pages in the wrong order +merge_request: 31222 +author: +type: fixed diff --git a/changelogs/unreleased/sh-ignore-git-errors-delete-project.yml b/changelogs/unreleased/sh-ignore-git-errors-delete-project.yml new file mode 100644 index 00000000000..f5e2147f00e --- /dev/null +++ b/changelogs/unreleased/sh-ignore-git-errors-delete-project.yml @@ -0,0 +1,5 @@ +--- +title: Ignore Gitaly errors if cache flushing fails on project destruction +merge_request: 31164 +author: +type: fixed diff --git a/changelogs/unreleased/sh-support-docker-oci-images.yml b/changelogs/unreleased/sh-support-docker-oci-images.yml new file mode 100644 index 00000000000..2dcf980fa50 --- /dev/null +++ b/changelogs/unreleased/sh-support-docker-oci-images.yml @@ -0,0 +1,5 @@ +--- +title: Support Docker OCI images +merge_request: 31127 +author: +type: fixed diff --git a/changelogs/unreleased/sh-update-rouge-3-7-0.yml b/changelogs/unreleased/sh-update-rouge-3-7-0.yml new file mode 100644 index 00000000000..6828f48863c --- /dev/null +++ b/changelogs/unreleased/sh-update-rouge-3-7-0.yml @@ -0,0 +1,5 @@ +--- +title: Update rouge to v3.7.0 +merge_request: 31254 +author: +type: other diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index 0e78980350f..dd53127ac2c 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -400,6 +400,15 @@ production: &base # path: shared/registry # issuer: gitlab-issuer + # Add notification settings if you plan to use Geo Replication for the registry + # notifications: + # - name: geo_event + # url: https://example.com/api/v4/container_registry_event/events + # timeout: 2s + # threshold: 5 + # backoff: 1s + # headers: + # Authorization: secret_phrase ## Error Reporting and Logging with Sentry sentry: diff --git a/config/initializers/0_license.rb b/config/initializers/0_license.rb index f750022dfdf..19c71c34904 100644 --- a/config/initializers/0_license.rb +++ b/config/initializers/0_license.rb @@ -10,7 +10,7 @@ Gitlab.ee do end # Needed to run migration - if ActiveRecord::Base.connected? && ActiveRecord::Base.connection.data_source_exists?('licenses') + if ActiveRecord::Base.connected? && ActiveRecord::Base.connection.table_exists?('licenses') message = LicenseHelper.license_message(signed_in: true, is_admin: true, in_html: false) if ::License.block_changes? && message.present? warn "WARNING: #{message}" diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index 494c4dd1f93..32fec7c3d22 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -259,6 +259,7 @@ Settings.registry['key'] ||= nil Settings.registry['issuer'] ||= nil Settings.registry['host_port'] ||= [Settings.registry['host'], Settings.registry['port']].compact.join(':') Settings.registry['path'] = Settings.absolute(Settings.registry['path'] || File.join(Settings.shared['path'], 'registry')) +Settings.registry['notifications'] ||= [] # # Error Reporting and Logging with Sentry diff --git a/config/initializers/active_record_migration.rb b/config/initializers/active_record_migration.rb deleted file mode 100644 index 04c06be7834..00000000000 --- a/config/initializers/active_record_migration.rb +++ /dev/null @@ -1,10 +0,0 @@ -require 'active_record/migration' - -module ActiveRecord - class Migration - # data_source_exists? is not available in 4.2.10, table_exists deprecated in 5.0 - def table_exists?(table_name) - ActiveRecord::Base.connection.data_source_exists?(table_name) - end - end -end diff --git a/config/initializers/load_balancing.rb b/config/initializers/load_balancing.rb index 029c0ff4277..a49bcbe1f96 100644 --- a/config/initializers/load_balancing.rb +++ b/config/initializers/load_balancing.rb @@ -3,7 +3,7 @@ # We need to run this initializer after migrations are done so it doesn't fail on CI Gitlab.ee do - if ActiveRecord::Base.connected? && ActiveRecord::Base.connection.data_source_exists?('licenses') + if ActiveRecord::Base.connected? && ActiveRecord::Base.connection.table_exists?('licenses') if Gitlab::Database::LoadBalancing.enable? Gitlab::Database.disable_prepared_statements diff --git a/config/initializers/octokit.rb b/config/initializers/octokit.rb new file mode 100644 index 00000000000..b3749258ec5 --- /dev/null +++ b/config/initializers/octokit.rb @@ -0,0 +1 @@ +Octokit.middleware.insert_after Octokit::Middleware::FollowRedirects, Gitlab::Octokit::Middleware diff --git a/config/initializers/peek.rb b/config/initializers/peek.rb index 1ffd133239d..4a2b7931f30 100644 --- a/config/initializers/peek.rb +++ b/config/initializers/peek.rb @@ -1,43 +1,13 @@ -Rails.application.config.peek.adapter = :redis, { client: ::Redis.new(Gitlab::Redis::Cache.params) } - -Peek.into Peek::Views::Host +require 'peek/adapters/redis' -if Gitlab::Database.postgresql? - require 'peek-pg' - PEEK_DB_CLIENT = ::PG::Connection - PEEK_DB_VIEW = Peek::Views::PG +Peek::Adapters::Redis.prepend ::Gitlab::PerformanceBar::RedisAdapterWhenPeekEnabled - # Remove once we have https://github.com/peek/peek-pg/pull/10 - module ::Peek::PGInstrumented - def exec_params(*args) - start = Time.now - super(*args) - ensure - duration = (Time.now - start) - PEEK_DB_CLIENT.query_time.update { |value| value + duration } - PEEK_DB_CLIENT.query_count.update { |value| value + 1 } - end - end -else - raise "Unsupported database adapter for peek!" -end +Rails.application.config.peek.adapter = :redis, { client: ::Redis.new(Gitlab::Redis::Cache.params) } -Peek.into PEEK_DB_VIEW +Peek.into Peek::Views::Host +Peek.into Peek::Views::ActiveRecord Peek.into Peek::Views::Gitaly -Peek.into Peek::Views::Rblineprof Peek.into Peek::Views::RedisDetailed +Peek.into Peek::Views::Rugged Peek.into Peek::Views::GC Peek.into Peek::Views::Tracing if Labkit::Tracing.tracing_url_enabled? - -# rubocop:disable Naming/ClassAndModuleCamelCase -class PEEK_DB_CLIENT - class << self - attr_accessor :query_details - end - self.query_details = Concurrent::Array.new -end - -PEEK_DB_VIEW.prepend ::Gitlab::PerformanceBar::PeekQueryTracker - -require 'peek/adapters/redis' -Peek::Adapters::Redis.prepend ::Gitlab::PerformanceBar::RedisAdapterWhenPeekEnabled diff --git a/config/initializers/sidekiq.rb b/config/initializers/sidekiq.rb index 166fb9b6916..9f88fb9895b 100644 --- a/config/initializers/sidekiq.rb +++ b/config/initializers/sidekiq.rb @@ -33,6 +33,7 @@ Sidekiq.configure_server do |config| config.redis = queues_config_hash config.server_middleware do |chain| + chain.add Gitlab::SidekiqMiddleware::Metrics if Settings.monitoring.sidekiq_exporter chain.add Gitlab::SidekiqMiddleware::ArgumentsLogger if ENV['SIDEKIQ_LOG_ARGUMENTS'] && !enable_json_logs chain.add Gitlab::SidekiqMiddleware::MemoryKiller if ENV['SIDEKIQ_MEMORY_KILLER_MAX_RSS'] chain.add Gitlab::SidekiqMiddleware::RequestStoreMiddleware unless ENV['SIDEKIQ_REQUEST_STORE'] == '0' diff --git a/config/prometheus/cluster_metrics.yml b/config/prometheus/cluster_metrics.yml index 3df76b0974f..f2a41e4c337 100644 --- a/config/prometheus/cluster_metrics.yml +++ b/config/prometheus/cluster_metrics.yml @@ -2,12 +2,12 @@ priority: 1 metrics: - title: "CPU Usage" - y_label: "CPU" + y_label: "CPU (cores)" required_metrics: ['container_cpu_usage_seconds_total'] weight: 1 queries: - query_range: 'avg(sum(rate(container_cpu_usage_seconds_total{id="/"}[15m])) by (job)) without (job)' - label: Usage + label: Usage (cores) unit: "cores" appearance: line: @@ -15,7 +15,7 @@ area: opacity: 0 - query_range: 'sum(kube_pod_container_resource_requests_cpu_cores{kubernetes_namespace="gitlab-managed-apps"})' - label: Requested + label: Requested (cores) unit: "cores" appearance: line: @@ -23,7 +23,7 @@ area: opacity: 0 - query_range: 'sum(kube_node_status_capacity_cpu_cores{kubernetes_namespace="gitlab-managed-apps"})' - label: Capacity + label: Capacity (cores) unit: "cores" appearance: line: @@ -32,12 +32,12 @@ area: opacity: 0 - title: "Memory usage" - y_label: "Memory" + y_label: "Memory (GiB)" required_metrics: ['container_memory_usage_bytes'] weight: 1 queries: - query_range: 'avg(sum(container_memory_usage_bytes{id="/"}) by (job)) without (job) / 2^30' - label: Usage + label: Usage (GiB) unit: "GiB" appearance: line: @@ -45,7 +45,7 @@ area: opacity: 0 - query_range: 'sum(kube_pod_container_resource_requests_memory_bytes{kubernetes_namespace="gitlab-managed-apps"})/2^30' - label: Requested + label: Requested (GiB) unit: "GiB" appearance: line: @@ -53,7 +53,7 @@ area: opacity: 0 - query_range: 'sum(kube_node_status_capacity_memory_bytes{kubernetes_namespace="gitlab-managed-apps"})/2^30' - label: Capacity + label: Capacity (GiB) unit: "GiB" appearance: line: diff --git a/config/prometheus/common_metrics.yml b/config/prometheus/common_metrics.yml index f9ce5a6f365..32475ef8380 100644 --- a/config/prometheus/common_metrics.yml +++ b/config/prometheus/common_metrics.yml @@ -21,16 +21,16 @@ panel_groups: metrics: - id: response_metrics_nginx_ingress_latency_pod_average query_range: 'avg(nginx_upstream_response_msecs_avg{upstream=~"%{kube_namespace}-%{ci_environment_slug}-.*"})' - label: Pod average + label: Pod average (ms) unit: ms - title: "HTTP Error Rate" type: "area-chart" - y_label: "HTTP Errors" + y_label: "HTTP Errors (%)" weight: 1 metrics: - id: response_metrics_nginx_ingress_http_error_rate query_range: 'sum(rate(nginx_upstream_responses_total{status_code="5xx", upstream=~"%{kube_namespace}-%{ci_environment_slug}-.*"}[2m])) / sum(rate(nginx_upstream_responses_total{upstream=~"%{kube_namespace}-%{ci_environment_slug}-.*"}[2m])) * 100' - label: 5xx Errors + label: 5xx Errors (%) unit: "%" # NGINX Ingress metrics for post-0.16.0 versions - group: Response metrics (NGINX Ingress) @@ -52,16 +52,16 @@ panel_groups: metrics: - id: response_metrics_nginx_ingress_16_latency_pod_average query_range: 'sum(rate(nginx_ingress_controller_ingress_upstream_latency_seconds_sum{namespace="%{kube_namespace}",ingress=~".*%{ci_environment_slug}.*"}[2m])) / sum(rate(nginx_ingress_controller_ingress_upstream_latency_seconds_count{namespace="%{kube_namespace}",ingress=~".*%{ci_environment_slug}.*"}[2m])) * 1000' - label: Pod average + label: Pod average (ms) unit: ms - title: "HTTP Error Rate" type: "area-chart" - y_label: "HTTP Errors" + y_label: "HTTP Errors (%)" weight: 1 metrics: - id: response_metrics_nginx_ingress_16_http_error_rate query_range: 'sum(rate(nginx_ingress_controller_requests{status=~"5.*",namespace="%{kube_namespace}",ingress=~".*%{ci_environment_slug}.*"}[2m])) / sum(rate(nginx_ingress_controller_requests{namespace="%{kube_namespace}",ingress=~".*%{ci_environment_slug}.*"}[2m])) * 100' - label: 5xx Errors + label: 5xx Errors (%) unit: "%" - group: Response metrics (HA Proxy) priority: 10 @@ -82,7 +82,7 @@ panel_groups: metrics: - id: response_metrics_ha_proxy_http_error_rate query_range: 'sum(rate(haproxy_frontend_http_responses_total{code="5xx",%{environment_filter}}[2m])) / sum(rate(haproxy_frontend_http_responses_total{%{environment_filter}}[2m]))' - label: HTTP Errors + label: HTTP Errors (%) unit: "%" - group: Response metrics (AWS ELB) priority: 10 @@ -94,7 +94,7 @@ panel_groups: metrics: - id: response_metrics_aws_elb_throughput_requests query_range: 'sum(aws_elb_request_count_sum{%{environment_filter}}) / 60' - label: Total + label: Total (req/sec) unit: req / sec - title: "Latency" type: "area-chart" @@ -103,7 +103,7 @@ panel_groups: metrics: - id: response_metrics_aws_elb_latency_average query_range: 'avg(aws_elb_latency_average{%{environment_filter}}) * 1000' - label: Average + label: Average (ms) unit: ms - title: "HTTP Error Rate" type: "area-chart" @@ -112,7 +112,7 @@ panel_groups: metrics: - id: response_metrics_aws_elb_http_error_rate query_range: 'sum(aws_elb_httpcode_backend_5_xx_sum{%{environment_filter}}) / sum(aws_elb_request_count_sum{%{environment_filter}})' - label: HTTP Errors + label: HTTP Errors (%) unit: "%" - group: Response metrics (NGINX) priority: 10 @@ -133,9 +133,9 @@ panel_groups: metrics: - id: response_metrics_nginx_latency query_range: 'avg(nginx_server_requestMsec{%{environment_filter}})' - label: Upstream + label: Upstream (ms) unit: ms - - title: "HTTP Error Rate" + - title: "HTTP Error Rate (Errors / Sec)" type: "area-chart" y_label: "HTTP 500 Errors / Sec" weight: 1 @@ -149,12 +149,12 @@ panel_groups: panels: - title: "Memory Usage (Total)" type: "area-chart" - y_label: "Total Memory Used" + y_label: "Total Memory Used (GB)" weight: 4 metrics: - id: system_metrics_kubernetes_container_memory_total query_range: 'avg(sum(container_memory_usage_bytes{container_name!="POD",pod_name=~"^%{ci_environment_slug}-(.*)",namespace="%{kube_namespace}"}) by (job)) without (job) /1024/1024/1024' - label: Total + label: Total (GB) unit: GB - title: "Core Usage (Total)" type: "area-chart" @@ -163,25 +163,25 @@ panel_groups: metrics: - id: system_metrics_kubernetes_container_cores_total query_range: 'avg(sum(rate(container_cpu_usage_seconds_total{container_name!="POD",pod_name=~"^%{ci_environment_slug}-(.*)",namespace="%{kube_namespace}"}[15m])) by (job)) without (job)' - label: Total + label: Total (cores) unit: "cores" - title: "Memory Usage (Pod average)" type: "area-chart" - y_label: "Memory Used per Pod" + y_label: "Memory Used per Pod (MB)" weight: 2 metrics: - id: system_metrics_kubernetes_container_memory_average query_range: 'avg(sum(container_memory_usage_bytes{container_name!="POD",pod_name=~"^%{ci_environment_slug}-([^c].*|c([^a]|a([^n]|n([^a]|a([^r]|r[^y])))).*|)-(.*)",namespace="%{kube_namespace}"}) by (job)) without (job) / count(avg(container_memory_usage_bytes{container_name!="POD",pod_name=~"^%{ci_environment_slug}-([^c].*|c([^a]|a([^n]|n([^a]|a([^r]|r[^y])))).*|)-(.*)",namespace="%{kube_namespace}"}) without (job)) /1024/1024' - label: Pod average + label: Pod average (MB) unit: MB - title: "Canary: Memory Usage (Pod Average)" type: "area-chart" - y_label: "Memory Used per Pod" + y_label: "Memory Used per Pod (MB)" weight: 2 metrics: - id: system_metrics_kubernetes_container_memory_average_canary query_range: 'avg(sum(container_memory_usage_bytes{container_name!="POD",pod_name=~"^%{ci_environment_slug}-canary-(.*)",namespace="%{kube_namespace}"}) by (job)) without (job) / count(avg(container_memory_usage_bytes{container_name!="POD",pod_name=~"^%{ci_environment_slug}-canary-(.*)",namespace="%{kube_namespace}"}) without (job)) /1024/1024' - label: Pod average + label: Pod average (MB) unit: MB track: canary - title: "Core Usage (Pod Average)" @@ -191,7 +191,7 @@ panel_groups: metrics: - id: system_metrics_kubernetes_container_core_usage query_range: 'avg(sum(rate(container_cpu_usage_seconds_total{container_name!="POD",pod_name=~"^%{ci_environment_slug}-([^c].*|c([^a]|a([^n]|n([^a]|a([^r]|r[^y])))).*|)-(.*)",namespace="%{kube_namespace}"}[15m])) by (job)) without (job) / count(sum(rate(container_cpu_usage_seconds_total{container_name!="POD",pod_name=~"^%{ci_environment_slug}-([^c].*|c([^a]|a([^n]|n([^a]|a([^r]|r[^y])))).*|)-(.*)",namespace="%{kube_namespace}"}[15m])) by (pod_name))' - label: Pod average + label: Pod average (cores) unit: "cores" - title: "Canary: Core Usage (Pod Average)" type: "area-chart" @@ -200,7 +200,7 @@ panel_groups: metrics: - id: system_metrics_kubernetes_container_core_usage_canary query_range: 'avg(sum(rate(container_cpu_usage_seconds_total{container_name!="POD",pod_name=~"^%{ci_environment_slug}-canary-(.*)",namespace="%{kube_namespace}"}[15m])) by (job)) without (job) / count(sum(rate(container_cpu_usage_seconds_total{container_name!="POD",pod_name=~"^%{ci_environment_slug}-canary-(.*)",namespace="%{kube_namespace}"}[15m])) by (pod_name))' - label: Pod average + label: Pod average (cores) unit: "cores" track: canary - title: "Knative function invocations" diff --git a/config/routes/git_http.rb b/config/routes/git_http.rb index a959d40881b..aac6d418a92 100644 --- a/config/routes/git_http.rb +++ b/config/routes/git_http.rb @@ -34,6 +34,18 @@ scope(path: '*namespace_id/:project_id', end end + # Redirect /group/project.wiki.git to the project wiki + scope(format: true, constraints: { project_id: Gitlab::PathRegex.project_wiki_git_route_regex, format: :git }) do + wiki_redirect = redirect do |params, request| + project_id = params[:project_id].delete_suffix('.wiki') + path = [params[:namespace_id], project_id, 'wikis'].join('/') + path << "?#{request.query_string}" unless request.query_string.blank? + path + end + + get '/', to: wiki_redirect + end + # Redirect /group/project/info/refs to /group/project.git/info/refs scope(constraints: { project_id: Gitlab::PathRegex.project_route_regex }) do # Allow /info/refs, /info/refs?service=git-upload-pack, and diff --git a/config/routes/project.rb b/config/routes/project.rb index c202463dadb..1f632765317 100644 --- a/config/routes/project.rb +++ b/config/routes/project.rb @@ -339,11 +339,7 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do resource :variables, only: [:show, :update] - resources :triggers, only: [:index, :create, :edit, :update, :destroy] do - member do - post :take_ownership - end - end + resources :triggers, only: [:index, :create, :edit, :update, :destroy] resource :mirror, only: [:show, :update] do member do diff --git a/config/webpack.config.js b/config/webpack.config.js index cd793743eb7..4b6a9e4b99e 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -6,6 +6,7 @@ const StatsWriterPlugin = require('webpack-stats-plugin').StatsWriterPlugin; const CompressionPlugin = require('compression-webpack-plugin'); const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin'); const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; +const CopyWebpackPlugin = require('copy-webpack-plugin'); const ROOT_PATH = path.resolve(__dirname, '..'); const CACHE_PATH = process.env.WEBPACK_CACHE_PATH || path.join(ROOT_PATH, 'tmp/cache'); @@ -278,6 +279,13 @@ module.exports = { } }), + new CopyWebpackPlugin([ + { + from: path.join(ROOT_PATH, 'node_modules/pdfjs-dist/cmaps/'), + to: path.join(ROOT_PATH, 'public/assets/webpack/cmaps/'), + }, + ]), + // compression can require a lot of compute time and is disabled in CI IS_PRODUCTION && !NO_COMPRESSION && new CompressionPlugin(), diff --git a/danger/gemfile/Dangerfile b/danger/gemfile/Dangerfile index 4e91abc371a..dfe64f79d7b 100644 --- a/danger/gemfile/Dangerfile +++ b/danger/gemfile/Dangerfile @@ -3,8 +3,7 @@ GEMFILE_LOCK_NOT_UPDATED_MESSAGE = <<~MSG.freeze Usually, when %<gemfile>s is updated, you should run ``` -bundle install && \ - bundle install +bundle install ``` or diff --git a/db/migrate/20180824202952_add_outbound_requests_whitelist_to_application_settings.rb b/db/migrate/20180824202952_add_outbound_requests_whitelist_to_application_settings.rb new file mode 100644 index 00000000000..4ee654ce873 --- /dev/null +++ b/db/migrate/20180824202952_add_outbound_requests_whitelist_to_application_settings.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class AddOutboundRequestsWhitelistToApplicationSettings < ActiveRecord::Migration[5.1] + DOWNTIME = false + + def change + add_column :application_settings, :outbound_local_requests_whitelist, :string, array: true, limit: 255 + end +end diff --git a/db/migrate/20190222051615_add_indexes_for_merge_request_diffs_query.rb b/db/migrate/20190222051615_add_indexes_for_merge_request_diffs_query.rb index 0048268ca6f..bf7f7b44dec 100644 --- a/db/migrate/20190222051615_add_indexes_for_merge_request_diffs_query.rb +++ b/db/migrate/20190222051615_add_indexes_for_merge_request_diffs_query.rb @@ -35,7 +35,7 @@ class AddIndexesForMergeRequestDiffsQuery < ActiveRecord::Migration[5.0] end def down - INDEX_SPECS.reverse.each do |spec| + INDEX_SPECS.reverse_each do |spec| remove_concurrent_index(*spec) end end diff --git a/db/migrate/20190611100201_add_geo_container_repository_updated_events_table.rb b/db/migrate/20190611100201_add_geo_container_repository_updated_events_table.rb new file mode 100644 index 00000000000..8963e837e08 --- /dev/null +++ b/db/migrate/20190611100201_add_geo_container_repository_updated_events_table.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class AddGeoContainerRepositoryUpdatedEventsTable < ActiveRecord::Migration[5.1] + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + def change + create_table :geo_container_repository_updated_events, force: :cascade do |t| + t.integer :container_repository_id, null: false + + t.index :container_repository_id, name: :idx_geo_con_rep_updated_events_on_container_repository_id, using: :btree + end + + add_column :geo_event_log, :container_repository_updated_event_id, :bigint + end +end diff --git a/db/migrate/20190611100202_add_index_to_geo_event_log.rb b/db/migrate/20190611100202_add_index_to_geo_event_log.rb new file mode 100644 index 00000000000..c5c855fed61 --- /dev/null +++ b/db/migrate/20190611100202_add_index_to_geo_event_log.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class AddIndexToGeoEventLog < ActiveRecord::Migration[5.1] + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + disable_ddl_transaction! + + def up + add_concurrent_index :geo_event_log, :container_repository_updated_event_id + end + + def down + remove_concurrent_index(:geo_event_log, :container_repository_updated_event_id) + end +end diff --git a/db/migrate/20190627122264_add_foreign_keys_for_container_repository.rb b/db/migrate/20190627122264_add_foreign_keys_for_container_repository.rb new file mode 100644 index 00000000000..cf7fd03e9af --- /dev/null +++ b/db/migrate/20190627122264_add_foreign_keys_for_container_repository.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +class AddForeignKeysForContainerRepository < ActiveRecord::Migration[5.1] + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + disable_ddl_transaction! + + def up + add_concurrent_foreign_key(:geo_container_repository_updated_events, :container_repositories, column: :container_repository_id, on_delete: :cascade) + + add_concurrent_foreign_key(:geo_event_log, :geo_container_repository_updated_events, column: :container_repository_updated_event_id, on_delete: :cascade) + end + + def down + if foreign_key_exists?(:geo_container_repository_updated_events, :container_repositories) + remove_foreign_key(:geo_container_repository_updated_events, :container_repositories) + end + + if foreign_key_exists?(:geo_event_log, :geo_container_repository_updated_events) + remove_foreign_key(:geo_event_log, :geo_container_repository_updated_events) + end + end +end diff --git a/db/migrate/20190709220014_import_common_metrics_y_axis.rb b/db/migrate/20190709220014_import_common_metrics_y_axis.rb new file mode 100644 index 00000000000..89ecf32ecc1 --- /dev/null +++ b/db/migrate/20190709220014_import_common_metrics_y_axis.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +class ImportCommonMetricsYAxis < ActiveRecord::Migration[5.1] + DOWNTIME = false + + def up + ::Gitlab::DatabaseImporters::CommonMetrics::Importer.new.execute + end + + def down + # no-op + end +end diff --git a/db/migrate/20190711124721_create_job_variables.rb b/db/migrate/20190711124721_create_job_variables.rb new file mode 100644 index 00000000000..a860522f39e --- /dev/null +++ b/db/migrate/20190711124721_create_job_variables.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +# See http://doc.gitlab.com/ce/development/migration_style_guide.html +# for more information on how to write migrations for GitLab. + +class CreateJobVariables < ActiveRecord::Migration[5.1] + include Gitlab::Database::MigrationHelpers + + # Set this constant to true if this migration requires downtime. + DOWNTIME = false + + def change + create_table :ci_job_variables do |t| + t.string :key, null: false + t.text :encrypted_value + t.string :encrypted_value_iv + t.references :job, null: false, index: true, foreign_key: { to_table: :ci_builds, on_delete: :cascade } + t.integer :variable_type, null: false, limit: 2, default: 1 + end + + add_index :ci_job_variables, [:key, :job_id], unique: true + end +end diff --git a/db/migrate/20190715042813_add_issue_id_to_versions.rb b/db/migrate/20190715042813_add_issue_id_to_versions.rb new file mode 100644 index 00000000000..1cefdbc9df2 --- /dev/null +++ b/db/migrate/20190715042813_add_issue_id_to_versions.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +class AddIssueIdToVersions < ActiveRecord::Migration[5.2] + DOWNTIME = false + + def up + add_reference :design_management_versions, :issue, index: true, foreign_key: { on_delete: :cascade } + end + + def down + remove_reference :design_management_versions, :issue + end +end diff --git a/db/migrate/20190715043954_set_issue_id_for_all_versions.rb b/db/migrate/20190715043954_set_issue_id_for_all_versions.rb new file mode 100644 index 00000000000..345b749f1a4 --- /dev/null +++ b/db/migrate/20190715043954_set_issue_id_for_all_versions.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +class SetIssueIdForAllVersions < ActiveRecord::Migration[5.2] + DOWNTIME = false + + def up + execute('UPDATE design_management_versions as versions SET issue_id = ( + SELECT design_management_designs.issue_id + FROM design_management_designs + INNER JOIN design_management_designs_versions ON design_management_designs.id = design_management_designs_versions.design_id + WHERE design_management_designs_versions.version_id = versions.id + LIMIT 1 + )') + end + + def down + # no-op + end +end diff --git a/db/migrate/20190715140740_add_event_type_to_design_management_designs_versions.rb b/db/migrate/20190715140740_add_event_type_to_design_management_designs_versions.rb new file mode 100644 index 00000000000..81a8b0a3271 --- /dev/null +++ b/db/migrate/20190715140740_add_event_type_to_design_management_designs_versions.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +# This migration sets up a event enum on the DesignsVersions join table +class AddEventTypeToDesignManagementDesignsVersions < ActiveRecord::Migration[5.2] + include Gitlab::Database::MigrationHelpers + + # Set this constant to true if this migration requires downtime. + DOWNTIME = false + + # We disable these cops here because adding this column is safe. The table does not + # have any data in it. + # rubocop: disable Migration/AddIndex + # rubocop: disable Migration/AddColumn + def up + add_column(:design_management_designs_versions, :event, :integer, + limit: 2, + null: false, + default: 0) + add_index(:design_management_designs_versions, :event) + end + + # rubocop: disable Migration/RemoveIndex + def down + remove_index(:design_management_designs_versions, :event) + remove_column(:design_management_designs_versions, :event) + end +end diff --git a/db/migrate/20190715142138_add_raw_blob_request_limit_to_application_settings.rb b/db/migrate/20190715142138_add_raw_blob_request_limit_to_application_settings.rb new file mode 100644 index 00000000000..e8198e11ea7 --- /dev/null +++ b/db/migrate/20190715142138_add_raw_blob_request_limit_to_application_settings.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class AddRawBlobRequestLimitToApplicationSettings < ActiveRecord::Migration[5.2] + DOWNTIME = false + + def change + add_column :application_settings, :raw_blob_request_limit, :integer, default: 300, null: false + end +end diff --git a/db/migrate/20190725012225_change_outbound_local_requests_whitelist_default.rb b/db/migrate/20190725012225_change_outbound_local_requests_whitelist_default.rb new file mode 100644 index 00000000000..21b00e0b7d9 --- /dev/null +++ b/db/migrate/20190725012225_change_outbound_local_requests_whitelist_default.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +class ChangeOutboundLocalRequestsWhitelistDefault < ActiveRecord::Migration[5.2] + include Gitlab::Database::MigrationHelpers + + # Set this constant to true if this migration requires downtime. + DOWNTIME = false + + class ApplicationSetting < ActiveRecord::Base + self.table_name = 'application_settings' + end + + def up + default_value = [] + + change_column_default(:application_settings, :outbound_local_requests_whitelist, default_value) + + ApplicationSetting + .where(outbound_local_requests_whitelist: nil) + .update(outbound_local_requests_whitelist: default_value) + + change_column_null(:application_settings, :outbound_local_requests_whitelist, false) + end + + def down + change_column_null(:application_settings, :outbound_local_requests_whitelist, true) + + change_column_default(:application_settings, :outbound_local_requests_whitelist, nil) + end +end diff --git a/db/migrate/20190729090456_add_index_on_environments_with_state.rb b/db/migrate/20190729090456_add_index_on_environments_with_state.rb new file mode 100644 index 00000000000..9a8d8391415 --- /dev/null +++ b/db/migrate/20190729090456_add_index_on_environments_with_state.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class AddIndexOnEnvironmentsWithState < ActiveRecord::Migration[5.2] + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + disable_ddl_transaction! + + def up + add_concurrent_index :environments, [:project_id, :state] + end + + def down + remove_concurrent_index :environments, [:project_id, :state] + end +end diff --git a/db/post_migrate/20190715043944_remove_sha_index_from_versions.rb b/db/post_migrate/20190715043944_remove_sha_index_from_versions.rb new file mode 100644 index 00000000000..b23abb80dda --- /dev/null +++ b/db/post_migrate/20190715043944_remove_sha_index_from_versions.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class RemoveShaIndexFromVersions < ActiveRecord::Migration[5.2] + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + disable_ddl_transaction! + + def up + remove_concurrent_index :design_management_versions, :sha + end + + def down + add_concurrent_index :design_management_versions, :sha, unique: true, using: :btree + end +end diff --git a/db/post_migrate/20190715044501_add_unique_issue_id_sha_index_to_versions.rb b/db/post_migrate/20190715044501_add_unique_issue_id_sha_index_to_versions.rb new file mode 100644 index 00000000000..27b0c9648f9 --- /dev/null +++ b/db/post_migrate/20190715044501_add_unique_issue_id_sha_index_to_versions.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class AddUniqueIssueIdShaIndexToVersions < ActiveRecord::Migration[5.2] + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + disable_ddl_transaction! + + def up + add_concurrent_index :design_management_versions, [:sha, :issue_id], unique: true, using: :btree + end + + def down + remove_concurrent_index :design_management_versions, [:sha, :issue_id] + end +end diff --git a/db/schema.rb b/db/schema.rb index f42a4c600ea..f6b7e22fe09 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2019_07_15_114644) do +ActiveRecord::Schema.define(version: 2019_07_29_090456) do # These are extensions that must be enabled in order to support this database enable_extension "pg_trgm" @@ -228,6 +228,8 @@ ActiveRecord::Schema.define(version: 2019_07_15_114644) do t.boolean "lock_memberships_to_ldap", default: false, null: false t.boolean "time_tracking_limit_to_hours", default: false, null: false t.string "grafana_url", default: "/-/grafana", null: false + t.string "outbound_local_requests_whitelist", limit: 255, default: [], null: false, array: true + t.integer "raw_blob_request_limit", default: 300, null: false t.index ["custom_project_templates_group_id"], name: "index_application_settings_on_custom_project_templates_group_id" t.index ["file_template_project_id"], name: "index_application_settings_on_file_template_project_id" t.index ["usage_stats_set_by_user_id"], name: "index_application_settings_on_usage_stats_set_by_user_id" @@ -603,6 +605,16 @@ ActiveRecord::Schema.define(version: 2019_07_15_114644) do t.index ["project_id"], name: "index_ci_job_artifacts_on_project_id" end + create_table "ci_job_variables", force: :cascade do |t| + t.string "key", null: false + t.text "encrypted_value" + t.string "encrypted_value_iv" + t.bigint "job_id", null: false + t.integer "variable_type", limit: 2, default: 1, null: false + t.index ["job_id"], name: "index_ci_job_variables_on_job_id" + t.index ["key", "job_id"], name: "index_ci_job_variables_on_key_and_job_id", unique: true + end + create_table "ci_pipeline_chat_data", force: :cascade do |t| t.integer "pipeline_id", null: false t.integer "chat_name_id", null: false @@ -1095,14 +1107,18 @@ ActiveRecord::Schema.define(version: 2019_07_15_114644) do create_table "design_management_designs_versions", id: false, force: :cascade do |t| t.bigint "design_id", null: false t.bigint "version_id", null: false + t.integer "event", limit: 2, default: 0, null: false t.index ["design_id", "version_id"], name: "design_management_designs_versions_uniqueness", unique: true t.index ["design_id"], name: "index_design_management_designs_versions_on_design_id" + t.index ["event"], name: "index_design_management_designs_versions_on_event" t.index ["version_id"], name: "index_design_management_designs_versions_on_version_id" end create_table "design_management_versions", force: :cascade do |t| t.binary "sha", null: false - t.index ["sha"], name: "index_design_management_versions_on_sha", unique: true + t.bigint "issue_id" + t.index ["issue_id"], name: "index_design_management_versions_on_issue_id" + t.index ["sha", "issue_id"], name: "index_design_management_versions_on_sha_and_issue_id", unique: true end create_table "draft_notes", force: :cascade do |t| @@ -1158,6 +1174,7 @@ ActiveRecord::Schema.define(version: 2019_07_15_114644) do t.index ["name"], name: "index_environments_on_name_varchar_pattern_ops", opclass: :varchar_pattern_ops t.index ["project_id", "name"], name: "index_environments_on_project_id_and_name", unique: true t.index ["project_id", "slug"], name: "index_environments_on_project_id_and_slug", unique: true + t.index ["project_id", "state"], name: "index_environments_on_project_id_and_state" end create_table "epic_issues", id: :serial, force: :cascade do |t| @@ -1275,6 +1292,11 @@ ActiveRecord::Schema.define(version: 2019_07_15_114644) do t.string "key", null: false end + create_table "geo_container_repository_updated_events", force: :cascade do |t| + t.integer "container_repository_id", null: false + t.index ["container_repository_id"], name: "idx_geo_con_rep_updated_events_on_container_repository_id" + end + create_table "geo_event_log", force: :cascade do |t| t.datetime "created_at", null: false t.bigint "repository_updated_event_id" @@ -1289,7 +1311,9 @@ ActiveRecord::Schema.define(version: 2019_07_15_114644) do t.bigint "job_artifact_deleted_event_id" t.bigint "reset_checksum_event_id" t.bigint "cache_invalidation_event_id" + t.bigint "container_repository_updated_event_id" t.index ["cache_invalidation_event_id"], name: "index_geo_event_log_on_cache_invalidation_event_id", where: "(cache_invalidation_event_id IS NOT NULL)" + t.index ["container_repository_updated_event_id"], name: "index_geo_event_log_on_container_repository_updated_event_id" t.index ["hashed_storage_attachments_event_id"], name: "index_geo_event_log_on_hashed_storage_attachments_event_id", where: "(hashed_storage_attachments_event_id IS NOT NULL)" t.index ["hashed_storage_migrated_event_id"], name: "index_geo_event_log_on_hashed_storage_migrated_event_id", where: "(hashed_storage_migrated_event_id IS NOT NULL)" t.index ["job_artifact_deleted_event_id"], name: "index_geo_event_log_on_job_artifact_deleted_event_id", where: "(job_artifact_deleted_event_id IS NOT NULL)" @@ -3626,6 +3650,7 @@ ActiveRecord::Schema.define(version: 2019_07_15_114644) do add_foreign_key "ci_group_variables", "namespaces", column: "group_id", name: "fk_33ae4d58d8", on_delete: :cascade add_foreign_key "ci_job_artifacts", "ci_builds", column: "job_id", on_delete: :cascade add_foreign_key "ci_job_artifacts", "projects", on_delete: :cascade + add_foreign_key "ci_job_variables", "ci_builds", column: "job_id", on_delete: :cascade add_foreign_key "ci_pipeline_chat_data", "chat_names", on_delete: :cascade add_foreign_key "ci_pipeline_chat_data", "ci_pipelines", column: "pipeline_id", on_delete: :cascade add_foreign_key "ci_pipeline_schedule_variables", "ci_pipeline_schedules", column: "pipeline_schedule_id", name: "fk_41c35fda51", on_delete: :cascade @@ -3679,6 +3704,7 @@ ActiveRecord::Schema.define(version: 2019_07_15_114644) do add_foreign_key "design_management_designs", "projects", on_delete: :cascade add_foreign_key "design_management_designs_versions", "design_management_designs", column: "design_id", name: "fk_03c671965c", on_delete: :cascade add_foreign_key "design_management_designs_versions", "design_management_versions", column: "version_id", name: "fk_f4d25ba00c", on_delete: :cascade + add_foreign_key "design_management_versions", "issues", on_delete: :cascade add_foreign_key "draft_notes", "merge_requests", on_delete: :cascade add_foreign_key "draft_notes", "users", column: "author_id", on_delete: :cascade add_foreign_key "elasticsearch_indexed_namespaces", "namespaces", on_delete: :cascade @@ -3700,7 +3726,9 @@ ActiveRecord::Schema.define(version: 2019_07_15_114644) do add_foreign_key "fork_network_members", "projects", on_delete: :cascade add_foreign_key "fork_networks", "projects", column: "root_project_id", name: "fk_e7b436b2b5", on_delete: :nullify add_foreign_key "forked_project_links", "projects", column: "forked_to_project_id", name: "fk_434510edb0", on_delete: :cascade + add_foreign_key "geo_container_repository_updated_events", "container_repositories", name: "fk_212c89c706", on_delete: :cascade add_foreign_key "geo_event_log", "geo_cache_invalidation_events", column: "cache_invalidation_event_id", name: "fk_42c3b54bed", on_delete: :cascade + add_foreign_key "geo_event_log", "geo_container_repository_updated_events", column: "container_repository_updated_event_id", name: "fk_6ada82d42a", on_delete: :cascade add_foreign_key "geo_event_log", "geo_hashed_storage_migrated_events", column: "hashed_storage_migrated_event_id", name: "fk_27548c6db3", on_delete: :cascade add_foreign_key "geo_event_log", "geo_job_artifact_deleted_events", column: "job_artifact_deleted_event_id", name: "fk_176d3fbb5d", on_delete: :cascade add_foreign_key "geo_event_log", "geo_lfs_object_deleted_events", column: "lfs_object_deleted_event_id", name: "fk_d5af95fcd9", on_delete: :cascade diff --git a/doc/README.md b/doc/README.md index bf7017d8fb4..af675582a99 100644 --- a/doc/README.md +++ b/doc/README.md @@ -302,7 +302,7 @@ The following documentation relates to the DevOps **Configure** stage: | Configure Topics | Description | |:-----------------------------------------------------------------------------------------------------------------------------------|:--------------------------------------------------------------------------| | [Auto DevOps](topics/autodevops/index.md) | Automatically employ a complete DevOps lifecycle. | -| [Easy creation of Kubernetes<br/>clusters on GKE](user/project/clusters/index.md#adding-and-creating-a-new-gke-cluster-via-gitlab) | Use Google Kubernetes Engine and GitLab. | +| [Create Kubernetes clusters on GKE](user/project/clusters/index.md#add-new-gke-cluster) | Use Google Kubernetes Engine and GitLab. | | [Executable Runbooks](user/project/clusters/runbooks/index.md) | Documented procedures that explain how to carry out particular processes. | | [GitLab ChatOps](ci/chatops/README.md) | Interact with CI/CD jobs through chat services. | | [Installing Applications](user/project/clusters/index.md#installing-applications) | Deploy Helm, Ingress, and Prometheus on Kubernetes. | diff --git a/doc/administration/audit_events.md b/doc/administration/audit_events.md index aaa43f67760..02de2caf558 100644 --- a/doc/administration/audit_events.md +++ b/doc/administration/audit_events.md @@ -73,6 +73,8 @@ From there, you can see the following actions: - User was added to project and with which [permissions] - Permission changes of a user assigned to a project - User was removed from project +- Project export was downloaded +- Project repository was downloaded ### Instance events **(PREMIUM ONLY)** diff --git a/doc/administration/geo/replication/configuration.md b/doc/administration/geo/replication/configuration.md index 0e11dffa0d6..fd076bb79d8 100644 --- a/doc/administration/geo/replication/configuration.md +++ b/doc/administration/geo/replication/configuration.md @@ -17,7 +17,7 @@ You are encouraged to first read through all the steps before executing them in your testing/production environment. NOTE: **Note:** -**Do not** set up any custom authentication for the **secondary** nodes. This will be handled by the **primary** node. +**Do not** set up any custom authentication for the **secondary** nodes. This will be handled by the **primary** node. Any change that requires access to the **Admin Area** needs to be done in the **primary** node because the **secondary** node is a read-only replica. @@ -242,7 +242,7 @@ node's Geo Nodes dashboard in your browser. ![Geo dashboard](img/geo_node_dashboard.png) If your installation isn't working properly, check the -[troubleshooting document]. +[troubleshooting document](troubleshooting.md). The two most obvious issues that can become apparent in the dashboard are: diff --git a/doc/administration/geo/replication/updating_the_geo_nodes.md b/doc/administration/geo/replication/updating_the_geo_nodes.md index 166ee94eca4..550b3b07a95 100644 --- a/doc/administration/geo/replication/updating_the_geo_nodes.md +++ b/doc/administration/geo/replication/updating_the_geo_nodes.md @@ -251,7 +251,7 @@ Omnibus is the following: 1. Check the steps about defining `postgresql['sql_user_password']`, `gitlab_rails['db_password']`. 1. Make sure `postgresql['max_replication_slots']` matches the number of **secondary** Geo nodes locations. 1. Install GitLab on the **secondary** server. -1. Re-run the [database replication process][database-replication]. +1. Re-run the [database replication process](database.md#step-3-initiate-the-replication-process). ## Special update notes for 9.0.x diff --git a/doc/administration/high_availability/README.md b/doc/administration/high_availability/README.md index 41ef68f5b57..42516d811a0 100644 --- a/doc/administration/high_availability/README.md +++ b/doc/administration/high_availability/README.md @@ -164,16 +164,13 @@ contention due to certain workloads. #### Reference Architecture -- **Status:** Work-in-progress - **Supported Users (approximate):** 10,000 -- **Related Issues:** [gitlab-com/support/support-team-meta#1513](https://gitlab.com/gitlab-com/support/support-team-meta/issues/1513), - [gitlab-org/quality/team-tasks#110](https://gitlab.com/gitlab-org/quality/team-tasks/issues/110) - -The Support and Quality teams are in the process of building and performance testing -an environment that will support about 10,000 users. The specifications below -are a work-in-progress representation of the work so far. Quality will be -certifying this environment in FY20-Q2. The specifications may be adjusted -prior to certification based on performance testing. +- **Known Issues:** While validating the reference architecture, slow endpoints were discovered and are being investigated. [gitlab-org/gitlab-ce/issues/64335](https://gitlab.com/gitlab-org/gitlab-ce/issues/64335) + +The Support and Quality teams built, performance tested, and validated an +environment that supports about 10,000 users. The specifications below are a +representation of the work so far. The specifications may be adjusted in the +future based on additional testing and iteration. - 3 PostgreSQL - 4 CPU, 8GB RAM per node - 1 PgBouncer - 2 CPU, 4GB RAM diff --git a/doc/administration/logs.md b/doc/administration/logs.md index 563701b8677..31876dd178a 100644 --- a/doc/administration/logs.md +++ b/doc/administration/logs.md @@ -242,7 +242,7 @@ I, [2015-02-13T06:17:00.679433 #9291] INFO -- : Moving existing hooks directory User clone/fetch activity using ssh transport appears in this log as `executing git command <gitaly-upload-pack...`. -## `unicorn\_stderr.log` +## `unicorn_stderr.log` This file lives in `/var/log/gitlab/unicorn/unicorn_stderr.log` for Omnibus GitLab packages or in `/home/git/gitlab/log/unicorn_stderr.log` for @@ -283,9 +283,6 @@ Introduced in GitLab 11.3. This file lives in `/var/log/gitlab/gitlab-rails/impo Omnibus GitLab packages or in `/home/git/gitlab/log/importer.log` for installations from source. -Currently it logs the progress of project imports from the Bitbucket Server -importer. Future importers may use this file. - ## `auth.log` Introduced in GitLab 12.0. This file lives in `/var/log/gitlab/gitlab-rails/auth.log` for diff --git a/doc/administration/monitoring/performance/img/performance_bar.png b/doc/administration/monitoring/performance/img/performance_bar.png Binary files differindex 2bf686f9017..89b09054d46 100644 --- a/doc/administration/monitoring/performance/img/performance_bar.png +++ b/doc/administration/monitoring/performance/img/performance_bar.png diff --git a/doc/administration/monitoring/performance/img/performance_bar_gitaly_calls.png b/doc/administration/monitoring/performance/img/performance_bar_gitaly_calls.png Binary files differindex 7af6d401d1d..265178729c4 100644 --- a/doc/administration/monitoring/performance/img/performance_bar_gitaly_calls.png +++ b/doc/administration/monitoring/performance/img/performance_bar_gitaly_calls.png diff --git a/doc/administration/monitoring/performance/img/performance_bar_line_profiling.png b/doc/administration/monitoring/performance/img/performance_bar_line_profiling.png Binary files differdeleted file mode 100644 index a55ce753101..00000000000 --- a/doc/administration/monitoring/performance/img/performance_bar_line_profiling.png +++ /dev/null diff --git a/doc/administration/monitoring/performance/img/performance_bar_redis_calls.png b/doc/administration/monitoring/performance/img/performance_bar_redis_calls.png Binary files differnew file mode 100644 index 00000000000..78dd7594adf --- /dev/null +++ b/doc/administration/monitoring/performance/img/performance_bar_redis_calls.png diff --git a/doc/administration/monitoring/performance/img/performance_bar_rugged_calls.png b/doc/administration/monitoring/performance/img/performance_bar_rugged_calls.png Binary files differnew file mode 100644 index 00000000000..f4068268137 --- /dev/null +++ b/doc/administration/monitoring/performance/img/performance_bar_rugged_calls.png diff --git a/doc/administration/monitoring/performance/img/performance_bar_sql_queries.png b/doc/administration/monitoring/performance/img/performance_bar_sql_queries.png Binary files differindex b3219b4fa94..dab323eb066 100644 --- a/doc/administration/monitoring/performance/img/performance_bar_sql_queries.png +++ b/doc/administration/monitoring/performance/img/performance_bar_sql_queries.png diff --git a/doc/administration/monitoring/performance/performance_bar.md b/doc/administration/monitoring/performance/performance_bar.md index 4ee156fdc11..2cc78ccc03c 100644 --- a/doc/administration/monitoring/performance/performance_bar.md +++ b/doc/administration/monitoring/performance/performance_bar.md @@ -8,15 +8,14 @@ activated, it looks as follows: It allows you to see (from left to right): - the current host serving the page -- the timing of the page (backend, frontend) - time taken and number of DB queries, click through for details of these queries ![SQL profiling using the Performance Bar](img/performance_bar_sql_queries.png) - time taken and number of [Gitaly] calls, click through for details of these calls ![Gitaly profiling using the Performance Bar](img/performance_bar_gitaly_calls.png) -- profile of the code used to generate the page, line by line. In the profile view, the numbers in the left panel represent wall time, cpu time, and number of calls (based on [rblineprof](https://github.com/tmm1/rblineprof)). - ![Line profiling using the Performance Bar](img/performance_bar_line_profiling.png) -- time taken and number of calls to Redis -- time taken and number of background jobs created by Sidekiq +- time taken and number of [Rugged] calls, click through for details of these calls + ![Rugged profiling using the Performance Bar](img/performance_bar_rugged_calls.png) +- time taken and number of Redis calls, click through for details of these calls + ![Redis profiling using the Performance Bar](img/performance_bar_redis_calls.png) - time taken and number of Ruby GC calls On the far right is a request selector that allows you to view the same metrics @@ -43,3 +42,4 @@ You can toggle the Bar using the same shortcut. ![GitLab Performance Bar Admin Settings](img/performance_bar_configuration_settings.png) [Gitaly]: ../../gitaly/index.md +[Rugged]: ../../high_availability/nfs.md#improving-nfs-performance-with-gitlab diff --git a/doc/administration/troubleshooting/debug.md b/doc/administration/troubleshooting/debug.md index 098d946a9fa..604dff5983d 100644 --- a/doc/administration/troubleshooting/debug.md +++ b/doc/administration/troubleshooting/debug.md @@ -209,7 +209,7 @@ ps auwx | grep unicorn | awk '{ print " -p " $2}' | xargs strace -tt -T -f -s 10 The output in `/tmp/unicorn.txt` may help diagnose the root cause. -# More information +## More information - [Debugging Stuck Ruby Processes](https://blog.newrelic.com/2013/04/29/debugging-stuck-ruby-processes-what-to-do-before-you-kill-9/) - [Cheatsheet of using gdb and ruby processes](gdb-stuck-ruby.txt) diff --git a/doc/api/README.md b/doc/api/README.md index f9cc1a09870..70540420544 100644 --- a/doc/api/README.md +++ b/doc/api/README.md @@ -29,7 +29,7 @@ The following API resources are available in the project context: | [Commits](commits.md) | `/projects/:id/repository/commits`, `/projects/:id/statuses` | | [Container Registry](container_registry.md) | `/projects/:id/registry/repositories` | | [Custom attributes](custom_attributes.md) | `/projects/:id/custom_attributes` (also available for groups and users) | -| [Dependencies](dependencies.md) **[ULTIMATE]** | `/projects/:id/dependencies` +| [Dependencies](dependencies.md) **(ULTIMATE)** | `/projects/:id/dependencies` | [Deploy keys](deploy_keys.md) | `/projects/:id/deploy_keys` (also available standalone) | | [Deployments](deployments.md) | `/projects/:id/deployments` | | [Discussions](discussions.md) (threaded comments) | `/projects/:id/issues/.../discussions`, `/projects/:id/snippets/.../discussions`, `/projects/:id/merge_requests/.../discussions`, `/projects/:id/commits/.../discussions` (also available for groups) | @@ -515,7 +515,7 @@ more than 10,000, the `X-Total` and `X-Total-Pages` headers as well as the ## Namespaced path encoding -If using namespaced API calls, make sure that the `NAMESPACE/PROJECT_NAME` is +If using namespaced API calls, make sure that the `NAMESPACE/PROJECT_PATH` is URL-encoded. For example, `/` is represented by `%2F`: @@ -524,6 +524,11 @@ For example, `/` is represented by `%2F`: GET /api/v4/projects/diaspora%2Fdiaspora ``` +NOTE: **Note:** +A project's **path** is not necessarily the same as its **name**. A +project's path can found in the project's URL or in the project's settings +under **General > Advanced > Change path**. + ## Branches and tags name encoding If your branch or tag contains a `/`, make sure the branch/tag name is diff --git a/doc/api/dependencies.md b/doc/api/dependencies.md index ed5ebdade19..2496b038c7f 100644 --- a/doc/api/dependencies.md +++ b/doc/api/dependencies.md @@ -17,8 +17,8 @@ supported by Gemnasium. ``` GET /projects/:id/dependencies -GET /projects/:id/vulnerabilities?package_manger=maven -GET /projects/:id/vulnerabilities?package_manger=yarn,bundler +GET /projects/:id/vulnerabilities?package_manager=maven +GET /projects/:id/vulnerabilities?package_manager=yarn,bundler ``` | Attribute | Type | Required | Description | diff --git a/doc/api/epics.md b/doc/api/epics.md index d05eb0a8804..3036b3c2364 100644 --- a/doc/api/epics.md +++ b/doc/api/epics.md @@ -10,7 +10,7 @@ If epics feature is not available a `403` status code will be returned. The [epic issues API](epic_issues.md) allows you to interact with issues associated with an epic. -# Milestone dates integration +## Milestone dates integration > [Introduced][ee-6448] in GitLab 11.3. diff --git a/doc/api/group_clusters.md b/doc/api/group_clusters.md index 31c0e6abead..29e58d9279a 100644 --- a/doc/api/group_clusters.md +++ b/doc/api/group_clusters.md @@ -210,7 +210,7 @@ Parameters: NOTE: **Note:** `name`, `api_url`, `ca_cert` and `token` can only be updated if the cluster was added -through the ["Add an existing Kubernetes Cluster"](../user/project/clusters/index.md#adding-an-existing-kubernetes-cluster) option or +through the ["Add existing Kubernetes cluster"](../user/project/clusters/index.md#add-existing-kubernetes-cluster) option or through the ["Add existing cluster to group"](#add-existing-cluster-to-group) endpoint. Example request: diff --git a/doc/api/oauth2.md b/doc/api/oauth2.md index 76e3a0fa1a4..f9382361187 100644 --- a/doc/api/oauth2.md +++ b/doc/api/oauth2.md @@ -50,11 +50,14 @@ The web application flow is: `/oauth/authorize` endpoint with the following GET parameters: ``` - https://gitlab.example.com/oauth/authorize?client_id=APP_ID&redirect_uri=REDIRECT_URI&response_type=code&state=YOUR_UNIQUE_STATE_HASH + https://gitlab.example.com/oauth/authorize?client_id=APP_ID&redirect_uri=REDIRECT_URI&response_type=code&state=YOUR_UNIQUE_STATE_HASH&scope=REQUESTED_SCOPES ``` - This will ask the user to approve the applications access to their account and - then redirect back to the `REDIRECT_URI` you provided. The redirect will + This will ask the user to approve the applications access to their account + based on the scopes specified in `REQUESTED_SCOPES` and then redirect back to + the `REDIRECT_URI` you provided. The [scope parameter](https://github.com/doorkeeper-gem/doorkeeper/wiki/Using-Scopes#requesting-particular-scopes) + is a space separated list of scopes you want to have access to (e.g. `scope=read_user+profile` + would request `read_user` and `profile` scopes). The redirect will include the GET `code` parameter, for example: ``` @@ -110,11 +113,14 @@ To request the access token, you should redirect the user to the `/oauth/authorize` endpoint using `token` response type: ``` -https://gitlab.example.com/oauth/authorize?client_id=APP_ID&redirect_uri=REDIRECT_URI&response_type=token&state=YOUR_UNIQUE_STATE_HASH +https://gitlab.example.com/oauth/authorize?client_id=APP_ID&redirect_uri=REDIRECT_URI&response_type=token&state=YOUR_UNIQUE_STATE_HASH&scope=REQUESTED_SCOPES ``` -This will ask the user to approve the application's access to their account and -then redirect them back to the `REDIRECT_URI` you provided. The redirect +This will ask the user to approve the applications access to their account +based on the scopes specified in `REQUESTED_SCOPES` and then redirect back to +the `REDIRECT_URI` you provided. The [scope parameter](https://github.com/doorkeeper-gem/doorkeeper/wiki/Using-Scopes#requesting-particular-scopes) + is a space separated list of scopes you want to have access to (e.g. `scope=read_user+profile` +would request `read_user` and `profile` scopes). The redirect will include a fragment with `access_token` as well as token details in GET parameters, for example: diff --git a/doc/api/pipeline_triggers.md b/doc/api/pipeline_triggers.md index 736312df116..e207ff8e98a 100644 --- a/doc/api/pipeline_triggers.md +++ b/doc/api/pipeline_triggers.md @@ -120,35 +120,6 @@ curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" --form descript } ``` -## Take ownership of a project trigger - -Update an owner of a project trigger. - -``` -POST /projects/:id/triggers/:trigger_id/take_ownership -``` - -| Attribute | Type | required | Description | -|---------------|---------|----------|--------------------------| -| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | -| `trigger_id` | integer | yes | The trigger id | - -``` -curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/triggers/10/take_ownership" -``` - -```json -{ - "id": 10, - "description": "my trigger", - "created_at": "2016-01-07T09:53:58.235Z", - "last_used": null, - "token": "6d056f63e50fe6f8c5f8f4aa10edb7", - "updated_at": "2016-01-07T09:53:58.235Z", - "owner": null -} -``` - ## Remove a project trigger Remove a project's build trigger. diff --git a/doc/api/project_clusters.md b/doc/api/project_clusters.md index 614ea41d572..762a4ad95ab 100644 --- a/doc/api/project_clusters.md +++ b/doc/api/project_clusters.md @@ -261,7 +261,7 @@ Parameters: NOTE: **Note:** `name`, `api_url`, `ca_cert` and `token` can only be updated if the cluster was added -through the ["Add an existing Kubernetes Cluster"](../user/project/clusters/index.md#adding-an-existing-kubernetes-cluster) option or +through the ["Add existing Kubernetes cluster"](../user/project/clusters/index.md#add-existing-kubernetes-cluster) option or through the ["Add existing cluster to project"](#add-existing-cluster-to-project) endpoint. Example request: diff --git a/doc/api/repository_files.md b/doc/api/repository_files.md index 87c7f371de1..b292c9dd7de 100644 --- a/doc/api/repository_files.md +++ b/doc/api/repository_files.md @@ -80,6 +80,75 @@ X-Gitlab-Size: 1476 ... ``` +## Get file blame from repository + +Allows you to receive blame information. Each blame range contains lines and corresponding commit info. + +``` +GET /projects/:id/repository/files/:file_path/blame +``` + +```bash +curl --request GET --header 'PRIVATE-TOKEN: <your_access_token>' 'https://gitlab.example.com/api/v4/projects/13083/repository/files/path%2Fto%2Ffile.rb/blame?ref=master' +``` + +Example response: + +```json +[ + { + "commit": { + "id": "d42409d56517157c48bf3bd97d3f75974dde19fb", + "message": "Add feature\n\nalso fix bug\n", + "parent_ids": [ + "cc6e14f9328fa6d7b5a0d3c30dc2002a3f2a3822" + ], + "authored_date": "2015-12-18T08:12:22.000Z", + "author_name": "John Doe", + "author_email": "john.doe@example.com", + "committed_date": "2015-12-18T08:12:22.000Z", + "committer_name": "John Doe", + "committer_email": "john.doe@example.com" + }, + "lines": [ + "require 'fileutils'", + "require 'open3'", + "" + ] + }, + ... +] +``` + +Parameters: + +- `file_path` (required) - Url encoded full path to new file. Ex. lib%2Fclass%2Erb +- `ref` (required) - The name of branch, tag or commit + +NOTE: **Note:** +`HEAD` method return just file metadata as in [Get file from repository](repository_files.md#get-file-from-repository). + +```bash +curl --head --header 'PRIVATE-TOKEN: <your_access_token>' 'https://gitlab.example.com/api/v4/projects/13083/repository/files/path%2Fto%2Ffile.rb/blame?ref=master' +``` + +Example response: + +```text +HTTP/1.1 200 OK +... +X-Gitlab-Blob-Id: 79f7bbd25901e8334750839545a9bd021f0e4c83 +X-Gitlab-Commit-Id: d5a3ff139356ce33e37e73add446f16869741b50 +X-Gitlab-Content-Sha256: 4c294617b60715c1d218e61164a3abd4808a4284cbc30e6728a01ad9aada4481 +X-Gitlab-Encoding: base64 +X-Gitlab-File-Name: file.rb +X-Gitlab-File-Path: path/to/file.rb +X-Gitlab-Last-Commit-Id: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d +X-Gitlab-Ref: master +X-Gitlab-Size: 1476 +... +``` + ## Get raw file from repository ``` diff --git a/doc/api/settings.md b/doc/api/settings.md index ff48cac1f47..68da88af698 100644 --- a/doc/api/settings.md +++ b/doc/api/settings.md @@ -39,6 +39,7 @@ Example response: "session_expire_delay" : 10080, "home_page_url" : null, "default_snippet_visibility" : "private", + "outbound_local_requests_whitelist": [], "domain_whitelist" : [], "domain_blacklist_enabled" : false, "domain_blacklist" : [], @@ -113,6 +114,7 @@ Example response: "default_project_visibility": "internal", "default_snippet_visibility": "private", "default_group_visibility": "private", + "outbound_local_requests_whitelist": [], "domain_whitelist": [], "domain_blacklist_enabled" : false, "domain_blacklist" : [], @@ -193,6 +195,7 @@ are listed in the descriptions of the relevant settings. | `domain_blacklist` | array of strings | required by: `domain_blacklist_enabled` | Users with e-mail addresses that match these domain(s) will NOT be able to sign-up. Wildcards allowed. Use separate lines for multiple entries. Ex: `domain.com`, `*.domain.com`. | | `domain_blacklist_enabled` | boolean | no | (**If enabled, requires:** `domain_blacklist`) Allows blocking sign-ups from emails from specific domains. | | `domain_whitelist` | array of strings | no | Force people to use only corporate emails for sign-up. Default is `null`, meaning there is no restriction. | +| `outbound_local_requests_whitelist` | array of strings | no | Define a list of trusted domains or ip addresses to which local requests are allowed when local requests for hooks and services are disabled. | `dsa_key_restriction` | integer | no | The minimum allowed bit length of an uploaded DSA key. Default is `0` (no restriction). `-1` disables DSA keys. | | `ecdsa_key_restriction` | integer | no | The minimum allowed curve size (in bits) of an uploaded ECDSA key. Default is `0` (no restriction). `-1` disables ECDSA keys. | | `ed25519_key_restriction` | integer | no | The minimum allowed curve size (in bits) of an uploaded ED25519 key. Default is `0` (no restriction). `-1` disables ED25519 keys. | diff --git a/doc/ci/README.md b/doc/ci/README.md index 7048ceaac41..6923d07bb1d 100644 --- a/doc/ci/README.md +++ b/doc/ci/README.md @@ -13,6 +13,11 @@ through the [continuous methodologies](introduction/index.md#introduction-to-cic - Continuous Delivery (CD) - Continuous Deployment (CD) +NOTE: **Out-of-the-box management systems can decrease hours spent on maintaining toolchains by 10% or more.** +Watch our +["Mastering continuous software development"](https://about.gitlab.com/webcast/mastering-ci-cd/) +webcast to learn about continuous methods and how GitLab’s built-in CI can help you simplify and scale software development. + ## Overview Continuous Integration works by pushing small code chunks to your @@ -155,6 +160,7 @@ for your CI/CD infrastructure: - [Why we chose GitLab CI for our CI/CD solution](https://about.gitlab.com/2016/10/17/gitlab-ci-oohlala/) - [Building our web-app on GitLab CI](https://about.gitlab.com/2016/07/22/building-our-web-app-on-gitlab-ci/) +- [5 Teams that made the switch to GitLab CI/CD](https://about.gitlab.com/2019/04/25/5-teams-that-made-the-switch-to-gitlab-ci-cd/) See also the [Why CI/CD?](https://docs.google.com/presentation/d/1OGgk2Tcxbpl7DJaIOzCX4Vqg3dlwfELC3u2jEeCBbDk) presentation. diff --git a/doc/ci/docker/using_docker_build.md b/doc/ci/docker/using_docker_build.md index efdcaf5a6f5..9f1ce1fc230 100644 --- a/doc/ci/docker/using_docker_build.md +++ b/doc/ci/docker/using_docker_build.md @@ -6,7 +6,6 @@ type: concepts, howto GitLab CI/CD allows you to use Docker Engine to build and test docker-based projects. - One of the new trends in Continuous Integration/Deployment is to: 1. Create an application image. @@ -29,7 +28,16 @@ during jobs. ## Runner Configuration -There are three methods to enable the use of `docker build` and `docker run` during jobs; each with their own tradeoffs. +There are three methods to enable the use of `docker build` and `docker run` +during jobs; each with their own tradeoffs. + +An alternative to using `docker build` is to [use kaniko](using_kaniko.md). +This avoids having to execute Runner in privileged mode. + +TIP: **Tip:** +To see how Docker and Runner are configured for shared Runners on +GitLab.com, see [GitLab.com Shared +Runners](../../user/gitlab_com/index.md#shared-runners). ### Use shell executor @@ -88,9 +96,9 @@ For more information please read [On Docker security: `docker` group considered The second approach is to use the special docker-in-docker (dind) [Docker image](https://hub.docker.com/_/docker/) with all tools installed (`docker`) and run the job script in context of that -image in privileged mode. +image in privileged mode. -NOTE: **Note:** `docker-compose` is not part of docker-in-docker (dind). In case you'd like to use `docker-compose` in your CI builds, please follow the [installation instructions for docker-compose](https://docs.docker.com/compose/install/) provided by docker. +NOTE: **Note:** `docker-compose` is not part of docker-in-docker (dind). In case you'd like to use `docker-compose` in your CI builds, please follow the [installation instructions for docker-compose](https://docs.docker.com/compose/install/) provided by docker. In order to do that, follow the steps: @@ -115,6 +123,13 @@ In order to do that, follow the steps: want to use [docker-in-docker] mode, you always have to use `privileged = true` in your Docker containers. + DANGER: **Danger:** + By enabling `--docker-privileged`, you are effectively disabling all of + the security mechanisms of containers and exposing your host to privilege + escalation which can lead to container breakout. For more information, check + out the official Docker documentation on + [Runtime privilege and Linux capabilities][docker-cap]. + The above command will create a `config.toml` entry similar to this: ```toml @@ -173,11 +188,6 @@ In order to do that, follow the steps: Docker-in-Docker works well, and is the recommended configuration, but it is not without its own challenges: -- By enabling `--docker-privileged`, you are effectively disabling all of - the security mechanisms of containers and exposing your host to privilege - escalation which can lead to container breakout. For more information, check - out the official Docker documentation on - [Runtime privilege and Linux capabilities][docker-cap]. - When using docker-in-docker, each job is in a clean environment without the past history. Concurrent jobs work fine because every build gets it's own instance of Docker engine so they won't conflict with each other. But this diff --git a/doc/ci/examples/README.md b/doc/ci/examples/README.md index 9295dcfd4e0..00995f881da 100644 --- a/doc/ci/examples/README.md +++ b/doc/ci/examples/README.md @@ -33,7 +33,7 @@ The following table lists examples with step-by-step tutorials that are containe | Java with Maven | [How to deploy Maven projects to Artifactory with GitLab CI/CD](artifactory_and_gitlab/index.md). | | PHP with PHPunit, atoum | [Testing PHP projects](php.md). | | PHP with NPM, SCP | [Running Composer and NPM scripts with deployment via SCP in GitLab CI/CD](deployment/composer-npm-deploy.md). | -| PHP with Laravel, Ennvoy | [Test and deploy Laravel applications with GitLab CI/CD and Envoy](laravel_with_gitlab_and_envoy/index.md). | +| PHP with Laravel, Envoy | [Test and deploy Laravel applications with GitLab CI/CD and Envoy](laravel_with_gitlab_and_envoy/index.md). | | Python on Heroku | [Test and deploy a Python application with GitLab CI/CD](test-and-deploy-python-application-to-heroku.md). | | Ruby on Heroku | [Test and deploy a Ruby application with GitLab CI/CD](test-and-deploy-ruby-application-to-heroku.md). | | Scala on Heroku | [Test and deploy a Scala application to Heroku](test-scala-application.md). | diff --git a/doc/ci/examples/code_quality.md b/doc/ci/examples/code_quality.md index 43f773dab7c..e63470ec9d9 100644 --- a/doc/ci/examples/code_quality.md +++ b/doc/ci/examples/code_quality.md @@ -34,6 +34,12 @@ For [GitLab Starter][ee] users, this information will be automatically extracted and shown right in the merge request widget. [Learn more on Code Quality in merge requests](../../user/project/merge_requests/code_quality.md). +CAUTION: **Caution:** +On self-managed instances, if a malicious actor compromises the Code Quality job +definition they will be able to execute privileged docker commands on the Runner +host. Having proper access control policies mitigates this attack vector by +allowing access only to trusted actors. + ## Previous job definitions CAUTION: **Caution:** diff --git a/doc/ci/img/manual_job_variables.png b/doc/ci/img/manual_job_variables.png Binary files differnew file mode 100644 index 00000000000..c7d62477cdd --- /dev/null +++ b/doc/ci/img/manual_job_variables.png diff --git a/doc/ci/introduction/index.md b/doc/ci/introduction/index.md index 6401ff90a0a..366aca3442e 100644 --- a/doc/ci/introduction/index.md +++ b/doc/ci/introduction/index.md @@ -9,6 +9,11 @@ In this document we'll present an overview of the concepts of Continuous Integra Continuous Delivery, and Continuous Deployment, as well as an introduction to GitLab CI/CD. +NOTE: **Out-of-the-box management systems can decrease hours spent on maintaining toolchains by 10% or more.** +Watch our +["Mastering continuous software development"](https://about.gitlab.com/webcast/mastering-ci-cd/) +webcast to learn about continuous methods and how GitLab’s built-in CI can help you simplify and scale software development. + ## Introduction to CI/CD methodologies The continuous methodologies of software development are based on diff --git a/doc/ci/merge_request_pipelines/pipelines_for_merged_results/index.md b/doc/ci/merge_request_pipelines/pipelines_for_merged_results/index.md index f63b17a9e5a..ad07c662965 100644 --- a/doc/ci/merge_request_pipelines/pipelines_for_merged_results/index.md +++ b/doc/ci/merge_request_pipelines/pipelines_for_merged_results/index.md @@ -62,18 +62,32 @@ CAUTION: **Warning:** Make sure your `gitlab-ci.yml` file is [configured properly for pipelines for merge requests](../index.md#configuring-pipelines-for-merge-requests), otherwise pipelines for merged results won't run and your merge requests will be stuck in an unresolved state. -## Merge Trains **(PREMIUM)** +## Troubleshooting -Read the [documentation on Merge Trains](merge_trains/index.md). +### Pipelines for merged results not created even with new change pushed to merge request -<!-- ## Troubleshooting +Can be caused by some disabled feature flags. Please make sure that +the following feature flags are enabled on your GitLab instance: -Include any troubleshooting steps that you can foresee. If you know beforehand what issues -one might have when setting this up, or when something is changed, or on upgrading, it's -important to describe those, too. Think of things that may go wrong and include them here. -This is important to minimize requests for support, and to avoid doc comments with -questions that you know someone might ask. +- `:ci_use_merge_request_ref` +- `:merge_ref_auto_sync` -Each scenario can be a third-level heading, e.g. `### Getting error message X`. -If you have none to add when creating a doc, leave this section in place -but commented out to help encourage others to add to it in the future. --> +To check these feature flag values, please ask administrator to execute the following commands: + +```shell +> sudo gitlab-rails console # Login to Rails console of GitLab instance. +> Feature.enabled?(:ci_use_merge_request_ref) # Check if it's enabled or not. +> Feature.enable(:ci_use_merge_request_ref) # Enable the feature flag. +``` + +## Using Merge Trains **(PREMIUM)** + +By enabling [Pipelines for merged results](#pipelines-for-merged-results-premium), +GitLab will [automatically display](merge_trains/index.md#how-to-add-a-merge-request-to-a-merge-train) +a **Start/Add Merge Train button** as the most recommended merge strategy. + +Generally, this is a safer option than merging merge requests immediately as your +merge request will be evaluated with an expected post-merge result before the actual +merge happens. + +For more information, read the [documentation on Merge Trains](merge_trains/index.md). diff --git a/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/img/merge_train_failure.png b/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/img/merge_train_failure.png Binary files differnew file mode 100644 index 00000000000..a8916e5721c --- /dev/null +++ b/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/img/merge_train_failure.png diff --git a/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/img/merge_train_immediate_merge.png b/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/img/merge_train_immediate_merge.png Binary files differnew file mode 100644 index 00000000000..65ff7e3d674 --- /dev/null +++ b/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/img/merge_train_immediate_merge.png diff --git a/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/index.md b/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/index.md index 44cbcde264c..80a1c264bc4 100644 --- a/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/index.md +++ b/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/index.md @@ -80,14 +80,65 @@ button while the latest pipeline is running. ![Add to merge train when pipeline succeeds](img/merge_train_start_when_pipeline_succeeds_v12_0.png) -<!-- ## Troubleshooting +## Immediately merge a merge request with a merge train -Include any troubleshooting steps that you can foresee. If you know beforehand what issues -one might have when setting this up, or when something is changed, or on upgrading, it's -important to describe those, too. Think of things that may go wrong and include them here. -This is important to minimize requests for support, and to avoid doc comments with -questions that you know someone might ask. +In case, you have a high-priority merge request (e.g. critical patch) to be merged urgently, +you can use **Merge Immediately** option for bypassing the merge train. +This is the fastest option to get the change merged into the target branch. -Each scenario can be a third-level heading, e.g. `### Getting error message X`. -If you have none to add when creating a doc, leave this section in place -but commented out to help encourage others to add to it in the future. --> +![Merge Immediately](img/merge_train_immediate_merge.png) + +However, every time you merge a merge request immediately, it could affect the +existing merge train to be reconstructed, specifically, it regenerates expected +merge commits and pipelines. This means, merging immediately essentially wastes +CI resources. + +## Troubleshooting + +### Merge request dropped from the merge train immediately + +If a merge request is not mergeable (for example, it's WIP, there is a merge +conflict, etc), your merge request will be dropped from the merge train automatically. + +In these cases, the reason for dropping the merge request is in the **system notes**. + +To check the reason: + +1. Open the merge request that was dropped from the merge train. +1. Open the **Discussion** tab. +1. Find a system note that includes either: + - The text **... removed this merge request from the merge train because ...** + - **... aborted this merge request from the merge train because ...** + The reason is given in the text after the **because ...** phrase. + +![Merge Train Failure](img/merge_train_failure.png) + +### Merge When Pipeline Succeeds cannot be chosen + +[Merge When Pipeline Succeeds](../../../../user/project/merge_requests/merge_when_pipeline_succeeds.md) +is unavailable when +[Pipelines for Merged Results is enabled](../index.md#enabling-pipelines-for-merged-results). + +Follow [this issue](https://gitlab.com/gitlab-org/gitlab-ee/issues/12267) to +track progress on this issue. + +### Merge Train disturbs your workflow + +First of all, please check if [merge immediately](#immediately-merge-a-merge-request-with-a-merge-train) +is available as a workaround in your workflow. This is the most recommended +workaround you'd be able to take immediately. If it's not available or acceptable, +please read through this section. + +Merge train is enabled by default when you enable [Pipelines for merged results](../index.md), +however, you can forcibly disable this feature by disabling the feature flag `:merge_trains_enabled`. +After you disabled this feature, all the existing merge trains will be aborted and +you will no longer see the **Start/Add Merge Train** button in merge requests. + +To check if the feature flag is enabled on your GitLab instance, +please ask administrator to execute the following commands: + +```shell +> sudo gitlab-rails console # Login to Rails console of GitLab instance. +> Feature.enabled?(:merge_trains_enabled) # Check if it's enabled or not. +> Feature.disable(:merge_trains_enabled) # Disable the feature flag. +```
\ No newline at end of file diff --git a/doc/ci/pipelines.md b/doc/ci/pipelines.md index 06a81c3d0c7..ed8d0e3bc35 100644 --- a/doc/ci/pipelines.md +++ b/doc/ci/pipelines.md @@ -6,6 +6,11 @@ type: reference > Introduced in GitLab 8.8. +NOTE: **Tip:** +Watch our +["Mastering continuous software development"](https://about.gitlab.com/webcast/mastering-ci-cd/) +webcast to see a comprehensive demo of GitLab CI/CD pipeline. + ## Introduction Pipelines are the top-level component of continuous integration, delivery, and deployment. @@ -318,6 +323,20 @@ stage has a job with a manual action. ![Pipelines example](img/pipelines.png) +### Specifying variables when running manual jobs + +> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/30485) in GitLab 12.2. + +When running manual jobs you can supply additional job specific variables. + +You can do this from the job page of the manual job you want to run with +additional variables. + +This is useful when you want to alter the execution of a job by using +environment variables. + +![Manual job variables](img/manual_job_variables.png) + ### Delay a job in a pipeline graph > [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/21767) in GitLab 11.4. @@ -345,7 +364,7 @@ GitLab provides API endpoints to: - [Triggering pipelines through the API](triggers/README.md). - [Pipeline triggers API](../api/pipeline_triggers.md). -### Start multiple manual actions in a stage +### Start multiple manual actions in a stage > [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/27188) in GitLab 11.11. diff --git a/doc/ci/services/mysql.md b/doc/ci/services/mysql.md index 697452cee83..9ea113969c8 100644 --- a/doc/ci/services/mysql.md +++ b/doc/ci/services/mysql.md @@ -25,6 +25,12 @@ variables: MYSQL_ROOT_PASSWORD: "<your_mysql_password>" ``` +NOTE: **Note:** +The `MYSQL_DATABASE` and `MYSQL_ROOT_PASSWORD` variables can't be set in the GitLab UI. +To set them, assign them to a variable [in the UI](../variables/README.md#via-the-ui), +and then assign that variable to the +`MYSQL_DATABASE` and `MYSQL_ROOT_PASSWORD` variables in your `.gitlab-ci.yml`. + And then configure your application to use the database, for example: ```yaml diff --git a/doc/ci/services/postgres.md b/doc/ci/services/postgres.md index b72dd6e920a..142f4f262e5 100644 --- a/doc/ci/services/postgres.md +++ b/doc/ci/services/postgres.md @@ -25,6 +25,13 @@ variables: POSTGRES_PASSWORD: "" ``` +NOTE: **Note:** +The `POSTGRES_DB`, `POSTGRES_USER`, and `POSTGRES_PASSWORD` variables can't be set in +the GitLab UI. To set them, assign them to a variable +[in the UI](../variables/README.md#via-the-ui), and then assign that +variable to the `POSTGRES_DB`, `POSTGRES_USER`, and `POSTGRES_PASSWORD` variables in +your `.gitlab-ci.yml`. + And then configure your application to use the database, for example: ```yaml diff --git a/doc/ci/triggers/README.md b/doc/ci/triggers/README.md index d1f9aa03b6b..2a382f18038 100644 --- a/doc/ci/triggers/README.md +++ b/doc/ci/triggers/README.md @@ -97,17 +97,6 @@ overview of the time the triggers were last used. ![Triggers page overview](img/triggers_page.png) -## Taking ownership of a trigger - -> **Note**: -GitLab 9.0 introduced a trigger ownership to solve permission problems. - -Each created trigger when run will impersonate their associated user including -their access to projects and their project permissions. - -You can take ownership of existing triggers by clicking *Take ownership*. -From now on the trigger will be run as you. - ## Revoking a trigger You can revoke a trigger any time by going at your project's @@ -282,8 +271,7 @@ Old triggers, created before GitLab 9.0 will be marked as legacy. Triggers with the legacy label do not have an associated user and only have access to the current project. They are considered deprecated and will be -removed with one of the future versions of GitLab. You are advised to -[take ownership](#taking-ownership-of-a-trigger) of any legacy triggers. +removed with one of the future versions of GitLab. [ee-2017]: https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/2017 [ee-2346]: https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/2346 diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md index 001f951ebb8..09b9fc87986 100644 --- a/doc/ci/yaml/README.md +++ b/doc/ci/yaml/README.md @@ -505,7 +505,7 @@ Feature.enable(:allow_unsafe_ruby_regexp) ### `only`/`except` (advanced) CAUTION: **Warning:** -This an _alpha_ feature, and it is subject to change at any time without +This is an _alpha_ feature, and it is subject to change at any time without prior notice! GitLab supports both simple and complex strategies, so it's possible to use an diff --git a/doc/development/README.md b/doc/development/README.md index ea5d9e10e2c..99c88146be5 100644 --- a/doc/development/README.md +++ b/doc/development/README.md @@ -113,6 +113,10 @@ description: 'Learn how to contribute to GitLab.' - [Database helper modules](database_helpers.md) - [Code comments](code_comments.md) +## Case studies + +- [Database case study: Filtering by label](filtering_by_label.md) + ## Integration guides - [Jira Connect app](integrations/jira_connect.md) diff --git a/doc/development/chaos_endpoints.md b/doc/development/chaos_endpoints.md index eb6dde2d24e..961520db7d8 100644 --- a/doc/development/chaos_endpoints.md +++ b/doc/development/chaos_endpoints.md @@ -69,7 +69,7 @@ curl http://localhost:3000/-/chaos/leakmem?memory_mb=1024&duration_s=10&token=se This endpoint attempts to fully utilise a single core, at 100%, for the given period. -Depending on your rack server setup, your request may timeout after a predermined period (normally 60 seconds). +Depending on your rack server setup, your request may timeout after a predetermined period (normally 60 seconds). If you're using Unicorn, this is done by killing the worker process. ``` @@ -80,7 +80,7 @@ GET /-/chaos/cpu_spin?duration_s=50&async=true | Attribute | Type | Required | Description | | ------------ | ------- | -------- | --------------------------------------------------------------------- | -| `duration_s` | integer | no | Duration, in seconds, that the core will be utilised. Defaults to 30s | +| `duration_s` | integer | no | Duration, in seconds, that the core will be utilized. Defaults to 30s | | `async` | boolean | no | Set to true to consume CPU in a Sidekiq background worker process | ```bash @@ -93,7 +93,7 @@ curl http://localhost:3000/-/chaos/cpu_spin?duration_s=60&token=secret This endpoint attempts to fully utilise a single core, and interleave it with DB request, for the given period. This endpoint can be used to model yielding execution to another threads when running concurrently. -Depending on your rack server setup, your request may timeout after a predermined period (normally 60 seconds). +Depending on your rack server setup, your request may timeout after a predetermined period (normally 60 seconds). If you're using Unicorn, this is done by killing the worker process. ``` @@ -105,7 +105,7 @@ GET /-/chaos/db_spin?duration_s=50&async=true | Attribute | Type | Required | Description | | ------------ | ------- | -------- | --------------------------------------------------------------------------- | | `interval_s` | float | no | Interval, in seconds, for every DB request. Defaults to 1s | -| `duration_s` | integer | no | Duration, in seconds, that the core will be utilised. Defaults to 30s | +| `duration_s` | integer | no | Duration, in seconds, that the core will be utilized. Defaults to 30s | | `async` | boolean | no | Set to true to perform the operation in a Sidekiq background worker process | ```bash diff --git a/doc/development/code_review.md b/doc/development/code_review.md index 709cd0c806b..b7d74b17eb3 100644 --- a/doc/development/code_review.md +++ b/doc/development/code_review.md @@ -365,6 +365,31 @@ Enterprise Edition instance. This has some implications: 1. **Filesystem access** can be slow, so try to avoid [shared files](shared_files.md) when an alternative solution is available. +## Examples + +How code reviews are conducted can surprise new contributors. Here are some examples of code reviews that should help to orient you as to what to expect. + +**["Modify `DiffNote` to reuse it for Designs"](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/13703):** +It contained everything from nitpicks around newlines to reasoning +about what versions for designs are, how we should compare them +if there was no previous version of a certain file (parent vs. +blank `sha` vs empty tree). + +**["Support multi-line suggestions"](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/25211)**: +The MR itself consists of a collaboration between FE and BE, +and documenting comments from the author for the reviewer. +There's some nitpicks, some questions for information, and +towards the end, a security vulnerability. + +**["Allow multiple repositories per project"](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/10251)**: +ZJ referred to the other projects (workhorse) this might impact, +suggested some improvements for consistency. And James' comments +helped us with overall code quality (using delegation, `&.` those +types of things), and making the code more robust. + +**["Support multiple assignees for merge requests"](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/10161)**: +A good example of collaboration on an MR touching multiple parts of the codebase. Nick pointed out interesting edge cases, James Lopes also joined in raising concerns on import/export feature. + ### Credits Largely based on the [thoughtbot code review guide]. diff --git a/doc/development/contributing/community_roles.md b/doc/development/contributing/community_roles.md index 3296cb173d7..7d2d1b77a0e 100644 --- a/doc/development/contributing/community_roles.md +++ b/doc/development/contributing/community_roles.md @@ -1,4 +1,4 @@ -### Community members & roles +# Community members & roles GitLab community members and their privileges/responsibilities. diff --git a/doc/development/contributing/style_guides.md b/doc/development/contributing/style_guides.md index 5c6ea1f469d..7832850a9f0 100644 --- a/doc/development/contributing/style_guides.md +++ b/doc/development/contributing/style_guides.md @@ -23,6 +23,7 @@ 1. Code should be written in [US English][us-english] 1. [Go](../go_guide/index.md) 1. [Python](../python_guide/index.md) +1. [Shell scripting](../shell_scripting_guide/index.md) This is also the style used by linting tools such as [RuboCop](https://github.com/rubocop-hq/rubocop) and [Hound CI](https://houndci.com). diff --git a/doc/development/database_review.md b/doc/development/database_review.md index 1413c2f69fb..3d10a0c84e5 100644 --- a/doc/development/database_review.md +++ b/doc/development/database_review.md @@ -68,6 +68,17 @@ make sure you have applied the ~database label and rerun the `danger-review` CI job, or pick someone from the [`@gl-database` team](https://gitlab.com/groups/gl-database/-/group_members). +### How to prepare for speedy database reviews + +In order to make reviewing easier and therefore faster, please consider preparing a comment +and details for a database reviewer: + +- Provide queries in SQL form rather than ActiveRecord. +- Format any queries with a SQL query formatter, for example with [sqlformat.darold.net](http://sqlformat.darold.net). +- Consider providing query plans via a link to [explain.depesz.com](https://explain.depesz.com) or another tool instead of textual form. +- For query changes, it is best to provide the SQL query along with a plan *before* and *after* the change. This helps to spot differences quickly. +- When providing query plans, make sure to use good parameter values, so that the query executed is a good example and also hits enough data. Usually, the `gitlab-org` namespace (`namespace_id = 9970`) and the `gitlab-org/gitlab-ce` project (`project_id = 13083`) provides enough data to serve as a good example. + ### How to review for database - Check migrations diff --git a/doc/development/documentation/index.md b/doc/development/documentation/index.md index 8ce855594df..d717b17136e 100644 --- a/doc/development/documentation/index.md +++ b/doc/development/documentation/index.md @@ -57,35 +57,22 @@ See the [Structure](styleguide.md#structure) section of the [Documentation Style We currently maintain two sets of docs: one in the [gitlab-ce](https://gitlab.com/gitlab-org/gitlab-ce/tree/master/doc) repo and one in [gitlab-ee](https://gitlab.com/gitlab-org/gitlab-ee/tree/master/doc). -They are similar, and most pages are identical, but they are different repositories. -With the single codebase effort, we want to make those two sets identical, so when the -time comes to have only one codebase, we'll be ready. - -Here are some links to get you up to speed with the current effort: - -- [CE/EE codebases blueprint](https://about.gitlab.com/handbook/engineering/infrastructure/blueprint/ce-ee-codebases/) -- [CE/EE codebases merge design](https://about.gitlab.com/handbook/engineering/infrastructure/design/merge-ce-ee-codebases/) -- [Single docs codebase epic](https://gitlab.com/groups/gitlab-org/-/epics/199) -- [Issue board of related issues](https://gitlab.com/groups/gitlab-org/-/boards/981090?&label_name[]=Documentation&label_name[]=single%20codebase) -- [Related merge requests](https://gitlab.com/groups/gitlab-org/-/merge_requests?scope=all&utf8=%E2%9C%93&state=all&label_name[]=Documentation&label_name[]=single%20codebase) -- [Visualize the existing diffs](https://leipert-projects.gitlab.io/is-gitlab-pretty-yet/diff/?search=%5Edoc) +They are identical, but they are different repositories. When the +time comes to have only one codebase for the GitLab project, we'll be ready. ### CE first -After a given documentation path is aligned across CE and EE, all merge requests -affecting that path must be submitted to CE, regardless of the content it has. -This means that: +All merge requests for documentation must be submitted to CE, regardless of the content +it has. This means that: -- For **EE-only docs changes**, you only have to submit a CE MR. +- For **EE-only docs changes**, you only have to submit an MR in the CE project. - For **EE-only features** that touch both the code and the docs, you have to submit - an EE MR containing all changes, and a CE MR containing only the docs changes + an EE MR containing all code changes, and a CE MR containing only the docs changes and without a changelog entry. This might seem like a duplicate effort, but it's only for the short term. -A list of the already aligned docs can be found in -[the epic description](https://gitlab.com/groups/gitlab-org/-/epics/199#ee-specific-lines-check). -Since the docs will be combined, it's crucial to add the relevant +Since the CE and EE docs are combined, it's crucial to add the relevant [product badges](styleguide.md#product-badges) for all EE documentation, so that we can discern which features belong to which tier. @@ -94,19 +81,9 @@ we can discern which features belong to which tier. There's a special test in place ([`ee_specific_check.rb`](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/scripts/ee_specific_check/ee_specific_check.rb)), which, among others, checks and prevents creating/editing new files and directories -in EE under `doc/`. - -We have a long list of documentation paths that are either whitelisted or not. -Paths in the whitelist (not commented out) will not be subject to the test, -which means you are allowed to create/change docs content in EE for the time -being. The goal is to not have any doc whitelisted. - -At the time of this writing, the only items left to be aligned are the API docs: - -- `doc/api/*` ([issue](https://gitlab.com/gitlab-org/gitlab-ce/issues/60045) / [merge request](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/27491)) - -Eventually, once all docs are aligned, we'll remove any doc reference from that -script, so it catches everything. +in EE under `doc/`. This should fail when changes to anything in `/doc` are submitted +in an EE MR. To pass the test, simply remove the docs changes from the EE MR, and +[submit them in CE](#ce-first). ## Changing document location diff --git a/doc/development/documentation/styleguide.md b/doc/development/documentation/styleguide.md index 36ffc02644e..dd798777c12 100644 --- a/doc/development/documentation/styleguide.md +++ b/doc/development/documentation/styleguide.md @@ -1092,6 +1092,6 @@ curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" --data "domain_ [cURL]: http://curl.haxx.se/ "cURL website" [single spaces]: http://www.slate.com/articles/technology/technology/2011/01/space_invaders.html -[gfm]: https://docs.gitlab.com/ce/user/markdown.html#newlines "GitLab flavored markdown documentation" +[gfm]: ../../user/markdown.md#newlines "GitLab flavored markdown documentation" [ce-1242]: https://gitlab.com/gitlab-org/gitlab-ce/issues/1242 [doc-restart]: ../../administration/restart_gitlab.md "GitLab restart documentation" diff --git a/doc/development/fe_guide/axios.md b/doc/development/fe_guide/axios.md index 0d9397c3bd5..09b4a3c3d96 100644 --- a/doc/development/fe_guide/axios.md +++ b/doc/development/fe_guide/axios.md @@ -1,15 +1,18 @@ # Axios + We use [axios][axios] to communicate with the server in Vue applications and most new code. In order to guarantee all defaults are set you *should not use `axios` directly*, you should import `axios` from `axios_utils`. ## CSRF token + All our request require a CSRF token. To guarantee this token is set, we are importing [axios][axios], setting the token, and exporting `axios` . This exported module should be used instead of directly using `axios` to ensure the token is set. ## Usage + ```javascript import axios from './lib/utils/axios_utils'; diff --git a/doc/development/fe_guide/style_guide_scss.md b/doc/development/fe_guide/style_guide_scss.md index f895cfd36ac..95c4a094c04 100644 --- a/doc/development/fe_guide/style_guide_scss.md +++ b/doc/development/fe_guide/style_guide_scss.md @@ -212,6 +212,7 @@ selectors are intended for use only with JavaScript to allow for removal or renaming without breaking styling. ### IDs + Don't use ID selectors in CSS. ```scss diff --git a/doc/development/filtering_by_label.md b/doc/development/filtering_by_label.md new file mode 100644 index 00000000000..6e6b71b1787 --- /dev/null +++ b/doc/development/filtering_by_label.md @@ -0,0 +1,166 @@ +# Filtering by label + +## Introduction + +GitLab has [labels](../user/project/labels.md) that can be assigned to issues, +merge requests, and epics. Labels on those objects are a many-to-many relation +through the polymorphic `label_links` table. + +To filter these objects by multiple labels - for instance, 'all open +issues with the label ~Plan and the label ~backend' - we generate a +query containing a `GROUP BY` clause. In a simple form, this looks like: + +```sql +SELECT + issues.* +FROM + issues + INNER JOIN label_links ON label_links.target_id = issues.id + AND label_links.target_type = 'Issue' + INNER JOIN labels ON labels.id = label_links.label_id +WHERE + issues.project_id = 13083 + AND (issues.state IN ('opened')) + AND labels.title IN ('Plan', + 'backend') +GROUP BY + issues.id +HAVING (COUNT(DISTINCT labels.title) = 2) +ORDER BY + issues.updated_at DESC, + issues.id DESC +LIMIT 20 OFFSET 0 +``` + +In particular, note that: + +1. We `GROUP BY issues.id` so that we can ... +2. Use the `HAVING (COUNT(DISTINCT labels.title) = 2)` condition to ensure that + all matched issues have both labels. + +This is more complicated than is ideal. It makes the query construction more +prone to errors (such as +[gitlab-org/gitlab-ce#15557](https://gitlab.com/gitlab-org/gitlab-ce/issues/15557)). + +## Attempt A: WHERE EXISTS + +### Attempt A1: use multiple subqueries with WHERE EXISTS + +In +[gitlab-org/gitlab-ce#37137](https://gitlab.com/gitlab-org/gitlab-ce/issues/37137) +and its associated merge request +[gitlab-org/gitlab-ce!14022](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/14022), +we tried to replace the `GROUP BY` with multiple uses of `WHERE EXISTS`. For the +example above, this would give: + +```sql +WHERE (EXISTS ( + SELECT + TRUE + FROM + label_links + INNER JOIN labels ON labels.id = label_links.label_id + WHERE + labels.title = 'Plan' + AND target_type = 'Issue' + AND target_id = issues.id)) +AND (EXISTS ( + SELECT + TRUE + FROM + label_links + INNER JOIN labels ON labels.id = label_links.label_id + WHERE + labels.title = 'backend' + AND target_type = 'Issue' + AND target_id = issues.id)) +``` + +While this worked without schema changes, and did improve readability somewhat, +it did not improve query performance. + +## Attempt B: Denormalize using an array column + +Having [removed MySQL support in GitLab +12.1](https://about.gitlab.com/2019/06/27/removing-mysql-support/), using +[Postgres's arrays](https://www.postgresql.org/docs/9.6/arrays.html) became more +tractable as we didn't have to support two databases. We discussed denormalizing +the `label_links` table for querying in +[gitlab-org/gitlab-ce#49651](https://gitlab.com/gitlab-org/gitlab-ce/issues/49651), +with two options: label IDs and titles. + +We can think of both of those as array columns on `issues`, `merge_requests`, +and `epics`: `issues.label_ids` would be an array column of label IDs, and +`issues.label_titles` would be an array of label titles. + +These array columns can be complemented with [GIN +indexes](https://www.postgresql.org/docs/9.6/gin-intro.html) to improve +matching. + +### Attempt B1: store label IDs for each object + +This has some strong advantages over titles: + +1. Unless a label is deleted, or a project is moved, we never need to + bulk-update the denormalized column. +2. It uses less storage than the titles. + +Unfortunately, our application design makes this hard. If we were able to query +just by label ID easily, we wouldn't need the `INNER JOIN labels` in the initial +query at the start of this document. GitLab allows users to filter by label +title across projects and even across groups, so a filter by the label ~Plan may +include labels with multiple distinct IDs. + +We do not want users to have to know about the different IDs, which means that +given this data set: + +| Project | ~Plan label ID | ~backend label ID | +| --- | --- | --- | +| A | 11 | 12 | +| B | 21 | 22 | +| C | 31 | 32 | + +We would need something like: + +```sql +WHERE + label_ids @> ARRAY[11, 12] + OR label_ids @> ARRAY[21, 22] + OR label_ids @> ARRAY[31, 32] +``` + +This can get even more complicated when we consider that in some cases, there +might be two ~backend labels - with different IDs - that could apply to the same +object, so the number of combinations would balloon further. + +### Attempt B2: store label titles for each object + +From the perspective of updating the labelable object, this is the worst +option. We have to bulk update the objects when: + +1. The objects are moved from one project to another. +1. The project is moved from one group to another. +1. The label is renamed. +1. The label is deleted. + +It also uses much more storage. Querying is simple, though: + +```sql +WHERE + label_titles @> ARRAY['Plan', 'backend'] +``` + +And our [tests in +gitlab-org/gitlab-ce#49651](https://gitlab.com/gitlab-org/gitlab-ce/issues/49651#note_188777346) +showed that this could be fast. + +However, at present, the disadvantages outweigh the advantages. + +## Conclusion + +We have yet to find a method that is demonstratably better than the current +method, when considering: + +1. Query performance. +1. Readability. +1. Ease of maintaining schema consistency. diff --git a/doc/development/go_guide/index.md b/doc/development/go_guide/index.md index f827d240bf6..9f0ac8cc753 100644 --- a/doc/development/go_guide/index.md +++ b/doc/development/go_guide/index.md @@ -173,6 +173,45 @@ func Test(t *testing.T) { } ``` +### Table-Driven Tests + +Using [Table-Driven Tests](https://github.com/golang/go/wiki/TableDrivenTests) +is generally good practice when you have multiple entries of +inputs/outputs for the same function. Below are some guidelines one can +follow when writing table-driven test. These guidelines are mostly +extracted from Go standard library source code. Keep in mind it's OK not +to follow these guidelines when it makes sense. + +#### Defining test cases + +Each table entry is a complete test case with inputs and expected +results, and sometimes with additional information such as a test name +to make the test output easily readable. + +- [Define a slice of anonymous struct](https://github.com/golang/go/blob/50bd1c4d4eb4fac8ddeb5f063c099daccfb71b26/src/encoding/csv/reader_test.go#L16) + inside of the test. +- [Define a slice of anonymous struct](https://github.com/golang/go/blob/55d31e16c12c38d36811bdee65ac1f7772148250/src/cmd/go/internal/module/module_test.go#L9-L66) + outside of the test. +- [Named structs](https://github.com/golang/go/blob/2e0cd2aef5924e48e1ceb74e3d52e76c56dd34cc/src/cmd/go/internal/modfetch/coderepo_test.go#L54-L69) + for code reuse. +- [Using `map[string]struct{}`](https://github.com/golang/go/blob/6d5caf38e37bf9aeba3291f1f0b0081f934b1187/src/cmd/trace/annotations_test.go#L180-L235). + +#### Contents of the test case + +- Ideally, each test case should have a field with a unique identifier + to use for naming subtests. In the Go standard library, this is commonly the + `name string` field. +- Use `want`/`expect`/`actual` when you are specifcing something in the + test case that will be used for assertion. + +#### Variable names + +- Each table-driven test map/slice of struct can be named `tests`. +- When looping through `tests` the anonymous struct can be referred + to as `tt` or `tc`. +- The description of the test can be referred to as + `name`/`testName`/`tn`. + ### Benchmarks Programs handling a lot of IO or complex operations should always include diff --git a/doc/development/import_export.md b/doc/development/import_export.md index 4c78c62f5f5..0c343bc22e4 100644 --- a/doc/development/import_export.md +++ b/doc/development/import_export.md @@ -19,6 +19,7 @@ Project.find_by_full_path('group/project').import_state.slice(:jid, :status, :la grep JID /var/log/gitlab/sidekiq/current grep "Import/Export error" /var/log/gitlab/sidekiq/current grep "Import/Export backtrace" /var/log/gitlab/sidekiq/current +tail /var/log/gitlab/gitlab-rails/importer.log ``` ## Troubleshooting performance issues diff --git a/doc/development/module_with_instance_variables.md b/doc/development/module_with_instance_variables.md index 7bdfa04fc57..443eee0b62c 100644 --- a/doc/development/module_with_instance_variables.md +++ b/doc/development/module_with_instance_variables.md @@ -1,6 +1,6 @@ -## Modules with instance variables could be considered harmful +# Modules with instance variables could be considered harmful -### Background +## Background Rails somehow encourages people using modules and instance variables everywhere. For example, using instance variables in the controllers, @@ -9,7 +9,7 @@ helpers, and views. They're also encouraging the use of saving everything in a giant, single object, and people could access everything in that one giant object. -### The problems +## The problems Of course this is convenient to develop, because we just have everything within reach. However this has a number of downsides when that chosen object @@ -24,7 +24,7 @@ manipulated from 3 different modules. It's hard to track when those variables start giving us troubles. We don't know which module would suddenly change one of the variables. Everything could touch anything. -### Similar concerns +## Similar concerns People are saying multiple inheritance is bad. Mixing multiple modules with multiple instance variables scattering everywhere suffer from the same issue. @@ -40,7 +40,7 @@ Note that `included` doesn't solve the whole issue. They define the dependencies, but they still allow each modules to talk implicitly via the instance variables in the final giant object, and that's where the problem is. -### Solutions +## Solutions We should split the giant object into multiple objects, and they communicate with each other with the API, i.e. public methods. In short, composition over @@ -53,7 +53,7 @@ With clearly defined API, this would make things less coupled and much easier to debug and track, and much more extensible for other objects to use, because they communicate in a clear way, rather than implicit dependencies. -### Acceptable use +## Acceptable use However, it's not always bad to use instance variables in a module, as long as it's contained in the same module; that is, no other modules or @@ -74,7 +74,7 @@ Unfortunately it's not easy to code more complex rules into the cop, so we rely on people's best judgement. If we could find another good pattern we could easily add to the cop, we should do it. -### How to rewrite and avoid disabling this cop +## How to rewrite and avoid disabling this cop Even if we could just disable the cop, we should avoid doing so. Some code could be easily rewritten in simple form. Consider this acceptable method: @@ -181,7 +181,7 @@ rather than whatever includes the module, and those modules which were also included, making it much easier to track down any issues, and reducing the chance of having name conflicts. -### How to disable this cop +## How to disable this cop Put the disabling comment right after your code in the same line: @@ -210,14 +210,14 @@ end Note that you need to enable it at some point, otherwise everything below won't be checked. -### Things we might need to ignore right now +## Things we might need to ignore right now Because of the way Rails helpers and mailers work, we might not be able to avoid the use of instance variables there. For those cases, we could ignore them at the moment. At least we're not going to share those modules with other random objects, so they're still somewhat isolated. -### Instance variables in views +## Instance variables in views They're bad because we can't easily tell who's using the instance variables (from controller's point of view) and where we set them up (from partials' diff --git a/doc/development/new_fe_guide/dependencies.md b/doc/development/new_fe_guide/dependencies.md index 12a4f089d41..8a6930acd37 100644 --- a/doc/development/new_fe_guide/dependencies.md +++ b/doc/development/new_fe_guide/dependencies.md @@ -15,6 +15,18 @@ Exceptions are made for some tools that we require in the `gitlab:assets:compile` CI job such as `webpack-bundle-analyzer` to analyze our production assets post-compile. +To add or upgrade a dependency, run: + +```sh +yarn add <your dependency here> +``` + +This may introduce duplicate dependencies. To de-duplicate `yarn.lock`, run: + +```sh +node_modules/.bin/yarn-deduplicate --list --strategy fewer yarn.lock && yarn install +``` + --- > TODO: Add Dependencies diff --git a/doc/development/new_fe_guide/development/accessibility.md b/doc/development/new_fe_guide/development/accessibility.md index 81a29170129..ae5c4c6a6cc 100644 --- a/doc/development/new_fe_guide/development/accessibility.md +++ b/doc/development/new_fe_guide/development/accessibility.md @@ -1,17 +1,21 @@ # Accessiblity + Using semantic HTML plays a key role when it comes to accessibility. ## Accessible Rich Internet Applications - ARIA + WAI-ARIA, the Accessible Rich Internet Applications specification, defines a way to make Web content and Web applications more accessible to people with disabilities. > Note: It is [recommended][using-aria] to use semantic elements as the primary method to achieve accessibility rather than adding aria attributes. Adding aria attributes should be seen as a secondary method for creating accessible elements. ### Role + The `role` attribute describes the role the element plays in the context of the document. Check the list of WAI-ARIA roles [here][roles] ## Icons + When using icons or images that aren't absolutely needed to understand the context, we should use `aria-hidden="true"`. On the other hand, if an icon is crucial to understand the context we should do one of the following: @@ -20,6 +24,7 @@ On the other hand, if an icon is crucial to understand the context we should do 1. Use `aria-labelledby` to point to an element that contains the explanation for that icon ## Form inputs + In forms we should use the `for` attribute in the label statement: ``` diff --git a/doc/development/new_fe_guide/style/index.md b/doc/development/new_fe_guide/style/index.md index 335d9e66240..f073dc56f1f 100644 --- a/doc/development/new_fe_guide/style/index.md +++ b/doc/development/new_fe_guide/style/index.md @@ -8,7 +8,7 @@ ## [Vue style guide](vue.md) -# Tooling +## Tooling ## [Prettier](prettier.md) diff --git a/doc/development/reusing_abstractions.md b/doc/development/reusing_abstractions.md index 59da02ed6fd..fce144f8dc2 100644 --- a/doc/development/reusing_abstractions.md +++ b/doc/development/reusing_abstractions.md @@ -14,13 +14,13 @@ on maintainability, the ability to easily debug problems, or even performance. An example would be to use `ProjectsFinder` in `IssuesFinder` to limit issues to those belonging to a set of projects. While initially this may seem like a good idea, both classes provide a very high level interface with very little control. -This means that `IssuesFinder` may not be able to produce a better optimised +This means that `IssuesFinder` may not be able to produce a better optimized database query, as a large portion of the query is controlled by the internals of `ProjectsFinder`. To work around this problem, you would use the same code used by `ProjectsFinder`, instead of using `ProjectsFinder` itself directly. This allows -you to compose your behaviour better, giving you more control over the behaviour +you to compose your behavior better, giving you more control over the behavior of the code. To illustrate, consider the following code from `IssuableFinder#projects`: @@ -52,7 +52,7 @@ functionality is added to this (high level) interface. Instead of _only_ affecting the cases where this is necessary, it may also start affecting `IssuableFinder` in a negative way. For example, the query produced by `GroupProjectsFinder` may include unnecessary conditions. Since we're using a -finder here, we can't easily opt-out of that behaviour. We could add options to +finder here, we can't easily opt-out of that behavior. We could add options to do so, but then we'd need as many options as we have features. Every option adds two code paths, which means that for four features we have to cover 8 different code paths. @@ -213,6 +213,5 @@ The API provided by Active Record itself, such as the `where` method, `save`, Everything in `app/workers`. -The scheduling of Sidekiq jobs using `SomeWorker.perform_async`, `perform_in`, -etc. Directly invoking a worker using `SomeWorker.new.perform` should be avoided -at all times in application code, though this is fine to use in tests. +Use `SomeWorker.perform_async` or `SomeWorker.perform_in` to schedule Sidekiq +jobs. Never directly invoke a worker using `SomeWorker.new.perform`. diff --git a/doc/development/shell_scripting_guide/index.md b/doc/development/shell_scripting_guide/index.md new file mode 100644 index 00000000000..ae7f2154682 --- /dev/null +++ b/doc/development/shell_scripting_guide/index.md @@ -0,0 +1,117 @@ +# Shell scripting standards and style guidelines + +## Overview + +GitLab consists of many various services and sub-projects. The majority of +their backend code is written in [Ruby](https://www.ruby-lang.org) and +[Go](https://golang.org). However, some of them use shell scripts for +automation of routine system administration tasks like deployment, +installation, etc. It's being done either for historical reasons or as an effort +to minimize the dependencies, for instance, for Docker images. + +This page aims to define and organize our shell scripting guidelines, +based on our various experiences. All shell scripts across GitLab project +should be eventually harmonized with this guide. If there are any per-project +deviations from this guide, they should be described in the +`README.md` or `PROCESS.md` file for such a project. + +### Avoid using shell scripts + +CAUTION: **Caution:** +This is a must-read section. + +Having said all of the above, we recommend staying away from shell scripts +as much as possible. A language like Ruby or Python (if required for +consistency with codebases that we leverage) is almost always a better choice. +The high-level interpreted languages have more readable syntax, offer much more +mature capabilities for unit-testing, linting, and error reporting. +Use shell scripts only if there's a strong restriction on project's +dependencies size or any other requirements that are more important +in a particular case. + +## Scope of this guide + +According to the [GitLab installation requirements](../../install/requirements.md), +this guide covers only those shells that are used by +[supported Linux distributions](../../install/requirements.md#supported-linux-distributions), +that is: + +- [POSIX Shell](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html) +- [Bash](https://www.gnu.org/software/bash/) + +## Shell language choice + +- When you need to reduce the dependencies list, use what's provided by the environment. For example, for Docker images it's `sh` from `alpine` which is the base image for most of our tool images. +- Everywhere else, use `bash` if possible. It's more powerful than `sh` but still a widespread shell. + +## Code style and format + +This section describes the tools that should be made a mandatory part of +a project's CI pipeline if it contains shell scripts. These tools +automate shell code formatting, checking for errors or vulnerabilities, etc. + +### Linting + +We're using the [ShellCheck](https://www.shellcheck.net/) utility in its default configuration to lint our +shell scripts. + +All projects with shell scripts should use this GitLab CI/CD job: + +```yaml +shell check: + image: koalaman/shellcheck-alpine + stage: test + before_script: + - shellcheck --version + script: + - shellcheck scripts/**/*.sh # path to your shell scripts +``` + +TIP: **Tip:** +By default, ShellCheck will use the [shell detection](https://github.com/koalaman/shellcheck/wiki/SC2148#rationale) +to determine the shell dialect in use. If the shell file is out of your control and ShellCheck cannot +detect the dialect, use `-s` flag to specify it: `-s sh` or `-s bash`. + +### Formatting + +It's recommended to use the [shfmt](https://github.com/mvdan/sh#shfmt) tool to maintain consistent formatting. +We format shell scripts according to the [Google Shell Style Guide](https://google.github.io/styleguide/shell.xml), +so the following `shfmt` invocation should be applied to the project's script files: + +```bash +shfmt -i 2 -ci scripts/**/*.sh +``` + +TIP: **Tip:** +By default, shfmt will use the [shell detection](https://github.com/mvdan/sh#shfmt) similar to one of ShellCheck +and ignore files starting with a period. To override this, use `-ln` flag to specify the shell dialect: +`-ln posix` or `-ln bash`. + +NOTE: **Note:** +Currently, the `shfmt` tool [is not shipped](https://github.com/mvdan/sh/issues/68) as a Docker image containing +a Linux shell. This makes it impossible to use the [official Docker image](https://hub.docker.com/r/mvdan/shfmt) +in GitLab Runner. This [may change](https://github.com/mvdan/sh/issues/68#issuecomment-507721371) in future. + +## Testing + +NOTE: **Note:** +This is a work in progress. + +It is an [ongoing effort](https://gitlab.com/gitlab-org/gitlab-ce/issues/64016) to evaluate different tools for the +automated testing of shell scripts (like [BATS](https://github.com/sstephenson/bats)). + +## Code Review + +The code review should be performed according to: + +- [ShellCheck Checks list](https://github.com/koalaman/shellcheck/wiki/Checks) +- [Google Shell Style Guide](https://google.github.io/styleguide/shell.xml) +- [Shfmt formatting caveats](https://github.com/mvdan/sh#caveats) + +However, the recommended course of action is to use the aforementioned +tools and address reported offenses. This should eliminate the need +for code review. + +--- + +[Return to Development documentation](../README.md). diff --git a/doc/development/testing_guide/frontend_testing.md b/doc/development/testing_guide/frontend_testing.md index ff28c2ea5e2..2985278cc92 100644 --- a/doc/development/testing_guide/frontend_testing.md +++ b/doc/development/testing_guide/frontend_testing.md @@ -588,7 +588,7 @@ end [jasmine-focus]: https://jasmine.github.io/2.5/focused_specs.html [karma]: http://karma-runner.github.io/ -[vue-test]: https://docs.gitlab.com/ce/development/fe_guide/vue.html#testing-vue-components +[vue-test]: ../fe_guide/vue.md#testing-vue-components [rspec]: https://github.com/rspec/rspec-rails#feature-specs [capybara]: https://github.com/teamcapybara/capybara [jasmine]: https://jasmine.github.io/ diff --git a/doc/development/verifying_database_capabilities.md b/doc/development/verifying_database_capabilities.md index 661ab9cef1a..ccec6f7d719 100644 --- a/doc/development/verifying_database_capabilities.md +++ b/doc/development/verifying_database_capabilities.md @@ -25,7 +25,7 @@ else end ``` -# Read-only database +## Read-only database The database can be used in read-only mode. In this case we have to make sure all GET requests don't attempt any write operations to the diff --git a/doc/gitlab-basics/README.md b/doc/gitlab-basics/README.md index fd16047b8e4..fc3d36910f2 100644 --- a/doc/gitlab-basics/README.md +++ b/doc/gitlab-basics/README.md @@ -1,15 +1,18 @@ --- comments: false +type: index --- # GitLab basics guides -This section provides resources to help you start with GitLab by focusing on basic functionality. +This section provides resources to help you start working with GitLab and Git by focusing +on the basic features that you will need to use. This documentation is split into the following groups: - [GitLab-specific functionality](#gitlab-basics), for basic GitLab features. -- [General Git functionality](#git-basics), for working with Git in conjunction with GitLab. +- [General Git functionality](#working-with-git-from-the-command-line), for working + with Git in conjunction with GitLab. ## GitLab basics @@ -17,22 +20,26 @@ The following are guides to basic GitLab functionality: - [Create and add your SSH public key](create-your-ssh-keys.md), for enabling Git over SSH. - [Create a project](create-project.md), to start using GitLab. -- [Create a group](../user/group/index.md#create-a-new-group), to combine and administer projects together. +- [Create a group](../user/group/index.md#create-a-new-group), to combine and administer + projects together. - [Create a branch](create-branch.md), to make changes to files stored in a project's repository. - [Fork a project](fork-project.md), to duplicate projects so they can be worked on in parallel. - [Add a file](add-file.md), to add new files to a project's repository. -- [Add an image](add-image.md), to add new images to a project's repository. -- [Create an issue](../user/project/issues/managing_issues.md#create-a-new-issue), to start collaborating within a project. -- [Create a merge request](add-merge-request.md), to request changes made in a branch be merged into a project's repository. -- See how these features come together in the [GitLab Flow introduction video](https://youtu.be/InKNIvky2KE) and [GitLab Flow page](../workflow/gitlab_flow.md). +- [Create an issue](../user/project/issues/managing_issues.md#create-a-new-issue), + to start collaborating within a project. +- [Create a merge request](add-merge-request.md), to request changes made in a branch + be merged into a project's repository. +- See how these features come together in the [GitLab Flow introduction video](https://youtu.be/InKNIvky2KE) + and [GitLab Flow page](../workflow/gitlab_flow.md). -## Git basics +## Working with Git from the command line -If you're familiar with Git on the command line, you can interact with your GitLab projects just as you would with any other Git repository. +If you're familiar with Git on the command line, you can interact with your GitLab +projects just as you would with any other Git repository. These resources will help get further acclimated to working on the command line. - [Start using Git on the command line](start-using-git.md), for some simple Git commands. - [Command line basics](command-line-commands.md), to create and edit files using the command line. -More Git resources are available at GitLab's [Git documentation](../topics/git/index.md). +More Git resources are available in GitLab's [Git documentation](../topics/git/index.md). diff --git a/doc/gitlab-basics/add-file.md b/doc/gitlab-basics/add-file.md index e9fbcbc23a9..41cc8bc4aeb 100644 --- a/doc/gitlab-basics/add-file.md +++ b/doc/gitlab-basics/add-file.md @@ -1,5 +1,91 @@ -# How to add a file +--- +type: howto +--- -You can create a file in your [terminal](command-line-commands.md) and push -to GitLab or you can use the +# Add a file to a repository + +Adding files to a repository is a small, but key task. Bringing files in to a repository, +such as code, images, or documents, allows them to be tracked by Git, even though they +may have been created elsewhere. + +You can add a file to a repository in your [terminal](#add-a-file-using-the-command-line), and +then push to GitLab. You can also use the [web interface](../user/project/repository/web_editor.md#upload-a-file), +which may be a simpler solution. + +If you need to create a file first, for example a `README.md` text file, that can +also be done from the [terminal](command-line-commands.md#create-a-text-file-in-the-current-directory) or [web interface](../user/project/repository/web_editor.md#create-a-file). + +## Add a file using the command line + +Open a [terminal/shell](command-line-commands.md), and change into the folder of your +GitLab project. This usually means running the following command until you get +to the desired destination: + +```sh +cd <destination folder> +``` + +[Create a branch](create-branch.md) to add your file to, before it is added to the master +(main) branch of the project. It is not strictly necessary, but working directly in +the `master` branch is not recommended unless your project is very small, and you are +the only person working on it. You can [switch to an existing branch](start-using-git.md#work-on-an-existing-branch), +if you have one already. + +Using your standard tool for copying files (for example, Finder in macOS, or File Explorer +in Windows), put the file into a directory within the GitLab project. + +Check if your file is actually present in the directory (if you are in Windows, +use `dir` instead): + +```sh +ls +``` + +You should see the name of the file in the list shown. + +Check the status: + +```sh +git status +``` + +Your file's name should appear in red, so `git` took notice of it! Now add it +to the repository: + +```sh +git add <name of file> +``` + +Check the status again, your file's name should have turned green: + +```sh +git status +``` + +Commit (save) your file to the repository: + +```sh +git commit -m "DESCRIBE COMMIT IN A FEW WORDS" +``` + +Now you can push (send) your changes (in the branch `<branch-name>`) to GitLab +(the git remote named 'origin'): + +```sh +git push origin <branch-name> +``` + +Your image will be added to your branch in your repository in GitLab. + +<!-- ## Troubleshooting + +Include any troubleshooting steps that you can foresee. If you know beforehand what issues +one might have when setting this up, or when something is changed, or on upgrading, it's +important to describe those, too. Think of things that may go wrong and include them here. +This is important to minimize requests for support, and to avoid doc comments with +questions that you know someone might ask. + +Each scenario can be a third-level heading, e.g. `### Getting error message X`. +If you have none to add when creating a doc, leave this section in place +but commented out to help encourage others to add to it in the future. --> diff --git a/doc/gitlab-basics/add-image.md b/doc/gitlab-basics/add-image.md index 17c210c43e0..11a4a6bbd97 100644 --- a/doc/gitlab-basics/add-image.md +++ b/doc/gitlab-basics/add-image.md @@ -1,56 +1,5 @@ -# How to add an image +--- +redirect_to: 'add-file.md' +--- -Using your standard tool for copying files (e.g. Finder in Mac OS, or Explorer -in Windows, or...), put the image file into the GitLab project. You can find the -project as a regular folder in your files. - -Go to your [shell](command-line-commands.md), and move into the folder of your -GitLab project. This usually means running the following command until you get -to the desired destination: - -``` -cd NAME-OF-FOLDER-YOU'D-LIKE-TO-OPEN -``` - -Check if your image is actually present in the directory (if you are in Windows, -use `dir` instead): - -``` -ls -``` - -You should see the name of the image in the list shown. - -Check the status: - -``` -git status -``` - -Your image's name should appear in red, so `git` took notice of it! Now add it -to the repository: - -``` -git add NAME-OF-YOUR-IMAGE -``` - -Check the status again, your image's name should have turned green: - -``` -git status -``` - -Commit: - -``` -git commit -m "DESCRIBE COMMIT IN A FEW WORDS" -``` - -Now you can push (send) your changes (in the branch NAME-OF-BRANCH) to GitLab -(the git remote named 'origin'): - -``` -git push origin NAME-OF-BRANCH -``` - -Your image will be added to your branch in your repository in GitLab. +This document was moved to [another location](add-file.md). diff --git a/doc/gitlab-basics/add-merge-request.md b/doc/gitlab-basics/add-merge-request.md index 7bb2e014738..1a6a26152fa 100644 --- a/doc/gitlab-basics/add-merge-request.md +++ b/doc/gitlab-basics/add-merge-request.md @@ -1,9 +1,16 @@ +--- +type: howto +--- + # How to create a merge request -Merge requests are useful to integrate separate changes that you've made to a -project, on different branches. This is a brief guide on how to create a merge -request. For more information, check the -[merge requests documentation](../user/project/merge_requests/index.md). +Merge requests are how you integrate separate changes that you've made in a +[branch](create-branch.md) to a [project](create-project.md). + +This is a brief guide on how to create a merge request. For more detailed information, +check the [merge requests documentation](../user/project/merge_requests/index.md), or +you can watch our [GitLab Flow video](https://www.youtube.com/watch?v=InKNIvky2KE) for +a quick overview of working with merge requests. --- @@ -12,19 +19,31 @@ request. For more information, check the 1. Go to the project where you'd like to merge your changes and click on the **Merge requests** tab. 1. Click on **New merge request** on the right side of the screen. -1. From there on, you have the option to select the source branch and the target +1. From there, you have the option to select the source branch and the target branch you'd like to compare to. The default target project is the upstream repository, but you can choose to compare across any of its forks. - ![Select a branch](img/merge_request_select_branch.png) + ![Select a branch](img/merge_request_select_branch.png) 1. When ready, click on the **Compare branches and continue** button. 1. At a minimum, add a title and a description to your merge request. Optionally, - select a user to review your merge request and to accept or close it. You may - also select a milestone and labels. + select a user to review your merge request. You may also select a milestone and + labels. - ![New merge request page](img/merge_request_page.png) + ![New merge request page](img/merge_request_page.png) 1. When ready, click on the **Submit merge request** button. -Your merge request will be ready to be approved and merged. +Your merge request will be ready to be reviewed, approved, and merged. + +<!-- ## Troubleshooting + +Include any troubleshooting steps that you can foresee. If you know beforehand what issues +one might have when setting this up, or when something is changed, or on upgrading, it's +important to describe those, too. Think of things that may go wrong and include them here. +This is important to minimize requests for support, and to avoid doc comments with +questions that you know someone might ask. + +Each scenario can be a third-level heading, e.g. `### Getting error message X`. +If you have none to add when creating a doc, leave this section in place +but commented out to help encourage others to add to it in the future. --> diff --git a/doc/gitlab-basics/basic-git-commands.md b/doc/gitlab-basics/basic-git-commands.md index c2a3415cbc4..4e0cc2de2bc 100644 --- a/doc/gitlab-basics/basic-git-commands.md +++ b/doc/gitlab-basics/basic-git-commands.md @@ -1,3 +1,5 @@ -# Basic Git commands +--- +redirect_to: 'start-using-git.md' +--- -This section is now merged into [Start using Git](start-using-git.md). +This document was moved to [another location](start-using-git.md). diff --git a/doc/gitlab-basics/command-line-commands.md b/doc/gitlab-basics/command-line-commands.md index b8ebbbea9d4..ed70d3ce598 100644 --- a/doc/gitlab-basics/command-line-commands.md +++ b/doc/gitlab-basics/command-line-commands.md @@ -1,75 +1,47 @@ -# Command Line basic commands - -## Start working on your project - -In Git, when you copy a project you say you "clone" it. To work on a git project locally (from your own computer), you will need to clone it. To do this, sign in to GitLab. - -When you are on your Dashboard, click on the project that you'd like to clone. -To work in the project, you can copy a link to the Git repository through a SSH -or a HTTPS protocol. SSH is easier to use after it's been -[set up](create-your-ssh-keys.md). While you are at the **Project** tab, select -HTTPS or SSH from the dropdown menu and copy the link using the _Copy URL to clipboard_ -button (you'll have to paste it on your shell in the next step). - -![Copy the HTTPS or SSH](img/project_clone_url.png) - -## Working with project files on the command line - -This section has examples of some basic shell commands that you might find useful. For more information, search the web for _bash commands_. - -Alternatively, you can edit files using your choice of editor (IDE) or the GitLab user interface. - -### Clone your project - -Go to your computer's shell and type the following command with your SSH or HTTPS URL: +--- +type: howto, reference +--- -``` -git clone PASTE HTTPS OR SSH HERE -``` - -A clone of the project will be created in your computer. - -NOTE: **Note:** -If you clone your project via a URL that contains special characters, make sure -that characters are URL-encoded. - -### Go into a project directory to work in it - -``` -cd NAME-OF-PROJECT -``` +# Command Line basic commands -### Go back one directory +When [working with Git from the command line](start-using-git.md), you will need to +use more than just the Git commands. There are several basic commands that you should +learn, in order to make full use of the command line. -``` -cd .. -``` +## Start working on your project -### List what’s in the current directory +To work on a git project locally (from your own computer), with the command line, +first you will need to [clone (copy) it](start-using-git.md#clone-a-repository) to +your computer. -``` -ls -``` +## Working with files on the command line -### List what’s in the current directory that starts with `a` +This section has examples of some basic shell commands that you might find useful. +For more information, search the web for _bash commands_. -``` -ls a* -``` +Alternatively, you can edit files using your choice of editor (IDE), or the GitLab user +interface (not locally). -### List what’s in the current directory that ends with `.md` +### Common commands -``` -ls *.md -``` +The list below is not exhaustive, but contains many of the most commonly used commands. -### Create a new directory +| Command | Description | +|--------------------------------|---------------------------------------------| +| `cd NAME-OF-DIRECTORY` | Go into a directory to work in it | +| `cd ..` | Go back one directory | +| `ls` | List what’s in the current directory | +| `ls a*` | List what’s in the current directory that starts with `a` | +| `ls *.md` | List what’s in the current directory that ends with `.md` | +| `mkdir NAME-OF-YOUR-DIRECTORY` | Create a new directory | +| `cat README.md` | Display the contents of a [text file you created previously](#create-a-text-file-in-the-current-directory) | +| `pwd` | Show the current directory | +| `clear` | Clear the shell window | -``` -mkdir NAME-OF-YOUR-DIRECTORY -``` +### Create a text file in the current directory -### Create a README.md file in the current directory +To create a text file from the command line, for example `README.md`, follow these +steps: ``` touch README.md @@ -80,37 +52,37 @@ nano README.md #### Press: enter ``` -### Show the contents of the README.md file +### Remove a file or directory -``` -cat README.md -``` - -### Remove a file +It is easy to delete (remove) a file or directory, but be careful: DANGER: **Danger:** -This will permanently delete the file. +This will **permanently** delete a file. ``` rm NAME-OF-FILE ``` -### Remove a directory and all of its contents - DANGER: **Danger:** -This will permanently delete the directory and all of its contents. +This will **permanently** delete a directory and **all** of its contents. ``` rm -r NAME-OF-DIRECTORY ``` -### View command history +### View and Execute commands from history + +You can view the history of all the commands you executed from the command line, +and then execute any of them again, if needed. + +First, list the commands you executed previously: ``` history ``` -### Execute command 123 from history +Then, choose a command from the list and check the number next to the command (`123`, +for example) . Execute the same full command with: ``` !123 @@ -118,28 +90,32 @@ history ### Carry out commands for which the account you are using lacks authority -You will be asked for an administrator’s password. +Not all commands can be executed from a basic user account on a computer, you may +need administrator's rights to execute commands that affect the system, or try to access +protected data, for example. You can use `sudo` to execute these commands, but you +will likely be asked for an administrator password. ``` -sudo COMMAND +sudo RESTRICTED-COMMAND ``` CAUTION: **Caution:** Be careful of the commands you run with `sudo`. Certain commands may cause -damage to your data and system. +damage to your data or system. -### Show which directory I am in +## Sample Git taskflow -``` -pwd -``` - -### Clear the shell window +If you are completely new to Git, looking through some [sample taskflows](https://rogerdudler.github.io/git-guide/) +will help you understand the best practices for using these commands as you work. -``` -clear -``` +<!-- ## Troubleshooting -### Sample Git taskflow +Include any troubleshooting steps that you can foresee. If you know beforehand what issues +one might have when setting this up, or when something is changed, or on upgrading, it's +important to describe those, too. Think of things that may go wrong and include them here. +This is important to minimize requests for support, and to avoid doc comments with +questions that you know someone might ask. -If you are completely new to Git, looking through some [sample taskflows](https://rogerdudler.github.io/git-guide/) will help you understand best practices for using these commands as you work. +Each scenario can be a third-level heading, e.g. `### Getting error message X`. +If you have none to add when creating a doc, leave this section in place +but commented out to help encourage others to add to it in the future. --> diff --git a/doc/gitlab-basics/create-branch.md b/doc/gitlab-basics/create-branch.md index ad94f0dad29..e2a2fb52af8 100644 --- a/doc/gitlab-basics/create-branch.md +++ b/doc/gitlab-basics/create-branch.md @@ -1,12 +1,16 @@ +--- +type: howto +--- + # How to create a branch -A branch is an independent line of development. +A branch is an independent line of development in a [project](../user/project/index.md). -New commits are recorded in the history for the current branch, which results -in taking the source from someone’s repository (the place where the history of -your work is stored) at certain point in time, and apply your own changes to it -in the history of the project. +When you create a new branch (in your [terminal](basic-git-commands.md) or with +[the web interface](../user/project/repository/web_editor.md#create-a-new-branch)), +you are creating a snapshot of a certain branch, usually the main `master` branch, +at it's current state. From there, you can start to make your own changes without +affecting the main codebase. The history of your changes will be tracked in your branch. -To add changes to your GitLab project, you should create a branch. You can do -it in your [terminal](basic-git-commands.md) or by -[using the web interface](../user/project/repository/web_editor.md#create-a-new-branch). +When your changes are ready, you then merge them into the rest of the codebase with a +[merge request](add-merge-request.md). diff --git a/doc/gitlab-basics/create-project.md b/doc/gitlab-basics/create-project.md index 2caf7dbbc7a..1833b27a292 100644 --- a/doc/gitlab-basics/create-project.md +++ b/doc/gitlab-basics/create-project.md @@ -1,10 +1,13 @@ -# Create a project +--- +type: howto +--- -[Projects](../user/project/index.md) combine many features of GitLab together. +# Creating projects -NOTE: **Note:** -For a list of words that cannot be used as project names see -[Reserved project and group names](../user/reserved_names.md). +Most work in GitLab is done within a [Project](../user/project/index.md). Files and +code are saved in projects, and most features are used within the scope of projects. + +## Create a project in GitLab To create a project in GitLab: @@ -14,11 +17,14 @@ To create a project in GitLab: - Create a [blank project](#blank-projects). - Create a project using with one of the available [project templates](#project-templates). - [Import a project](../user/project/import/index.md) from a different repository, - if enabled on your GitLab instance. Contact your GitLab admin if this - is unavailable. + if enabled on your GitLab instance. Contact your GitLab admin if this is unavailable. - Run [CI/CD pipelines for external repositories](../ci/ci_cd_for_external_repos/index.md). **(PREMIUM)** -## Blank projects +NOTE: **Note:** +For a list of words that cannot be used as project names see +[Reserved project and group names](../user/reserved_names.md). + +### Blank projects To create a new blank project on the **New project** page: @@ -37,23 +43,25 @@ To create a new blank project on the **New project** page: can be cloned. 1. Click **Create project**. -## Project templates +### Project templates -Project templates can pre-populate your project with necessary files to get you started quickly. +Project templates can pre-populate a new project with the necessary files to get you +started quickly. There are two types of project templates: - [Built-in templates](#built-in-templates), sourced from the following groups: - [`project-templates`](https://gitlab.com/gitlab-org/project-templates) - [`pages`](https://gitlab.com/pages) -- [Custom project templates](#custom-project-templates-premium-only), for custom templates configured by GitLab administrators and users. +- [Custom project templates](#custom-project-templates-premium-only), for custom templates + configured by GitLab administrators and users. -### Built-in templates +#### Built-in templates Built-in templates are project templates that are: -- Developed and maintained in the - [`project-templates`](https://gitlab.com/gitlab-org/project-templates) and [`pages`](https://gitlab.com/pages) groups. +- Developed and maintained in the [`project-templates`](https://gitlab.com/gitlab-org/project-templates) + and [`pages`](https://gitlab.com/pages) groups. - Released with GitLab. To use a built-in template on the **New project** page: @@ -62,22 +70,25 @@ To use a built-in template on the **New project** page: 1. From the list of available built-in templates, click the: - **Preview** button to look at the template source itself. - **Use template** button to start creating the project. -1. Finish creating the project by filling out the project's details. The process is the same as for - using a [blank project](#blank-projects). +1. Finish creating the project by filling out the project's details. The process is + the same as creating a [blank project](#blank-projects). TIP: **Tip:** -You can improve the existing built-in templates or contribute new ones on the -[`project-templates`](https://gitlab.com/gitlab-org/project-templates) and [`pages`](https://gitlab.com/pages) groups. +You can improve the existing built-in templates or contribute new ones in the +[`project-templates`](https://gitlab.com/gitlab-org/project-templates) and +[`pages`](https://gitlab.com/pages) groups. -### Custom project templates **(PREMIUM ONLY)** +#### Custom project templates **(PREMIUM ONLY)** > [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/6860) in [GitLab Premium](https://about.gitlab.com/pricing) 11.2. -Creating new projects based on custom project templates is a convenient option to bootstrap a project. +Creating new projects based on custom project templates is a convenient option to +bootstrap a project. -Custom projects are available from the **Instance** or **Group** tabs under the **Create from template** tab, -depending on the type of template. +Custom projects are available at the [instance-level](../user/admin_area/custom_project_templates.md) +from the **Instance** tab, or at the [group-level](../user/group/custom_project_templates.md) +from the **Group** tab, under the **Create from template** tab. To use a custom project template on the **New project** page: @@ -85,23 +96,19 @@ To use a custom project template on the **New project** page: 1. From the list of available custom templates, click the: - **Preview** button to look at the template source itself. - **Use template** button to start creating the project. -1. Finish creating the project by filling out the project's details. The process is the same as for - using a [blank project](#blank-projects). - -For information on configuring custom project templates, see: - -- [Custom instance-level project templates](../user/admin_area/custom_project_templates.md), for instance-level templates. -- [Custom group-level project templates](../user/group/custom_project_templates.md), for group-level templates. +1. Finish creating the project by filling out the project's details. The process is + the same as creating a [blank project](#blank-projects). ## Push to create a new project > [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/26388) in GitLab 10.5. -When you create a new repo locally, instead of going to GitLab to manually -create a new project and then push the repo, you can directly push it to -GitLab to create the new project, all without leaving your terminal. If you have access to that -namespace, we will automatically create a new project under that GitLab namespace with its -visibility set to Private by default (you can later change it in the [project's settings](../public_access/public_access.md#how-to-change-project-visibility)). +When you create a new repository locally, instead of going to GitLab to manually +create a new project and then [clone the repo](start-using-git.md#clone-a-repository) +locally, you can directly push it to GitLab to create the new project, all without leaving +your terminal. If you have access rights to the associated namespace, GitLab will +automatically create a new project under that GitLab namespace with its visibility +set to Private by default (you can later change it in the [project's settings](../public_access/public_access.md#how-to-change-project-visibility)). This can be done by using either SSH or HTTPS: @@ -127,3 +134,15 @@ remote: To view the project, visit: remote: https://gitlab.example.com/namespace/nonexistent-project remote: ``` + +<!-- ## Troubleshooting + +Include any troubleshooting steps that you can foresee. If you know beforehand what issues +one might have when setting this up, or when something is changed, or on upgrading, it's +important to describe those, too. Think of things that may go wrong and include them here. +This is important to minimize requests for support, and to avoid doc comments with +questions that you know someone might ask. + +Each scenario can be a third-level heading, e.g. `### Getting error message X`. +If you have none to add when creating a doc, leave this section in place +but commented out to help encourage others to add to it in the future. --> diff --git a/doc/gitlab-basics/create-your-ssh-keys.md b/doc/gitlab-basics/create-your-ssh-keys.md index aac73d4c9c5..338b96374aa 100644 --- a/doc/gitlab-basics/create-your-ssh-keys.md +++ b/doc/gitlab-basics/create-your-ssh-keys.md @@ -1,22 +1,27 @@ -# Create and add your SSH public key +--- +type: howto +--- -This topic describes how to: +# Create and add your SSH public key -- Create an SSH key pair to use with GitLab. -- Add the SSH public key to your GitLab account. +It is best practice to use [Git over SSH instead of Git over HTTP](https://git-scm.com/book/en/v2/Git-on-the-Server-The-Protocols). +In order to use SSH, you will need to -You do this to use [Git over SSH instead of Git over HTTP](https://git-scm.com/book/en/v2/Git-on-the-Server-The-Protocols). +1. [Create an SSH key pair](#creating-your-ssh-key-pair) on your local computer. +1. [Add the key to GitLab](#adding-your-ssh-public-key-to-gitlab). ## Creating your SSH key pair -1. Go to your [command line](start-using-git.md). -1. Follow the [instructions](../ssh/README.md#generating-a-new-ssh-key-pair) to generate your SSH key pair. +1. Go to your [command line](start-using-git.md#open-a-shell). +1. Follow the [instructions](../ssh/README.md#generating-a-new-ssh-key-pair) to generate + your SSH key pair. ## Adding your SSH public key to GitLab -To add the SSH public key to GitLab, -see [Adding an SSH key to your GitLab account](../ssh/README.md#adding-an-ssh-key-to-your-gitlab-account). +To add the SSH public key to GitLab, see +[Adding an SSH key to your GitLab account](../ssh/README.md#adding-an-ssh-key-to-your-gitlab-account). NOTE: **Note:** -Once you add a key, you cannot edit it. If the paste -[didn't work](../ssh/README.md#testing-that-everything-is-set-up-correctly), you need to remove the key and re-add it. +Once you add a key, you cannot edit it. If it didn't paste properly, it +[will not work](../ssh/README.md#testing-that-everything-is-set-up-correctly), and +you will need to remove the key from GitLab and try adding it again. diff --git a/doc/gitlab-basics/fork-project.md b/doc/gitlab-basics/fork-project.md index a128a7c7dd3..5c19985121d 100644 --- a/doc/gitlab-basics/fork-project.md +++ b/doc/gitlab-basics/fork-project.md @@ -1,20 +1,11 @@ +--- +type: howto +--- + # How to fork a project A fork is a copy of an original repository that you put in another namespace where you can experiment and apply changes that you can later decide whether or not to share, without affecting the original project. -It takes just a few steps to fork a project in GitLab. - -1. Go to a project's dashboard under the **Project** tab and click on the - **Fork** button. - - ![Click on Fork button](img/fork_new.png) - -1. You will be asked where to fork the repository. Click on the user or group - to where you'd like to add the forked project. - - ![Choose namespace](img/fork_choose_namespace.png) - -1. After a few moments, depending on the repository's size, the forking will - complete. +It takes just a few steps to [fork a project in GitLab](../workflow/forking_workflow.md#creating-a-fork). diff --git a/doc/gitlab-basics/start-using-git.md b/doc/gitlab-basics/start-using-git.md index b3c5d32f2f5..3e3f96fb31f 100644 --- a/doc/gitlab-basics/start-using-git.md +++ b/doc/gitlab-basics/start-using-git.md @@ -1,38 +1,43 @@ +--- +type: howto, tutorial +--- + # Start using Git on the command line -If you want to start using Git and GitLab, make sure that you have created and/or signed into an account on GitLab. +While GitLab has a powerful user interface, if you want to use Git itself, you will +have to do so from the command line. If you want to start using Git and GitLab together, +make sure that you have created and/or signed into an account on GitLab. ## Open a shell -Depending on your operating system, you will need to use a shell of your preference. Here are some suggestions: - -- [Terminal](http://blog.teamtreehouse.com/introduction-to-the-mac-os-x-command-line) on Mac OSX +Depending on your operating system, you will need to use a shell of your preference. +Here are some suggestions: +- [Terminal](http://blog.teamtreehouse.com/introduction-to-the-mac-os-x-command-line) on macOS - [GitBash](https://msysgit.github.io) on Windows - - [Linux Terminal](http://www.howtogeek.com/140679/beginner-geek-how-to-start-using-the-linux-terminal/) on Linux ## Check if Git has already been installed -Git is usually preinstalled on Mac and Linux. - -Type the following command and then press enter: +Git is usually preinstalled on Mac and Linux, so run the following command: ```bash git --version ``` -You should receive a message that tells you which Git version you have on your computer. If you don’t receive a "Git version" message, it means that you need to [download Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git). +You should receive a message that tells you which Git version you have on your computer. +If you don’t receive a "Git version" message, it means that you need to +[download Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git). -If Git doesn't automatically download, there's an option on the website to [download manually](https://git-scm.com/downloads). Then follow the steps on the installation window. - -After you are finished installing Git, open a new shell and type `git --version` again to verify that it was correctly installed. +After you are finished installing Git, open a new shell and type `git --version` again +to verify that it was correctly installed. ## Add your Git username and set your email -It is important to configure your Git username and email address, since every Git commit will use this information to identify you as the author. +It is important to configure your Git username and email address, since every Git +commit will use this information to identify you as the author. -On your shell, type the following command to add your username: +In your shell, type the following command to add your username: ```bash git config --global user.name "YOUR_USERNAME" @@ -56,7 +61,10 @@ To verify that you entered your email correctly, type: git config --global user.email ``` -You'll need to do this only once, since you are using the `--global` option. It tells Git to always use this information for anything you do on that system. If you want to override this with a different username or email address for specific projects, you can run the command without the `--global` option when you’re in that project. +You'll need to do this only once, since you are using the `--global` option. It tells +Git to always use this information for anything you do on that system. If you want +to override this with a different username or email address for specific projects, +you can run the command without the `--global` option when you’re in that project. ## Check your information @@ -68,12 +76,12 @@ git config --global --list ## Basic Git commands -Start using Git via the command line with the most basic -commands as described below. +Start using Git via the command line with the most basic commands as described below. -## Initialize a local directory for Git version control +### Initialize a local directory for Git version control -If you have an existing local directory that you want to *initialize* for version control, use the `init` command to instruct Git to begin tracking the directory: +If you have an existing local directory that you want to *initialize* for version +control, use the `init` command to instruct Git to begin tracking the directory: ```bash git init @@ -81,34 +89,33 @@ git init This creates a `.git` directory that contains the Git configuration files. -Once the directory has been initialized, you can [add a remote repository](#add-a-remote-repository) and [send changes to GitLab.com](#send-changes-to-gitlabcom). View the instructions on [Create a project](../gitlab-basics/create-project.html#push-to-create-a-new-project) to create a new project on GitLab with your changes. +Once the directory has been initialized, you can [add a remote repository](#add-a-remote-repository) +and [send changes to GitLab.com](#send-changes-to-gitlabcom). You will also need to +[create a new project in GitLab](../gitlab-basics/create-project.html#push-to-create-a-new-project) +for your Git repository. ### Clone a repository -To start working locally on an existing remote repository, -clone it with the command `git clone <repository path>`. -By cloning a repository, you'll download a copy of its -files into your local computer, preserving the Git -connection with the remote repository. +To start working locally on an existing remote repository, clone it with the command +`git clone <repository path>`. By cloning a repository, you'll download a copy of its +files to your local computer, automatically preserving the Git connection with the +remote repository. -You can either clone it via HTTPS or [SSH](../ssh/README.md). -If you chose to clone it via HTTPS, you'll have to enter your -credentials every time you pull and push. With SSH, you enter -your credentials once and can pull and push straightaway. +You can either clone it via HTTPS or [SSH](../ssh/README.md). If you chose to clone +it via HTTPS, you'll have to enter your credentials every time you pull and push. +With SSH, you enter your credentials only once. -You can find both paths (HTTPS and SSH) by navigating to -your project's landing page and clicking **Clone**. GitLab -will prompt you with both paths, from which you can copy +You can find both paths (HTTPS and SSH) by navigating to your project's landing page +and clicking **Clone**. GitLab will prompt you with both paths, from which you can copy and paste in your command line. -As an example, consider a repository path: +As an example, consider this repository path: - HTTPS: `https://gitlab.com/gitlab-org/gitlab-ce.git` -- SSH: `` git@gitlab.com:gitlab-org/gitlab-ce.git `` +- SSH: `git@gitlab.com:gitlab-org/gitlab-ce.git` -To get started, open a terminal window in the directory -you wish to clone the repository files into, and run one -of the following commands. +To get started, open a terminal window in the directory you wish to clone the repository +files into, and run one of the following commands. Clone via HTTPS: @@ -122,13 +129,15 @@ Clone via SSH: git clone git@gitlab.com:gitlab-org/gitlab-ce.git ``` -Both commands will download a copy of the files in a -folder named after the project's name. - -You can then navigate to the directory and start working +Both commands will download a copy of the files in a folder named after the project's +name. You can then navigate to the directory and start working on it locally. -### Go to the master branch to pull the latest changes from there +### Switch to the master branch + +You are always in a branch when working with Git. The main branch is the master branch, +but you can use the same command to switch to a different branch by changing `master` +to the branch name. ```bash git checkout master @@ -136,13 +145,20 @@ git checkout master ### Download the latest changes in the project -This is for you to work on an up-to-date copy (it is important to do this every time you start working on a project), while you set up tracking branches. You pull from remote repositories to get all the changes made by users since the last time you cloned or pulled the project. Later, you can push your local commits to the remote repositories. +To work on an up-to-date copy of the project (it is important to do this every time +you start working on a project), you `pull` to get all the changes made by users since +the last time you cloned or pulled the project. Use `master` for the `<name-of-branch>` +to get the main branch code, or the branch name of the branch you are currently working +in. ```bash -git pull REMOTE NAME-OF-BRANCH +git pull REMOTE <name-of-branch> ``` -When you first clone a repository, REMOTE is typically "origin". This is where the repository came from, and it indicates the SSH or HTTPS URL of the repository on the remote server. NAME-OF-BRANCH is usually "master", but it may be any existing branch. +When you first clone a repository, REMOTE is typically `origin`. This is where the +repository was cloned from, and it indicates the SSH or HTTPS URL of the repository +on the remote server. `<name-of-branch>` is usually `master`, but it may be any existing +branch. ### View your remote repositories @@ -157,17 +173,20 @@ git remote -v To add a link to a remote repository: ```bash -git remote add SOURCE-NAME REPOSITORY-PATH +git remote add <source-name> <repository-path> ``` -You'll use this source name every time you [push changes to GitLab.com](#send-changes-to-gitlabcom), so use something easy to remember and type. +You'll use this source name every time you [push changes to GitLab.com](#send-changes-to-gitlabcom), +so use something easy to remember and type. ### Create a branch -To create a branch, type the following (spaces won't be recognized in the branch name, so you will need to use a hyphen or underscore): +To create a new branch, to work from without affecting the `master` branch, type the +following (spaces won't be recognized in the branch name, so you will need to use a +hyphen or underscore): ```bash -git checkout -b NAME-OF-BRANCH +git checkout -b <name-of-branch>> ``` ### Work on an existing branch @@ -175,12 +194,14 @@ git checkout -b NAME-OF-BRANCH To switch to an existing branch, so you can work on it: ```bash -git checkout NAME-OF-BRANCH +git checkout <name-of-branch> ``` ### View the changes you've made -It's important to be aware of what's happening and the status of your changes. When you add, change, or delete files/folders, Git knows about it. To check the status of your changes: +It's important to be aware of what's happening and the status of your changes. When +you add, change, or delete files/folders, Git knows about it. To check the status of +your changes: ```bash git status @@ -188,7 +209,8 @@ git status ### View differences -To view the differences between your local, unstaged changes and the repository versions that you cloned or pulled, type: +To view the differences between your local, unstaged changes and the repository versions +that you cloned or pulled, type: ```bash git diff @@ -196,16 +218,19 @@ git diff ### Add and commit local changes -You'll see your local changes in red when you type `git status`. These changes may be new, modified, or deleted files/folders. Use `git add` to stage a local file/folder for committing. Then use `git commit` to commit the staged files: +You'll see any local changes in red when you type `git status`. These changes may +be new, modified, or deleted files/folders. Use `git add` to first stage (prepare) +a local file/folder for committing. Then use `git commit` to commit (save) the staged +files: ```bash -git add FILE OR FOLDER +git add <file-name OR folder-name> git commit -m "COMMENT TO DESCRIBE THE INTENTION OF THE COMMIT" ``` ### Add all changes to commit -To add and commit all local changes in one command: +To add and commit (save) all local changes quickly: ```bash git add . @@ -217,35 +242,32 @@ The `.` character typically means _all_ in Git. ### Send changes to GitLab.com -To push all local commits to the remote repository: +To push all local commits (saved changes) to the remote repository: ```bash -git push REMOTE NAME-OF-BRANCH +git push <remote> <name-of-branch> ``` -For example, to push your local commits to the _master_ branch of the _origin_ remote: +For example, to push your local commits to the _`master`_ branch of the _`origin`_ remote: ```bash git push origin master ``` -### Delete all changes in the Git repository +### Delete all changes in the branch -To delete all local changes in the repository that have not been added to the staging area, and leave unstaged files/folders, type: +To delete all local changes in the branch that have not been added to the staging +area, and leave unstaged files/folders, type: ```bash git checkout . ``` -### Delete all untracked changes in the Git repository - -```bash -git clean -f -``` +Note that this removes *changes* to files, not the files themselves. ### Unstage all changes that have been added to the staging area -To undo the most recent add, but not committed, files/folders: +To undo the most recently added, but not committed, changes to files/folders: ```bash git reset . @@ -259,25 +281,31 @@ To undo the most recent commit, type: git reset HEAD~1 ``` -This leaves the files and folders unstaged in your local repository. +This leaves the changed files and folders unstaged in your local repository. CAUTION: **Warning:** -A Git commit is mostly irreversible, particularly if you already pushed it to the remote repository. Although you can undo a commit, the best option is to avoid the situation altogether. +A Git commit should not usually be reverse, particularly if you already pushed it +to the remote repository. Although you can undo a commit, the best option is to avoid +the situation altogether by working carefully. -### Merge created branch with master branch +### Merge a branch with master branch -You need to be in the created branch. +When you are ready to make all the changes in a branch a permanent addition to +the master branch, you `merge` the two together: ```bash -git checkout NAME-OF-BRANCH +git checkout <name-of-branch> git merge master ``` -### Merge master branch with created branch +<!-- ## Troubleshooting -You need to be in the master branch. +Include any troubleshooting steps that you can foresee. If you know beforehand what issues +one might have when setting this up, or when something is changed, or on upgrading, it's +important to describe those, too. Think of things that may go wrong and include them here. +This is important to minimize requests for support, and to avoid doc comments with +questions that you know someone might ask. -```bash -git checkout master -git merge NAME-OF-BRANCH -``` +Each scenario can be a third-level heading, e.g. `### Getting error message X`. +If you have none to add when creating a doc, leave this section in place +but commented out to help encourage others to add to it in the future. --> diff --git a/doc/install/azure/index.md b/doc/install/azure/index.md index c0e1b0ebbc8..543a222bd25 100644 --- a/doc/install/azure/index.md +++ b/doc/install/azure/index.md @@ -70,7 +70,7 @@ The first items we need to configure are the basic settings of the underlying vi > **Note:** if you're unsure which authentication type to use, select **Password** 1. If you chose **SSH public key** - enter your `SSH public key` into the field provided - _(read the [SSH documentation][GitLab-Docs-SSH] to learn more about how to set up SSH + _(read the [SSH documentation](../../ssh/README.md) to learn more about how to set up SSH public keys)_ 1. If you chose **Password** - enter the password you wish to use _(this is the password that you will use later in this tutorial to [SSH] into the VM, so make sure it's a strong password/passphrase)_ @@ -407,7 +407,7 @@ on any cloud service you choose. ## Where to next? -Check out our other [Technical Articles][GitLab-Technical-Articles] or browse the [GitLab Documentation][GitLab-Docs] to learn more about GitLab. +Check out our other [Technical Articles](../../articles/index.md) or browse the [GitLab Documentation][GitLab-Docs](../../README.md) to learn more about GitLab. ### Useful links @@ -423,9 +423,6 @@ Check out our other [Technical Articles][GitLab-Technical-Articles] or browse th - [SSH], [PuTTY] and [Using SSH in PuTTY][Using-SSH-In-Putty] [Original-Blog-Post]: https://about.gitlab.com/2016/07/13/how-to-setup-a-gitlab-instance-on-microsoft-azure/ "How to Set up a GitLab Instance on Microsoft Azure" -[GitLab-Docs]: https://docs.gitlab.com/ce/README.html "GitLab Documentation" -[GitLab-Technical-Articles]: https://docs.gitlab.com/ce/articles/index.html "GitLab Technical Articles" -[GitLab-Docs-SSH]: https://docs.gitlab.com/ce/ssh/README.html "GitLab Documentation: SSH" [CE]: https://about.gitlab.com/features/ [EE]: https://about.gitlab.com/features/#ee-starter diff --git a/doc/install/installation.md b/doc/install/installation.md index 06ec00cecc4..46ee980841b 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -6,7 +6,7 @@ type: howto This is the official installation guide to set up a production GitLab server using the source files. To set up a **development installation** or for many -other installation options, see the [main installation page](index.md). +other installation options, see the [main installation page](README.md). It was created for and tested on **Debian/Ubuntu** operating systems. Read [requirements.md](requirements.md) for hardware and operating system requirements. If you want to install on RHEL/CentOS, we recommend using the diff --git a/doc/integration/README.md b/doc/integration/README.md index 135952a1b08..55f9666e3a3 100644 --- a/doc/integration/README.md +++ b/doc/integration/README.md @@ -27,7 +27,7 @@ See the documentation below for details on how to configure these services. - [SAML](saml.md) Configure GitLab as a SAML 2.0 Service Provider - [Trello](trello_power_up.md) Integrate Trello with GitLab -> GitLab Enterprise Edition contains [advanced Jenkins support][jenkins]. +> GitLab Enterprise Edition contains [advanced Jenkins support](jenkins.md). ## Project services @@ -70,5 +70,3 @@ After that restart GitLab with: ```bash sudo gitlab-ctl restart ``` - -[jenkins]: https://docs.gitlab.com/ee/integration/jenkins.html diff --git a/doc/integration/jenkins.md b/doc/integration/jenkins.md index 50cb3d50009..6755640d39c 100644 --- a/doc/integration/jenkins.md +++ b/doc/integration/jenkins.md @@ -35,6 +35,9 @@ and [Migrating from Jenkins to GitLab](https://www.youtube.com/watch?v=RlEVGOpYF For a real use case, read the blog post [Continuous integration: From Jenkins to GitLab using Docker](https://about.gitlab.com/2017/07/27/docker-my-precious/). +NOTE: **Moving from a traditional CI plug-in to a single application for the entire software development lifecycle can decrease hours spent on maintaining toolchains by 10% or more.** +Visit the ['GitLab vs. Jenkins' comparison page](https://about.gitlab.com/devops-tools/jenkins-vs-gitlab.html) to learn how our built-in CI compares to Jenkins. + ## Requirements - [Jenkins GitLab Plugin](https://wiki.jenkins.io/display/JENKINS/GitLab+Plugin) diff --git a/doc/integration/slack.md b/doc/integration/slack.md index f84ab769218..9fcf2c2d99a 100644 --- a/doc/integration/slack.md +++ b/doc/integration/slack.md @@ -1,5 +1,5 @@ --- -redirect_to: '../project_services/slack.md' +redirect_to: '../user/project/integrations/slack.md' --- -This document was moved to [project_services/slack.md](../project_services/slack.md). +This document was moved to [project_services/slack.md](../user/project/integrations/slack.md). diff --git a/doc/public_access/public_access.md b/doc/public_access/public_access.md index d04428fdbfe..ea4702acc41 100644 --- a/doc/public_access/public_access.md +++ b/doc/public_access/public_access.md @@ -37,7 +37,7 @@ visibility setting keep this setting. You can read more about the change in the ### Private projects -Private projects can only be cloned and viewed by project members. +Private projects can only be cloned and viewed by project members (except for guests). They will appear in the public access directory (`/public`) for project members only. diff --git a/doc/topics/autodevops/index.md b/doc/topics/autodevops/index.md index 30b9e88ade8..1687a3aee72 100644 --- a/doc/topics/autodevops/index.md +++ b/doc/topics/autodevops/index.md @@ -1,6 +1,7 @@ # Auto DevOps -> [Introduced][ce-37115] in GitLab 10.0. Generally available on GitLab 11.0. +> - [Introduced][ce-37115] in GitLab 10.0. +> - Generally available on GitLab 11.0. Auto DevOps provides pre-defined CI/CD configuration which allows you to automatically detect, build, test, deploy, and monitor your applications. Leveraging CI/CD best practices and tools, Auto DevOps aims @@ -43,16 +44,16 @@ platform or a Platform as a Service (PaaS). It takes inspiration from the innovative work done by [Heroku](https://www.heroku.com/) and goes beyond it in multiple ways: -1. Auto DevOps works with any Kubernetes cluster; you're not limited to running - on GitLab's infrastructure. (Note that many features also work without Kubernetes.) -1. There is no additional cost (no markup on the infrastructure costs), and you - can use a self-hosted Kubernetes cluster or Containers as a Service on any - public cloud (for example, [Google Kubernetes Engine](https://cloud.google.com/kubernetes-engine/)). -1. Auto DevOps has more features including security testing, performance testing, - and code quality testing. -1. Auto DevOps offers an incremental graduation path. If you need advanced customizations, - you can start modifying the templates without having to start over on a - completely different platform. Review the [customizing](#customizing) section for more information. +- Auto DevOps works with any Kubernetes cluster; you're not limited to running + on GitLab's infrastructure. (Note that many features also work without Kubernetes). +- There is no additional cost (no markup on the infrastructure costs), and you + can use a self-hosted Kubernetes cluster or Containers as a Service on any + public cloud (for example, [Google Kubernetes Engine](https://cloud.google.com/kubernetes-engine/)). +- Auto DevOps has more features including security testing, performance testing, + and code quality testing. +- Auto DevOps offers an incremental graduation path. If you need advanced customizations, + you can start modifying the templates without having to start over on a + completely different platform. Review the [customizing](#customizing) section for more information. ## Features @@ -86,42 +87,46 @@ Auto DevOps provides great defaults for all the stages; you can, however, For an overview on the creation of Auto DevOps, read the blog post [From 2/3 of the Self-Hosted Git Market, to the Next-Generation CI System, to Auto DevOps](https://about.gitlab.com/2017/06/29/whats-next-for-gitlab-ci/). +NOTE: **Note** +Kubernetes clusters can [be used without](../../user/project/clusters/index.md) +Auto DevOps. + ## Requirements To make full use of Auto DevOps, you will need: -1. **GitLab Runner** (needed for all stages) - Your Runner needs to be - configured to be able to run Docker. Generally this means using the - [Docker](https://docs.gitlab.com/runner/executors/docker.html) or [Kubernetes - executor](https://docs.gitlab.com/runner/executors/kubernetes.html), with - [privileged mode enabled](https://docs.gitlab.com/runner/executors/docker.html#use-docker-in-docker-with-privileged-mode). - The Runners do not need to be installed in the Kubernetes cluster, but the - Kubernetes executor is easy to use and is automatically autoscaling. - Docker-based Runners can be configured to autoscale as well, using [Docker - Machine](https://docs.gitlab.com/runner/install/autoscaling.html). Runners - should be registered as [shared Runners](../../ci/runners/README.md#registering-a-shared-runner) - for the entire GitLab instance, or [specific Runners](../../ci/runners/README.md#registering-a-specific-runner) - that are assigned to specific projects. -1. **Base domain** (needed for Auto Review Apps and Auto Deploy) - You will need - a domain configured with wildcard DNS which is going to be used by all of your - Auto DevOps applications. [Read the specifics](#auto-devops-base-domain). -1. **Kubernetes** (needed for Auto Review Apps, Auto Deploy, and Auto Monitoring) - - To enable deployments, you will need Kubernetes 1.5+. You need a [Kubernetes cluster][kubernetes-clusters] - for the project, or a Kubernetes [default service template](../../user/project/integrations/services_templates.md) - for the entire GitLab installation. - 1. **A load balancer** - You can use NGINX ingress by deploying it to your - Kubernetes cluster using the - [`nginx-ingress`](https://github.com/kubernetes/charts/tree/master/stable/nginx-ingress) - Helm chart. -1. **Prometheus** (needed for Auto Monitoring) - To enable Auto Monitoring, you - will need Prometheus installed somewhere (inside or outside your cluster) and - configured to scrape your Kubernetes cluster. To get response metrics - (in addition to system metrics), you need to - [configure Prometheus to monitor NGINX](../../user/project/integrations/prometheus_library/nginx_ingress.md#configuring-nginx-ingress-monitoring). - The [Prometheus service](../../user/project/integrations/prometheus.md) - integration needs to be enabled for the project, or enabled as a - [default service template](../../user/project/integrations/services_templates.md) - for the entire GitLab installation. +- **GitLab Runner** (needed for all stages) - Your Runner needs to be + configured to be able to run Docker. Generally this means using the + [Docker](https://docs.gitlab.com/runner/executors/docker.html) or [Kubernetes + executor](https://docs.gitlab.com/runner/executors/kubernetes.html), with + [privileged mode enabled](https://docs.gitlab.com/runner/executors/docker.html#use-docker-in-docker-with-privileged-mode). + The Runners do not need to be installed in the Kubernetes cluster, but the + Kubernetes executor is easy to use and is automatically autoscaling. + Docker-based Runners can be configured to autoscale as well, using [Docker + Machine](https://docs.gitlab.com/runner/install/autoscaling.html). Runners + should be registered as [shared Runners](../../ci/runners/README.md#registering-a-shared-runner) + for the entire GitLab instance, or [specific Runners](../../ci/runners/README.md#registering-a-specific-runner) + that are assigned to specific projects. +- **Base domain** (needed for Auto Review Apps and Auto Deploy) - You will need + a domain configured with wildcard DNS which is going to be used by all of your + Auto DevOps applications. [Read the specifics](#auto-devops-base-domain). +- **Kubernetes** (needed for Auto Review Apps, Auto Deploy, and Auto Monitoring) - + To enable deployments, you will need Kubernetes 1.5+. You need a [Kubernetes cluster][kubernetes-clusters] + for the project, or a Kubernetes [default service template](../../user/project/integrations/services_templates.md) + for the entire GitLab installation. + - **A load balancer** - You can use NGINX ingress by deploying it to your + Kubernetes cluster using the + [`nginx-ingress`](https://github.com/kubernetes/charts/tree/master/stable/nginx-ingress) + Helm chart. +- **Prometheus** (needed for Auto Monitoring) - To enable Auto Monitoring, you + will need Prometheus installed somewhere (inside or outside your cluster) and + configured to scrape your Kubernetes cluster. To get response metrics + (in addition to system metrics), you need to + [configure Prometheus to monitor NGINX](../../user/project/integrations/prometheus_library/nginx_ingress.md#configuring-nginx-ingress-monitoring). + The [Prometheus service](../../user/project/integrations/prometheus.md) + integration needs to be enabled for the project, or enabled as a + [default service template](../../user/project/integrations/services_templates.md) + for the entire GitLab installation. If you do not have Kubernetes or Prometheus installed, then Auto Review Apps, Auto Deploy, and Auto Monitoring will be silently skipped. @@ -147,7 +152,7 @@ NOTE: **Note** A wildcard DNS A record matching the base domain(s) is required, for example, given a base domain of `example.com`, you'd need a DNS entry like: -``` +```text *.example.com 3600 A 1.2.3.4 ``` @@ -191,10 +196,10 @@ The following table is an example of how the three different clusters would be configured. | Cluster name | Cluster environment scope | `KUBE_INGRESS_BASE_DOMAIN` variable value | Variable environment scope | Notes | -| ------------ | -------------- | ----------------------------- | ------------- | ------ | -| review | `review/*` | `review.example.com` | `review/*` | The review cluster which will run all [Review Apps](../../ci/review_apps/index.md). `*` is a wildcard, which means it will be used by every environment name starting with `review/`. | -| staging | `staging` | `staging.example.com` | `staging` | (Optional) The staging cluster which will run the deployments of the staging environments. You need to [enable it first](#deploy-policy-for-staging-and-production-environments). | -| production | `production` | `example.com` | `production` | The production cluster which will run the deployments of the production environment. You can use [incremental rollouts](#incremental-rollout-to-production-premium). | +|--------------|---------------------------|-------------------------------------------|----------------------------|---| +| review | `review/*` | `review.example.com` | `review/*` | The review cluster which will run all [Review Apps](../../ci/review_apps/index.md). `*` is a wildcard, which means it will be used by every environment name starting with `review/`. | +| staging | `staging` | `staging.example.com` | `staging` | (Optional) The staging cluster which will run the deployments of the staging environments. You need to [enable it first](#deploy-policy-for-staging-and-production-environments). | +| production | `production` | `example.com` | `production` | The production cluster which will run the deployments of the production environment. You can use [incremental rollouts](#incremental-rollout-to-production-premium). | To add a different cluster for each environment: @@ -224,7 +229,7 @@ full use of Auto DevOps are available. If this is your fist time, we recommend y GitLab.com users can enable/disable Auto DevOps at the project-level only. Self-managed users can enable/disable Auto DevOps at the project-level, group-level or instance-level. -### Enabling/disabling Auto DevOps at the instance-level (Administrators only) +### At the instance level (Administrators only) Even when disabled at the instance level, group owners and project maintainers can still enable Auto DevOps at the group and project level, respectively. @@ -234,7 +239,7 @@ Auto DevOps at the group and project level, respectively. 1. If enabling, optionally set up the Auto DevOps [base domain](#auto-devops-base-domain) which will be used for Auto Deploy and Auto Review Apps. 1. Click **Save changes** for the changes to take effect. -### Enabling/disabling Auto DevOps at the group-level +### At the group level > [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/52447) in GitLab 11.10. @@ -250,7 +255,7 @@ When enabling or disabling Auto DevOps at group-level, group configuration will the subgroups and projects inside that group, unless Auto DevOps is specifically enabled or disabled on the subgroup or project. -### Enabling/disabling Auto DevOps at the project-level +### At the project level If enabling, check that your project doesn't have a `.gitlab-ci.yml`, or if one exists, remove it. @@ -263,7 +268,7 @@ If enabling, check that your project doesn't have a `.gitlab-ci.yml`, or if one When the feature has been enabled, an Auto DevOps pipeline is triggered on the default branch. -### Feature flag to enable for a percentage of projects +### Enable for a percentage of projects There is also a feature flag to enable Auto DevOps by default to your chosen percentage of projects. @@ -371,7 +376,7 @@ Any differences between the source and target branches are also Static Application Security Testing (SAST) uses the [SAST Docker image](https://gitlab.com/gitlab-org/security-products/sast) to run static analysis on the current code and checks for potential security issues. The -the Auto SAST stage will be skipped on licenses other than Ultimate and requires GitLab Runner 11.5 or above. +Auto SAST stage will be skipped on licenses other than Ultimate and requires GitLab Runner 11.5 or above. Once the report is created, it's uploaded as an artifact which you can later download and check out. @@ -488,7 +493,7 @@ Any security warnings are also shown in the merge request widget. Read how Auto Browser Performance Testing utilizes the [Sitespeed.io container](https://hub.docker.com/r/sitespeedio/sitespeed.io/) to measure the performance of a web page. A JSON report is created and uploaded as an artifact, which includes the overall performance score for each page. By default, the root page of Review and Production environments will be tested. If you would like to add additional URL's to test, simply add the paths to a file named `.gitlab-urls.txt` in the root directory, one per line. For example: -``` +```text / /features /direction @@ -664,10 +669,6 @@ to the desired environment. See [Limiting environment scopes of variables](../.. ### Customizing `.gitlab-ci.yml` -Everything about Auto DevOps is customizable since the [Auto DevOps template] -is just an example of a [`.gitlab-ci.yml`](../../ci/yaml/README.md) and uses -only features that are available to any `.gitlab-ci.yml`. - Auto DevOps is completely customizable because the [Auto DevOps template]: - Is just an implementation of a [`.gitlab-ci.yml`](../../ci/yaml/README.md) file. @@ -724,47 +725,34 @@ The following variables can be used for setting up the Auto DevOps domain, providing a custom Helm chart, or scaling your application. PostgreSQL can also be customized, and you can easily use a [custom buildpack](#custom-buildpacks). -| **Variable** | **Description** | -| ------------ | --------------- | -| `AUTO_DEVOPS_CHART` | The Helm Chart used to deploy your apps; defaults to the one [provided by GitLab](https://gitlab.com/gitlab-org/charts/auto-deploy-app). | -| `AUTO_DEVOPS_CHART_REPOSITORY` | The Helm Chart repository used to search for charts; defaults to `https://charts.gitlab.io`. | -| `AUTO_DEVOPS_CHART_REPOSITORY_NAME` | From Gitlab 11.11, this variable can be used to set the name of the helm repository; defaults to "gitlab" | -| `AUTO_DEVOPS_CHART_REPOSITORY_USERNAME` | From Gitlab 11.11, this variable can be used to set a username to connect to the helm repository. Defaults to no credentials. (Also set AUTO_DEVOPS_CHART_REPOSITORY_PASSWORD) | -| `AUTO_DEVOPS_CHART_REPOSITORY_PASSWORD` | From Gitlab 11.11, this variable can be used to set a password to connect to the helm repository. Defaults to no credentials. (Also set AUTO_DEVOPS_CHART_REPOSITORY_USERNAME) | -| `REPLICAS` | The number of replicas to deploy; defaults to 1. | -| `PRODUCTION_REPLICAS` | The number of replicas to deploy in the production environment. Takes precedence over `REPLICAS` and defaults to 1. For zero downtime upgrades, set to 2 or greater. | -| `CANARY_REPLICAS` | The number of canary replicas to deploy for [Canary Deployments](../../user/project/canary_deployments.md); defaults to 1 | -| `CANARY_PRODUCTION_REPLICAS` | The number of canary replicas to deploy for [Canary Deployments](../../user/project/canary_deployments.md) in the production environment. This takes precedence over `CANARY_REPLICAS`; defaults to 1 | -| `ADDITIONAL_HOSTS` | Fully qualified domain names specified as a comma-separated list that are added to the ingress hosts. | -| `<ENVIRONMENT>_ADDITIONAL_HOSTS` | For a specific environment, the fully qualified domain names specified as a comma-separated list that are added to the ingress hosts. This takes precedence over `ADDITIONAL_HOSTS`. | -| `POSTGRES_ENABLED` | Whether PostgreSQL is enabled; defaults to `"true"`. Set to `false` to disable the automatic deployment of PostgreSQL. | -| `POSTGRES_USER` | The PostgreSQL user; defaults to `user`. Set it to use a custom username. | -| `POSTGRES_PASSWORD` | The PostgreSQL password; defaults to `testing-password`. Set it to use a custom password. | -| `POSTGRES_DB` | The PostgreSQL database name; defaults to the value of [`$CI_ENVIRONMENT_SLUG`](../../ci/variables/README.md#predefined-environment-variables). Set it to use a custom database name. | -| `POSTGRES_VERSION` | Tag for the [`postgres` Docker image](https://hub.docker.com/_/postgres) to use. Defaults to `9.6.2`. | -| `BUILDPACK_URL` | The buildpack's full URL. It can point to either Git repositories or a tarball URL. For Git repositories, it is possible to point to a specific `ref`, for example `https://github.com/heroku/heroku-buildpack-ruby.git#v142` | -| `SAST_CONFIDENCE_LEVEL` | The minimum confidence level of security issues you want to be reported; `1` for Low, `2` for Medium, `3` for High; defaults to `3`.| -| `DEP_SCAN_DISABLE_REMOTE_CHECKS` | Whether remote Dependency Scanning checks are disabled; defaults to `"false"`. Set to `"true"` to disable checks that send data to GitLab central servers. [Read more about remote checks](https://gitlab.com/gitlab-org/security-products/dependency-scanning#remote-checks).| -| `DB_INITIALIZE` | From GitLab 11.4, this variable can be used to specify the command to run to initialize the application's PostgreSQL database. It runs inside the application pod. | -| `DB_MIGRATE` | From GitLab 11.4, this variable can be used to specify the command to run to migrate the application's PostgreSQL database. It runs inside the application pod. | -| `STAGING_ENABLED` | From GitLab 10.8, this variable can be used to define a [deploy policy for staging and production environments](#deploy-policy-for-staging-and-production-environments). | -| `CANARY_ENABLED` | From GitLab 11.0, this variable can be used to define a [deploy policy for canary environments](#deploy-policy-for-canary-environments-premium). | -| `INCREMENTAL_ROLLOUT_MODE`| From GitLab 11.4, this variable, if present, can be used to enable an [incremental rollout](#incremental-rollout-to-production-premium) of your application for the production environment.<br/>Set to: <ul><li>`manual`, for manual deployment jobs.</li><li>`timed`, for automatic rollout deployments with a 5 minute delay each one.</li></ul> | -| `TEST_DISABLED` | From GitLab 11.0, this variable can be used to disable the `test` job. If the variable is present, the job will not be created. | -| `CODE_QUALITY_DISABLED` | From GitLab 11.0, this variable can be used to disable the `codequality` job. If the variable is present, the job will not be created. | -| `LICENSE_MANAGEMENT_DISABLED` | From GitLab 11.0, this variable can be used to disable the `license_management` job. If the variable is present, the job will not be created. | -| `SAST_DISABLED` | From GitLab 11.0, this variable can be used to disable the `sast` job. If the variable is present, the job will not be created. | -| `DEPENDENCY_SCANNING_DISABLED` | From GitLab 11.0, this variable can be used to disable the `dependency_scanning` job. If the variable is present, the job will not be created. | -| `CONTAINER_SCANNING_DISABLED` | From GitLab 11.0, this variable can be used to disable the `sast:container` job. If the variable is present, the job will not be created. | -| `REVIEW_DISABLED` | From GitLab 11.0, this variable can be used to disable the `review` and the manual `review:stop` job. If the variable is present, these jobs will not be created. | -| `DAST_DISABLED` | From GitLab 11.0, this variable can be used to disable the `dast` job. If the variable is present, the job will not be created. | -| `PERFORMANCE_DISABLED` | From GitLab 11.0, this variable can be used to disable the `performance` job. If the variable is present, the job will not be created. | -| `K8S_SECRET_*` | From GitLab 11.7, any variable prefixed with [`K8S_SECRET_`](#application-secret-variables) will be made available by Auto DevOps as environment variables to the deployed application. | -| `KUBE_INGRESS_BASE_DOMAIN` | From GitLab 11.8, this variable can be used to set a domain per cluster. See [cluster domains](../../user/project/clusters/index.md#base-domain) for more information. | -| `ROLLOUT_RESOURCE_TYPE` | From GitLab 11.9, this variable allows specification of the resource type being deployed when using a custom helm chart. Default value is `deployment`. | -| `ROLLOUT_STATUS_DISABLED` | From GitLab 12.0, this variable allows to disable rollout status check because it doesn't support all resource types, for example, `cronjob`. | -| `HELM_UPGRADE_EXTRA_ARGS` | From GitLab 11.11, this variable allows extra arguments in `helm` commands when deploying the application. Note that using quotes will not prevent word splitting. **Tip:** you can use this variable to [customize the Auto Deploy helm chart](https://docs.gitlab.com/ee/topics/autodevops/index.html#custom-helm-chart) by applying custom override values with `--values my-values.yaml`. | -| `HELM_RELEASE_NAME` | From GitLab 12.1, this variable allows the `helm` release name to be overridden, this can be used to assign unique release names when deploying multiple projects to a single namespace | +#### Build and deployment + +The following table lists variables related to building and deploying +applications. + +| **Variable** | **Description** | +|-----------------------------------------|------------------------------------| +| `ADDITIONAL_HOSTS` | Fully qualified domain names specified as a comma-separated list that are added to the ingress hosts. | +| `<ENVIRONMENT>_ADDITIONAL_HOSTS` | For a specific environment, the fully qualified domain names specified as a comma-separated list that are added to the ingress hosts. This takes precedence over `ADDITIONAL_HOSTS`. | +| `AUTO_DEVOPS_CHART` | Helm Chart used to deploy your apps. Defaults to the one [provided by GitLab](https://gitlab.com/gitlab-org/charts/auto-deploy-app). | +| `AUTO_DEVOPS_CHART_REPOSITORY` | Helm Chart repository used to search for charts. Defaults to `https://charts.gitlab.io`. | +| `AUTO_DEVOPS_CHART_REPOSITORY_NAME` | From Gitlab 11.11, used to set the name of the helm repository. Defaults to `gitlab`. | +| `AUTO_DEVOPS_CHART_REPOSITORY_USERNAME` | From Gitlab 11.11, used to set a username to connect to the helm repository. Defaults to no credentials. Also set `AUTO_DEVOPS_CHART_REPOSITORY_PASSWORD`. | +| `AUTO_DEVOPS_CHART_REPOSITORY_PASSWORD` | From Gitlab 11.11, used to set a password to connect to the helm repository. Defaults to no credentials. Also set `AUTO_DEVOPS_CHART_REPOSITORY_USERNAME`. | +| `BUILDPACK_URL` | Buildpack's full URL. Can point to either Git repositories or a tarball URL. For Git repositories, it is possible to point to a specific `ref`. For example `https://github.com/heroku/heroku-buildpack-ruby.git#v142`. | +| `CANARY_ENABLED` | From GitLab 11.0, used to define a [deploy policy for canary environments](#deploy-policy-for-canary-environments-premium). | +| `CANARY_PRODUCTION_REPLICAS` | Number of canary replicas to deploy for [Canary Deployments](../../user/project/canary_deployments.md) in the production environment. Takes precedence over `CANARY_REPLICAS`. Defaults to 1. | +| `CANARY_REPLICAS` | Number of canary replicas to deploy for [Canary Deployments](../../user/project/canary_deployments.md). Defaults to 1. | +| `HELM_RELEASE_NAME` | From GitLab 12.1, allows the `helm` release name to be overridden. Can be used to assign unique release names when deploying multiple projects to a single namespace. | +| `HELM_UPGRADE_EXTRA_ARGS` | From GitLab 11.11, allows extra arguments in `helm` commands when deploying the application. Note that using quotes will not prevent word splitting. **Tip:** you can use this variable to [customize the Auto Deploy helm chart](#custom-helm-chart) by applying custom override values with `--values my-values.yaml`. | +| `INCREMENTAL_ROLLOUT_MODE` | From GitLab 11.4, if present, can be used to enable an [incremental rollout](#incremental-rollout-to-production-premium) of your application for the production environment. Set to `manual` for manual deployment jobs or `timed` for automatic rollout deployments with a 5 minute delay each one. | +| `K8S_SECRET_*` | From GitLab 11.7, any variable prefixed with [`K8S_SECRET_`](#application-secret-variables) will be made available by Auto DevOps as environment variables to the deployed application. | +| `KUBE_INGRESS_BASE_DOMAIN` | From GitLab 11.8, can be used to set a domain per cluster. See [cluster domains](../../user/project/clusters/index.md#base-domain) for more information. | +| `PRODUCTION_REPLICAS` | Number of replicas to deploy in the production environment. Takes precedence over `REPLICAS` and defaults to 1. For zero downtime upgrades, set to 2 or greater. | +| `REPLICAS` | Number of replicas to deploy. Defaults to 1. | +| `ROLLOUT_RESOURCE_TYPE` | From GitLab 11.9, allows specification of the resource type being deployed when using a custom helm chart. Default value is `deployment`. | +| `ROLLOUT_STATUS_DISABLED` | From GitLab 12.0, used to disable rollout status check because it doesn't support all resource types, for example, `cronjob`. | +| `STAGING_ENABLED` | From GitLab 10.8, used to define a [deploy policy for staging and production environments](#deploy-policy-for-staging-and-production-environments). | TIP: **Tip:** Set up the replica variables using a @@ -776,6 +764,42 @@ You should *not* scale your application using Kubernetes directly. This can cause confusion with Helm not detecting the change, and subsequent deploys with Auto DevOps can undo your changes. +#### Database + +The following table lists variables related to the database. + +| **Variable** | **Description** | +| `DB_INITIALIZE` | From GitLab 11.4, used to specify the command to run to initialize the application's PostgreSQL database. Runs inside the application pod. | +| `DB_MIGRATE` | From GitLab 11.4, used to specify the command to run to migrate the application's PostgreSQL database. Runs inside the application pod. | +| `POSTGRES_ENABLED` | Whether PostgreSQL is enabled. Defaults to `"true"`. Set to `false` to disable the automatic deployment of PostgreSQL. | +| `POSTGRES_USER` | The PostgreSQL user. Defaults to `user`. Set it to use a custom username. | +| `POSTGRES_PASSWORD` | The PostgreSQL password. Defaults to `testing-password`. Set it to use a custom password. | +| `POSTGRES_DB` | The PostgreSQL database name. Defaults to the value of [`$CI_ENVIRONMENT_SLUG`](../../ci/variables/README.md#predefined-environment-variables). Set it to use a custom database name. | +| `POSTGRES_VERSION` | Tag for the [`postgres` Docker image](https://hub.docker.com/_/postgres) to use. Defaults to `9.6.2`. | + +#### Security tools + +The following table lists variables related to security tools. + +| **Variable** | **Description** | +| `SAST_CONFIDENCE_LEVEL` | Minimum confidence level of security issues you want to be reported; `1` for Low, `2` for Medium, `3` for High. Defaults to `3`. | +| `DS_DISABLE_REMOTE_CHECKS` | Whether remote Dependency Scanning checks are disabled. Defaults to `"false"`. Set to `"true"` to disable checks that send data to GitLab central servers. [Read more about remote checks](../../user/application_security/dependency_scanning/index.md#remote-checks). | + +#### Disable jobs + +The following table lists variables used to disable jobs. + +| **Variable** | **Description** | +| `CODE_QUALITY_DISABLED` | From GitLab 11.0, used to disable the `codequality` job. If the variable is present, the job will not be created. | +| `CONTAINER_SCANNING_DISABLED` | From GitLab 11.0, used to disable the `sast:container` job. If the variable is present, the job will not be created. | +| `DAST_DISABLED` | From GitLab 11.0, used to disable the `dast` job. If the variable is present, the job will not be created. | +| `DEPENDENCY_SCANNING_DISABLED` | From GitLab 11.0, used to disable the `dependency_scanning` job. If the variable is present, the job will not be created. | +| `LICENSE_MANAGEMENT_DISABLED` | From GitLab 11.0, used to disable the `license_management` job. If the variable is present, the job will not be created. | +| `PERFORMANCE_DISABLED` | From GitLab 11.0, used to disable the `performance` job. If the variable is present, the job will not be created. | +| `REVIEW_DISABLED` | From GitLab 11.0, used to disable the `review` and the manual `review:stop` job. If the variable is present, these jobs will not be created. | +| `SAST_DISABLED` | From GitLab 11.0, used to disable the `sast` job. If the variable is present, the job will not be created. | +| `TEST_DISABLED` | From GitLab 11.0, used to disable the `test` job. If the variable is present, the job will not be created. | + #### Application secret variables > [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/49056) in GitLab 11.7. @@ -1009,7 +1033,7 @@ multi-buildpack does not. As of GitLab 10.0, the supported buildpacks are: -``` +```text - heroku-buildpack-multi v1.0.0 - heroku-buildpack-ruby v168 - heroku-buildpack-nodejs v99 @@ -1057,7 +1081,7 @@ planned for a subsequent release. case, you may need to customize your `.gitlab-ci.yml` with your test commands. - Auto Deploy will fail if GitLab can not create a Kubernetes namespace and service account for your project. For help debugging this issue, see - [Troubleshooting failed deployment jobs](../../user/project/clusters/index.md#troubleshooting-failed-deployment-jobs). + [Troubleshooting failed deployment jobs](../../user/project/clusters/index.md#troubleshooting). ### Disable the banner instance wide diff --git a/doc/university/README.md b/doc/university/README.md index f696db2df20..b17f40b91a5 100644 --- a/doc/university/README.md +++ b/doc/university/README.md @@ -9,6 +9,10 @@ GitLab University is a great place to start when learning about version control If you're looking for a GitLab subscription for _your university_, see our [Education](https://about.gitlab.com/solutions/education/) page. +CAUTION: **Caution:** +Some of the content in GitLab University may be out of date and we plan to +[evaluate](https://gitlab.com/gitlab-org/gitlab-ce/issues/41064) it. + The GitLab University curriculum is composed of GitLab videos, screencasts, presentations, projects and external GitLab content hosted on other services and has been organized into the following sections: 1. [GitLab Beginner](#1-gitlab-beginner). diff --git a/doc/user/abuse_reports.md b/doc/user/abuse_reports.md index 41ee7e62b2c..e6c86cc8f2e 100644 --- a/doc/user/abuse_reports.md +++ b/doc/user/abuse_reports.md @@ -1,6 +1,12 @@ # Abuse reports -Report abuse from users to GitLab administrators. +You can report abuse from other GitLab users to GitLab administrators. + +A GitLab administrator [can then choose](admin_area/abuse_reports.md) to: + +- Remove the user, which deletes them from the instance. +- Block the user, which denies them access to the instance. +- Or remove the report, which retains the users access to the instance. You can report a user through their: @@ -12,7 +18,8 @@ You can report a user through their: To report abuse from a user's profile page: -1. Click on the exclamation point report abuse button at the top right of the user's profile. +1. Click on the exclamation point report abuse button at the top right of the + user's profile. 1. Complete an abuse report. 1. Click the **Send report** button. @@ -26,15 +33,18 @@ To report abuse from a user's comment: 1. Click the **Send report** button. NOTE: **Note:** -A URL to the reported user's comment will be -pre-filled in the abuse report's **Message** field. +A URL to the reported user's comment will be pre-filled in the abuse report's +**Message** field. ## Reporting abuse through a user's issue or merge request The **Report abuse** button is displayed at the top right of the issue or merge request: -- When **Report abuse** is selected from the menu that appears when the **Close issue** or **Close merge request** button is clicked, for users that have permission to close the issue or merge request. -- When viewing the issue or merge request, for users that don't have permission to close the issue or merge request. +- When **Report abuse** is selected from the menu that appears when the + **Close issue** or **Close merge request** button is clicked, for users that + have permission to close the issue or merge request. +- When viewing the issue or merge request, for users that don't have permission + to close the issue or merge request. With the **Report abuse** button displayed, to submit an abuse report: diff --git a/doc/user/admin_area/abuse_reports.md b/doc/user/admin_area/abuse_reports.md index 01c2d9607f5..0c5d2f81e25 100644 --- a/doc/user/admin_area/abuse_reports.md +++ b/doc/user/admin_area/abuse_reports.md @@ -1,31 +1,77 @@ +--- +type: reference, howto +--- + # Abuse reports View and resolve abuse reports from GitLab users. -Admins can view abuse reports in the admin area and are able to -resolve the reports by removing the reported user, blocking the reported user, or removing the report. +GitLab administrators can view and [resolve](#resolving-abuse-reports) abuse +reports in the Admin Area. ## Reporting abuse -To find out more about reporting abuse, see [abuse reports user documentation](../abuse_reports.md). +To find out more about reporting abuse, see [abuse reports user +documentation](../abuse_reports.md). ## Resolving abuse reports -To access abuse reports, go to **Admin area > Abuse Reports**. +To access abuse reports, go to **Admin Area > Abuse Reports**. There are 3 ways to resolve an abuse report, with a button for each method: -- Remove user & report: [Deletes the reported user](../profile/account/delete_account.md) from the instance and removes the abuse report from the list. -- Block user: Blocks the reported user from the instance and does not remove the abuse report from the list. -- Remove report: Removes the abuse report from the list and does not restrict the access for the reported user. +- Remove user & report. This will: + - [Delete the reported user](../profile/account/delete_account.md) from the + instance. + - Remove the abuse report from the list. +- [Block user](#blocking-users). +- Remove report. This will: + - Remove the abuse report from the list. + - Remove access restrictions for the reported user. + +The following is an example of the **Abuse Reports** page: ![abuse-reports-page-image](img/abuse_reports_page.png) -## Blocked users +### Blocking users + +A blocked user cannot log in or access any repositories, but all of their data +remains. + +Blocking a user: + +- Leaves them in the abuse report list. +- Changes the **Block user** button to a disabled **Already blocked** button. + +The user will be notified with the +[following message](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/app/workers/email_receiver_worker.rb#L38): -Blocking a user will not remove the abuse report from the list. +```text +Your account has been blocked. If you believe this is in error, contact a staff member. +``` -Instead, the block button will be disabled and explain that the user is "Already blocked". -You are still able to remove the user and/or report if necessary. +After blocking, you can still either: + +- Remove the user and report if necessary. +- Remove the report. + +The following is an example of a blocked user listed on the **Abuse Reports** +page: ![abuse-report-blocked-user-image](img/abuse_report_blocked_user.png) + +NOTE: **Note:** +Users can be [blocked](../../api/users.md#block-user) and +[unblocked](../../api/users.md#unblock-user) using the GitLab API. + +<!-- ## Troubleshooting + +Include any troubleshooting steps that you can foresee. If you know beforehand what issues +one might have when setting this up, or when something is changed, or on upgrading, it's +important to describe those, too. Think of things that may go wrong and include them here. +This is important to minimize requests for support, and to avoid doc comments with +questions that you know someone might ask. + +Each scenario can be a third-level heading, e.g. `### Getting error message X`. +If you have none to add when creating a doc, leave this section in place +but commented out to help encourage others to add to it in the future. --> diff --git a/doc/user/admin_area/broadcast_messages.md b/doc/user/admin_area/broadcast_messages.md index 02445abdb37..01b6558bdbe 100644 --- a/doc/user/admin_area/broadcast_messages.md +++ b/doc/user/admin_area/broadcast_messages.md @@ -1,3 +1,7 @@ +--- +type: reference, howto +--- + # Broadcast Messages GitLab can display messages to all users of a GitLab instance in a banner that appears in the UI. @@ -51,3 +55,15 @@ Once deleted, the broadcast message is removed from the list of broadcast messag NOTE: **Note:** Broadcast messages can be deleted while active. + +<!-- ## Troubleshooting + +Include any troubleshooting steps that you can foresee. If you know beforehand what issues +one might have when setting this up, or when something is changed, or on upgrading, it's +important to describe those, too. Think of things that may go wrong and include them here. +This is important to minimize requests for support, and to avoid doc comments with +questions that you know someone might ask. + +Each scenario can be a third-level heading, e.g. `### Getting error message X`. +If you have none to add when creating a doc, leave this section in place +but commented out to help encourage others to add to it in the future. --> diff --git a/doc/user/admin_area/custom_project_templates.md b/doc/user/admin_area/custom_project_templates.md index 427f3103cfc..02c2efaa4f3 100644 --- a/doc/user/admin_area/custom_project_templates.md +++ b/doc/user/admin_area/custom_project_templates.md @@ -1,26 +1,49 @@ +--- +type: reference +--- + # Custom instance-level project templates **(PREMIUM ONLY)** > [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/6860) in [GitLab Premium](https://about.gitlab.com/pricing/) 11.2. -When you create a new [project](../project/index.md), creating it based on custom project templates is -a convenient bootstrap option. +GitLab administrators can configure the group where all the custom project +templates are sourced. -GitLab administrators can configure a GitLab group that serves as template -source for an entire GitLab instance under **Admin area > Settings > Custom project templates**. +Every project directly under the group namespace will be +available to the user if they have access to them. For example: + +- Public project in the group will be available to every logged in user. +- Private projects will be available only if the user is a member of the project. + +Repository and database information that are copied over to each new project are +identical to the data exported with +[GitLab's Project Import/Export](../project/settings/import_export.md). NOTE: **Note:** To set project templates at a group level, see [Custom group-level project templates](../group/custom_project_templates.md). -Within this section, you can configure the group where all the custom project -templates are sourced. Every project directly under the group namespace will be -available to the user if they have access to them. For example, every public -project in the group will be available to every logged in user. +## Configuring -However, private projects will be available only if the user is a member of the project. +GitLab administrators can configure a GitLab group that serves as template +source for an entire GitLab instance by: + +1. Navigating to **Admin area > Settings > Templates**. +1. Expanding **Custom project templates**. +1. Selecting a group to use. +1. Pressing **Save changes**. NOTE: **Note:** Projects below subgroups of the template group are **not** supported. -Repository and database information that are copied over to each new project are -identical to the data exported with [GitLab's Project Import/Export](../project/settings/import_export.md). +<!-- ## Troubleshooting + +Include any troubleshooting steps that you can foresee. If you know beforehand what issues +one might have when setting this up, or when something is changed, or on upgrading, it's +important to describe those, too. Think of things that may go wrong and include them here. +This is important to minimize requests for support, and to avoid doc comments with +questions that you know someone might ask. + +Each scenario can be a third-level heading, e.g. `### Getting error message X`. +If you have none to add when creating a doc, leave this section in place +but commented out to help encourage others to add to it in the future. --> diff --git a/doc/user/admin_area/settings/usage_statistics.md b/doc/user/admin_area/settings/usage_statistics.md index f698e0a1608..516600c9d99 100644 --- a/doc/user/admin_area/settings/usage_statistics.md +++ b/doc/user/admin_area/settings/usage_statistics.md @@ -52,8 +52,8 @@ You can view the exact JSON payload in the administration panel. To view the pay 1. Expand **Settings** in the left sidebar and click on **Metrics and profiling**. 1. Expand **Usage statistics** and click on the **Preview payload** button. -You can see how [the usage ping data maps to different stages of the product](https://gitlab.com/gitlab-data/analytics/blob/master/transform/snowflake-dbt/data/ping_metrics_to_stage_mapping_data.csv). - +You can see how [the usage ping data maps to different stages of the product](https://gitlab.com/gitlab-data/analytics/blob/master/transform/snowflake-dbt/data/ping_metrics_to_stage_mapping_data.csv). + ### Deactivate the usage ping The usage ping is opt-out. If you want to deactivate this feature, go to diff --git a/doc/user/application_security/container_scanning/index.md b/doc/user/application_security/container_scanning/index.md index da75684a3fe..86491c7d74e 100644 --- a/doc/user/application_security/container_scanning/index.md +++ b/doc/user/application_security/container_scanning/index.md @@ -1,3 +1,7 @@ +--- +type: reference, howto +--- + # Container Scanning **(ULTIMATE)** > [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/3672) @@ -47,7 +51,7 @@ To enable Container Scanning in your pipeline, you need: your Docker image to your project's [Container Registry](../../project/container_registry.md). The name of the Docker image should match the following scheme: - ``` + ```text $CI_REGISTRY_IMAGE/$CI_COMMIT_REF_SLUG:$CI_COMMIT_SHA ``` @@ -114,7 +118,7 @@ When the GitLab Runner uses the Docker executor and NFS is used (e.g., `/var/lib/docker` is on an NFS mount), Container Scanning might fail with an error like the following: -``` +```text docker: Error response from daemon: failed to copy xattrs: failed to set xattr "security.selinux" on /path/to/file: operation not supported. ``` diff --git a/doc/user/application_security/dast/index.md b/doc/user/application_security/dast/index.md index 4b98dd73d76..88e2d1ef22b 100644 --- a/doc/user/application_security/dast/index.md +++ b/doc/user/application_security/dast/index.md @@ -1,3 +1,7 @@ +--- +type: reference, howto +--- + # Dynamic Application Security Testing (DAST) **(ULTIMATE)** > [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/4348) @@ -199,3 +203,15 @@ Once a vulnerability is found, you can interact with it. Read more on how to For more information about the vulnerabilities database update, check the [maintenance table](../index.md#maintenance-and-update-of-the-vulnerabilities-database). + +<!-- ## Troubleshooting + +Include any troubleshooting steps that you can foresee. If you know beforehand what issues +one might have when setting this up, or when something is changed, or on upgrading, it's +important to describe those, too. Think of things that may go wrong and include them here. +This is important to minimize requests for support, and to avoid doc comments with +questions that you know someone might ask. + +Each scenario can be a third-level heading, e.g. `### Getting error message X`. +If you have none to add when creating a doc, leave this section in place +but commented out to help encourage others to add to it in the future. --> diff --git a/doc/user/application_security/dependency_scanning/index.md b/doc/user/application_security/dependency_scanning/index.md index 7473647f129..10b4d9d4c7c 100644 --- a/doc/user/application_security/dependency_scanning/index.md +++ b/doc/user/application_security/dependency_scanning/index.md @@ -1,3 +1,7 @@ +--- +type: reference, howto +--- + # Dependency Scanning **(ULTIMATE)** > [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/5105) @@ -48,14 +52,15 @@ The following languages and dependency managers are supported. | Language (package managers) | Supported | Scan tool(s) | |----------------------------- | --------- | ------------ | +| Java ([Gradle](https://gradle.org/)) | not currently ([issue](https://gitlab.com/gitlab-org/gitlab-ee/issues/13075 "Dependency Scanning for Gradle" )) | not available | +| Java ([Maven](https://maven.apache.org/)) | yes | [gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) | | JavaScript ([npm](https://www.npmjs.com/), [yarn](https://yarnpkg.com/en/)) | yes | [gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium), [Retire.js](https://retirejs.github.io/retire.js) | +| Go ([Golang](https://golang.org/)) | not currently ([issue](https://gitlab.com/gitlab-org/gitlab-ee/issues/7132 "Dependency Scanning for Go")) | not available | +| PHP ([Composer](https://getcomposer.org/)) | yes | [gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) | | Python ([pip](https://pip.pypa.io/en/stable/)) (only `requirements.txt` supported) | yes | [gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) | +| Python ([Pipfile](https://docs.pipenv.org/en/latest/basics/)) | not currently ([issue](https://gitlab.com/gitlab-org/gitlab-ee/issues/11756 "Pipfile.lock support for Dependency Scanning"))| not available | +| Python ([poetry](https://poetry.eustace.io/)) | not currently ([issue](https://gitlab.com/gitlab-org/gitlab-ee/issues/7006 "Support Poetry in Dependency Scanning")) | not available | | Ruby ([gem](https://rubygems.org/)) | yes | [gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium), [bundler-audit](https://github.com/rubysec/bundler-audit) | -| Java ([Maven](https://maven.apache.org/)) | yes | [gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) | -| PHP ([Composer](https://getcomposer.org/)) | yes | [gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) | -| Python ([poetry](https://poetry.eustace.io/)) | no ([issue](https://gitlab.com/gitlab-org/gitlab-ee/issues/7006 "Support Poetry in Dependency Scanning")) | not available | -| Python ([Pipfile](https://docs.pipenv.org/en/latest/basics/)) | no ([issue](https://gitlab.com/gitlab-org/gitlab-ee/issues/11756 "Pipfile.lock support for Dependency Scanning"))| not available | -| Go ([Golang](https://golang.org/)) | no ([issue](https://gitlab.com/gitlab-org/gitlab-ee/issues/7132 "Dependency Scanning for Go")) | not available | ## Remote checks @@ -150,7 +155,7 @@ using environment variables. | `DS_DOCKER_CLIENT_NEGOTIATION_TIMEOUT` | Time limit for Docker client negotiation. Timeouts are parsed using Go's [`ParseDuration`](https://golang.org/pkg/time/#ParseDuration). Valid time units are `ns`, `us` (or `µs`), `ms`, `s`, `m`, `h`. For example, `300ms`, `1.5h`, or `2h45m`. | | `DS_PULL_ANALYZER_IMAGE_TIMEOUT` | Time limit when pulling the image of an analyzer. Timeouts are parsed using Go's [`ParseDuration`](https://golang.org/pkg/time/#ParseDuration). Valid time units are `ns`, `us` (or `µs`), `ms`, `s`, `m`, `h`. For example, `300ms`, `1.5h`, or `2h45m`. | | `DS_RUN_ANALYZER_TIMEOUT` | Time limit when running an analyzer. Timeouts are parsed using Go's [`ParseDuration`](https://golang.org/pkg/time/#ParseDuration). Valid time units are `ns`, `us` (or `µs`), `ms`, `s`, `m`, `h`. For example, `300ms`, `1.5h`, or `2h45m`. | -| `PIP_INDEX_URL` | Base URL of Python Package Index (default https://pypi.org/simple). | +| `PIP_INDEX_URL` | Base URL of Python Package Index (default `https://pypi.org/simple`). | | `PIP_EXTRA_INDEX_URL` | Array of [extra URLs](https://pip.pypa.io/en/stable/reference/pip_install/#cmdoption-extra-index-url) of package indexes to use in addition to `PIP_INDEX_URL`. Comma separated. | ## Reports JSON format @@ -331,7 +336,7 @@ project's dependencies with their versions. This list can be generated only for [languages and package managers](#supported-languages-and-package-managers) supported by Gemnasium. -To see the generated dependency list, navigate to your project's **Project > Dependency List**. +To see the generated dependency list, navigate to your project's **Security & Compliance > Dependency List**. ## Versioning and release process @@ -342,3 +347,15 @@ Please check the [Release Process documentation](https://gitlab.com/gitlab-org/s You can search the [gemnasium-db](https://gitlab.com/gitlab-org/security-products/gemnasium-db) project to find a vulnerability in the Gemnasium database. You can also [submit new vulnerabilities](https://gitlab.com/gitlab-org/security-products/gemnasium-db/blob/master/CONTRIBUTING.md). + +<!-- ## Troubleshooting + +Include any troubleshooting steps that you can foresee. If you know beforehand what issues +one might have when setting this up, or when something is changed, or on upgrading, it's +important to describe those, too. Think of things that may go wrong and include them here. +This is important to minimize requests for support, and to avoid doc comments with +questions that you know someone might ask. + +Each scenario can be a third-level heading, e.g. `### Getting error message X`. +If you have none to add when creating a doc, leave this section in place +but commented out to help encourage others to add to it in the future. --> diff --git a/doc/user/application_security/index.md b/doc/user/application_security/index.md index 56a4cbd26d2..31f0b5a050c 100644 --- a/doc/user/application_security/index.md +++ b/doc/user/application_security/index.md @@ -1,10 +1,22 @@ +--- +type: reference, howto +--- + # GitLab Secure **(ULTIMATE)** -Check your application for security vulnerabilities that may lead to unauthorized access, -data leaks, and denial of services. GitLab will perform static and dynamic tests on the -code of your application, looking for known flaws and report them in the merge request -so you can fix them before merging. Security teams can use dashboards to get a -high-level view on projects and groups, and start remediation processes when needed. +Check your application for security vulnerabilities that may lead to +unauthorized access, data leaks, and denial of services. + +GitLab will perform static and dynamic tests on the code of your application, +looking for known flaws and report them in the merge request so you can fix +them before merging. + +Security teams can use dashboards to get a high-level view on projects and +groups, and start remediation processes when needed. + +<i class="fa fa-youtube-play youtube" aria-hidden="true"></i> +For an overview of application security with GitLab, see +[Security Deep Dive](https://www.youtube.com/watch?v=k4vEJnGYy84). ## Security scanning tools @@ -54,7 +66,7 @@ Each security vulnerability in the merge request report or the entry, a detailed information will pop up with different possible options: - [Dismiss vulnerability](#dismissing-a-vulnerability): Dismissing a vulnerability - will place a <s>strikethrough</s> styling on it. + will place a ~~strikethrough~~ styling on it. - [Create issue](#creating-an-issue-for-a-vulnerability): The new issue will have the title and description pre-populated with the information from the vulnerability report and will be created as [confidential](../project/issues/confidential_issues.md) by default. @@ -124,7 +136,7 @@ generated by GitLab. To apply the fix: #### Creating a merge request from a vulnerability > [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/9224) in - [GitLab Ultimate](https://about.gitlab.com/pricing) 11.9. +> [GitLab Ultimate](https://about.gitlab.com/pricing) 11.9. In certain cases, GitLab will allow you to create a merge request that will automatically remediate the vulnerability. Any vulnerability that has a @@ -135,3 +147,15 @@ If this action is available there will be a **Create merge request** button in t Clicking on this button will create a merge request to apply the solution onto the source branch. ![Create merge request from vulnerability](img/create_issue_with_list_hover.png) + +<!-- ## Troubleshooting + +Include any troubleshooting steps that you can foresee. If you know beforehand what issues +one might have when setting this up, or when something is changed, or on upgrading, it's +important to describe those, too. Think of things that may go wrong and include them here. +This is important to minimize requests for support, and to avoid doc comments with +questions that you know someone might ask. + +Each scenario can be a third-level heading, e.g. `### Getting error message X`. +If you have none to add when creating a doc, leave this section in place +but commented out to help encourage others to add to it in the future. --> diff --git a/doc/user/application_security/license_management/index.md b/doc/user/application_security/license_management/index.md index b0eb753938b..c324848c703 100644 --- a/doc/user/application_security/license_management/index.md +++ b/doc/user/application_security/license_management/index.md @@ -1,3 +1,7 @@ +--- +type: reference, howto +--- + # License Management **(ULTIMATE)** > [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/5483) @@ -227,3 +231,15 @@ pipeline ID that has a `license_management` job to see the Licenses tab with the licenses (if any). ![License Management Pipeline Tab](img/license_management_pipeline_tab.png) + +<!-- ## Troubleshooting + +Include any troubleshooting steps that you can foresee. If you know beforehand what issues +one might have when setting this up, or when something is changed, or on upgrading, it's +important to describe those, too. Think of things that may go wrong and include them here. +This is important to minimize requests for support, and to avoid doc comments with +questions that you know someone might ask. + +Each scenario can be a third-level heading, e.g. `### Getting error message X`. +If you have none to add when creating a doc, leave this section in place +but commented out to help encourage others to add to it in the future. --> diff --git a/doc/user/application_security/sast/index.md b/doc/user/application_security/sast/index.md index 7df86eedd18..aac881112ff 100644 --- a/doc/user/application_security/sast/index.md +++ b/doc/user/application_security/sast/index.md @@ -1,3 +1,7 @@ +--- +type: reference, howto +--- + # Static Application Security Testing (SAST) **(ULTIMATE)** > [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/3775) @@ -334,3 +338,15 @@ Once a vulnerability is found, you can interact with it. Read more on how to For more information about the vulnerabilities database update, check the [maintenance table](../index.md#maintenance-and-update-of-the-vulnerabilities-database). + +<!-- ## Troubleshooting + +Include any troubleshooting steps that you can foresee. If you know beforehand what issues +one might have when setting this up, or when something is changed, or on upgrading, it's +important to describe those, too. Think of things that may go wrong and include them here. +This is important to minimize requests for support, and to avoid doc comments with +questions that you know someone might ask. + +Each scenario can be a third-level heading, e.g. `### Getting error message X`. +If you have none to add when creating a doc, leave this section in place +but commented out to help encourage others to add to it in the future. --> diff --git a/doc/user/application_security/security_dashboard/img/dashboard.png b/doc/user/application_security/security_dashboard/img/dashboard.png Binary files differdeleted file mode 100644 index a75168b1ce4..00000000000 --- a/doc/user/application_security/security_dashboard/img/dashboard.png +++ /dev/null diff --git a/doc/user/application_security/security_dashboard/img/group_security_dashboard.png b/doc/user/application_security/security_dashboard/img/group_security_dashboard.png Binary files differnew file mode 100644 index 00000000000..40689861e2a --- /dev/null +++ b/doc/user/application_security/security_dashboard/img/group_security_dashboard.png diff --git a/doc/user/application_security/security_dashboard/img/project_security_dashboard.png b/doc/user/application_security/security_dashboard/img/project_security_dashboard.png Binary files differindex f0dad6c54d0..89b310895d3 100644 --- a/doc/user/application_security/security_dashboard/img/project_security_dashboard.png +++ b/doc/user/application_security/security_dashboard/img/project_security_dashboard.png diff --git a/doc/user/application_security/security_dashboard/index.md b/doc/user/application_security/security_dashboard/index.md index 2a2385c00ae..ac8c1ac0354 100644 --- a/doc/user/application_security/security_dashboard/index.md +++ b/doc/user/application_security/security_dashboard/index.md @@ -1,3 +1,7 @@ +--- +type: reference, howto +--- + # GitLab Security Dashboard **(ULTIMATE)** The Security Dashboard is a good place to get an overview of all the security @@ -16,9 +20,9 @@ To benefit from the Security Dashboard you must first configure one of the The Security Dashboard supports the following reports: - [Container Scanning](../container_scanning/index.md) -- [DAST](../dast/index.md) +- [Dynamic Application Security Testing](../dast/index.md) - [Dependency Scanning](../dependency_scanning/index.md) -- [SAST](../sast/index.md) +- [Static Application Security Testing](../sast/index.md) ## Requirements @@ -43,13 +47,13 @@ for your project. Use it to find and fix vulnerabilities affecting the ## Group Security Dashboard > [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/6709) in - [GitLab Ultimate](https://about.gitlab.com/pricing) 11.5. +> [GitLab Ultimate](https://about.gitlab.com/pricing) 11.5. The group Security Dashboard gives an overview of the vulnerabilities of all the projects in a group and its subgroups. First, navigate to the Security Dashboard found under your group's -**Overview > Security Dashboard**. +**Security** tab. Once you're on the dashboard, at the top you should see a series of filters for: @@ -58,7 +62,7 @@ Once you're on the dashboard, at the top you should see a series of filters for: - Report type - Project -![dashboard with action buttons and metrics](img/dashboard.png) +![dashboard with action buttons and metrics](img/group_security_dashboard.png) Selecting one or more filters will filter the results in this page. The first section is an overview of all the vulnerabilities, grouped by severity. @@ -102,3 +106,15 @@ That way, reports are created even if no code change happens. When using [Auto DevOps](../../../topics/autodevops/index.md), use [special environment variables](../../../topics/autodevops/index.md#environment-variables) to configure daily security scans. + +<!-- ## Troubleshooting + +Include any troubleshooting steps that you can foresee. If you know beforehand what issues +one might have when setting this up, or when something is changed, or on upgrading, it's +important to describe those, too. Think of things that may go wrong and include them here. +This is important to minimize requests for support, and to avoid doc comments with +questions that you know someone might ask. + +Each scenario can be a third-level heading, e.g. `### Getting error message X`. +If you have none to add when creating a doc, leave this section in place +but commented out to help encourage others to add to it in the future. --> diff --git a/doc/user/clusters/applications.md b/doc/user/clusters/applications.md index d5c836554ce..1bc43f4b7a4 100644 --- a/doc/user/clusters/applications.md +++ b/doc/user/clusters/applications.md @@ -5,11 +5,12 @@ be added directly to your configured cluster. These applications are needed for [Review Apps](../../ci/review_apps/index.md) and [deployments](../../ci/environments.md) when using [Auto DevOps](../../topics/autodevops/index.md). You can install them after you -[create a cluster](../project/clusters/index.md#adding-and-creating-a-new-gke-cluster-via-gitlab). +[create a cluster](../project/clusters/index.md#add-new-gke-cluster). ## Installing applications Applications managed by GitLab will be installed onto the `gitlab-managed-apps` namespace. + This namespace: - Is different from the namespace used for project deployments. @@ -94,7 +95,7 @@ CI/CD](../../ci/README.md), the open-source continuous integration service included with GitLab that coordinates the jobs. When installing the GitLab Runner via the applications, it will run in **privileged mode** by default. Make sure you read the [security -implications](../project/clusters/index.md/#security-implications) before doing so. +implications](../project/clusters/index.md#security-implications) before doing so. NOTE: **Note:** The diff --git a/doc/user/group/clusters/index.md b/doc/user/group/clusters/index.md index 0dffc216f8e..625c5440ec0 100644 --- a/doc/user/group/clusters/index.md +++ b/doc/user/group/clusters/index.md @@ -5,7 +5,6 @@ type: reference # Group-level Kubernetes clusters > [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/34758) in GitLab 11.6. -> Group Cluster integration is currently in [Beta](https://about.gitlab.com/handbook/product/#alpha-beta-ga). ## Overview @@ -138,6 +137,13 @@ The result will then be: - The Staging cluster will be used for the `deploy to staging` job. - The Production cluster will be used for the `deploy to production` job. +## Security of Runners + +For important information about securely configuring GitLab Runners, see +[Security of +Runners](../../project/clusters/index.md#security-of-gitlab-runners) +documentation for project-level clusters. + <!-- ## Troubleshooting Include any troubleshooting steps that you can foresee. If you know beforehand what issues diff --git a/doc/user/group/index.md b/doc/user/group/index.md index 14c831fe671..98e1c654d0e 100644 --- a/doc/user/group/index.md +++ b/doc/user/group/index.md @@ -331,7 +331,7 @@ This will disable the option for all users who previously had permissions to operate project memberships, so no new users can be added. Furthermore, any request to add a new user to a project through API will not be possible. -#### IP access restriction **(ULTIMATE)** +#### IP access restriction **(ULTIMATE ONLY)** > [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/1985) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.0. diff --git a/doc/user/group/saml_sso/img/scim_attribute_mapping.png b/doc/user/group/saml_sso/img/scim_attribute_mapping.png Binary files differindex c9f6b71f5b0..dad459d8c28 100644 --- a/doc/user/group/saml_sso/img/scim_attribute_mapping.png +++ b/doc/user/group/saml_sso/img/scim_attribute_mapping.png diff --git a/doc/user/group/saml_sso/img/scim_name_identifier_mapping.png b/doc/user/group/saml_sso/img/scim_name_identifier_mapping.png Binary files differnew file mode 100644 index 00000000000..85e5648816e --- /dev/null +++ b/doc/user/group/saml_sso/img/scim_name_identifier_mapping.png diff --git a/doc/user/group/saml_sso/img/scim_provisioning_status.png b/doc/user/group/saml_sso/img/scim_provisioning_status.png Binary files differnew file mode 100644 index 00000000000..4b8887b5418 --- /dev/null +++ b/doc/user/group/saml_sso/img/scim_provisioning_status.png diff --git a/doc/user/group/saml_sso/scim_setup.md b/doc/user/group/saml_sso/scim_setup.md index 55c5a18db7d..ab48c9080a9 100644 --- a/doc/user/group/saml_sso/scim_setup.md +++ b/doc/user/group/saml_sso/scim_setup.md @@ -45,7 +45,7 @@ The following identity providers are supported: Feature.enable(:group_scim, group) ``` -### GitLab configuration +## GitLab configuration Once [Single sign-on](index.md) has been configured, we can: @@ -55,41 +55,48 @@ Once [Single sign-on](index.md) has been configured, we can: ![SCIM token configuration](img/scim_token.png) -## SCIM IdP configuration +## Identity Provider configuration -### Configuration on Azure +### Azure -In the [Single sign-on](index.md) configuration for the group, make sure -that the **Name identifier value** (NameID) points to a unique identifier, such -as the `user.objectid`. This will match the `extern_uid` used on GitLab. +First, double check the [Single sign-on](index.md) configuration for your group and ensure that **Name identifier value** (NameID) points to `user.objectid` or another unique identifier. This will match the `extern_uid` used on GitLab. -The GitLab app in Azure needs to be configured following -[Azure's SCIM setup](https://docs.microsoft.com/en-us/azure/active-directory/manage-apps/use-scim-to-provision-users-and-groups#getting-started). +![Name identifier value mapping](img/scim_name_identifier_mapping.png) -Note the following: +#### Set up admin credentials + +Next, configure your GitLab application in Azure by following the +[Provisioning users and groups to applications that support SCIM](https://docs.microsoft.com/en-us/azure/active-directory/manage-apps/use-scim-to-provision-users-and-groups#provisioning-users-and-groups-to-applications-that-support-scim) +section in Azure's SCIM setup documentation. + +During this configuration, note the following: - The `Tenant URL` and `secret token` are the ones retrieved in the [previous step](#gitlab-configuration). - Should there be any problems with the availability of GitLab or similar errors, the notification email set will get those. +- It is recommended to set a notification email and check the **Send an email notification when a failure occurs** checkbox. - For mappings, we will only leave `Synchronize Azure Active Directory Users to AppName` enabled. -You can then test the connection clicking on `Test Connection`. +You can then test the connection by clicking on **Test Connection**. If the connection is successful, be sure to save your configuration before moving on. See below for [troubleshooting](#troubleshooting). -### Synchronize Azure Active Directory users +#### Configure attribute mapping -1. Click on `Synchronize Azure Active Directory Users to AppName`, to configure - the attribute mapping. -1. Select the unique identifier (in the example `objectId`) as the `id` and `externalId`, - and enable the `Create`, `Update`, and `Delete` actions. -1. Map the `userPricipalName` to `emails[type eq "work"].value` and `mailNickname` to - `userName`. +1. Click on `Synchronize Azure Active Directory Users to AppName`, to configure the attribute mapping. +1. Click **Delete** next to the `mail` mapping. +1. Map `userPrincipalName` to `emails[type eq "work"].value` and change it's **Matching precedence** to `2`. +1. Map `mailNickname` to `userName`. +1. Create a new mapping by clicking **Add New Mapping** then set **Source attribute** to `objectId`, **Target attribute** to `id`, **Match objects using this attribute** to `Yes`, and **Matching precedence** to `1`. +1. Create a new mapping by clicking **Add New Mapping** then set **Source attribute** to `objectId`, and **Target attribute** to `externalId`. +1. Click the `userPrincipalName` mapping and change **Match objects using this attribute** to `No`. - Example configuration: + Save your changes and you should have the following configuration: ![Azure's attribute mapping configuration](img/scim_attribute_mapping.png) -1. Click on **Show advanced options > Edit attribute list for AppName**. + NOTE: **Note:** If you used a unique identifier **other than** `objectId`, be sure to map it instead to both `id` and `externalId`. + +1. Below the mapping list click on **Show advanced options > Edit attribute list for AppName**. 1. Leave the `id` as the primary and only required field. NOTE: **Note:** @@ -99,24 +106,20 @@ You can then test the connection clicking on `Test Connection`. ![Azure's attribute advanced configuration](img/scim_advanced.png) 1. Save all the screens and, in the **Provisioning** step, set - the `Provisioning Status` to `ON`. + the `Provisioning Status` to `On`. + + ![Provisioning status toggle switch](img/scim_provisioning_status.png) NOTE: **Note:** You can control what is actually synced by selecting the `Scope`. For example, `Sync only assigned users and groups` will only sync the users assigned to - the application (`Users and groups`), otherwise it will sync the whole Active Directory. + the application (`Users and groups`), otherwise, it will sync the whole Active Directory. Once enabled, the synchronization details and any errors will appear on the bottom of the **Provisioning** screen, together with a link to the audit logs. -<!-- ## Troubleshooting +## Troubleshooting -Include any troubleshooting steps that you can foresee. If you know beforehand what issues -one might have when setting this up, or when something is changed, or on upgrading, it's -important to describe those, too. Think of things that may go wrong and include them here. -This is important to minimize requests for support, and to avoid doc comments with -questions that you know someone might ask. +### Testing Azure connection: invalid credentials -Each scenario can be a third-level heading, e.g. `### Getting error message X`. -If you have none to add when creating a doc, leave this section in place -but commented out to help encourage others to add to it in the future. --> +When testing the connection, you may encounter an error: **You appear to have entered invalid credentials. Please confirm you are using the correct information for an administrative account**. If `Tenant URL` and `secret token` are correct, check whether your group path contains characters that may be considered invalid JSON primitives (such as `.`). Removing such characters from the group path typically resolves the error. diff --git a/doc/user/instance/clusters/index.md b/doc/user/instance/clusters/index.md index 894f83d3c75..f557dcf4b3c 100644 --- a/doc/user/instance/clusters/index.md +++ b/doc/user/instance/clusters/index.md @@ -1,7 +1,6 @@ # Instance-level Kubernetes clusters > [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/39840) in GitLab 11.11. -> Instance-level cluster integration is currently in [Beta](https://about.gitlab.com/handbook/product/#alpha-beta-ga). ## Overview diff --git a/doc/user/markdown.md b/doc/user/markdown.md index 37f3f21f539..9380dcf2a32 100644 --- a/doc/user/markdown.md +++ b/doc/user/markdown.md @@ -136,26 +136,26 @@ Supported formats (named colors are not supported): Color written inside backticks will be followed by a color "chip": ```markdown -`#F00` -`#F00A` -`#FF0000` -`#FF0000AA` -`RGB(0,255,0)` -`RGB(0%,100%,0%)` -`RGBA(0,255,0,0.3)` -`HSL(540,70%,50%)` -`HSLA(540,70%,50%,0.3)` -``` - -`#F00` -`#F00A` -`#FF0000` -`#FF0000AA` -`RGB(0,255,0)` -`RGB(0%,100%,0%)` -`RGBA(0,255,0,0.3)` -`HSL(540,70%,50%)` -`HSLA(540,70%,50%,0.3)` +`#F00` +`#F00A` +`#FF0000` +`#FF0000AA` +`RGB(0,255,0)` +`RGB(0%,100%,0%)` +`RGBA(0,255,0,0.3)` +`HSL(540,70%,50%)` +`HSLA(540,70%,50%,0.3)` +``` + +`#F00` +`#F00A` +`#FF0000` +`#FF0000AA` +`RGB(0,255,0)` +`RGB(0%,100%,0%)` +`RGBA(0,255,0,0.3)` +`HSL(540,70%,50%)` +`HSLA(540,70%,50%,0.3)` ### Diagrams and flowcharts using Mermaid @@ -397,6 +397,7 @@ unordered or ordered lists: - [ ] Sub-task 1 - [x] Sub-task 2 - [ ] Sub-task 3 + 1. [x] Completed task 1. [ ] Incomplete task 1. [ ] Sub-task 1 @@ -408,6 +409,7 @@ unordered or ordered lists: - [ ] Sub-task 1 - [x] Sub-task 2 - [ ] Sub-task 3 + 1. [x] Completed task 1. [ ] Incomplete task 1. [ ] Sub-task 1 @@ -976,7 +978,7 @@ after the `</summary>` tag and before the `</details>` tag, as shown in the exam These details _will_ remain **hidden** until expanded. - PASTE LOGS HERE +PASTE LOGS HERE </details> ``` @@ -988,7 +990,7 @@ These details _will_ remain **hidden** until expanded. These details <em>will</em> remain <b>hidden</b> until expanded. - PASTE LOGS HERE +PASTE LOGS HERE </details> @@ -1047,14 +1049,14 @@ A new line due to the previous backslash. First paragraph. Another line in the same paragraph. -A third line in the same paragraph, but this time ending with two spaces. +A third line in the same paragraph, but this time ending with two spaces. A new line directly under the first paragraph. <!-- (Do *NOT* remove the two ending whitespaces in the second line) --> <!-- (They are needed for the Markdown text to render correctly on docs.gitlab.com, the backslash works fine inside GitLab itself) --> Second paragraph. -Another line, this time ending with a backslash. +Another line, this time ending with a backslash. A new line due to the previous backslash. ### Links @@ -1135,13 +1137,13 @@ GFM will autolink almost any URL you put into your text: ### Lists Ordered and unordered lists can be easily created. Add the number you want the list -to start with, like `1. ` (with a space) at the start of each line for ordered lists. +to start with, like `1.`, followed by a space, at the start of each line for ordered lists. After the first number, it does not matter what number you use, ordered lists will be -numbered automatically by vertical order, so repeating `1. ` for all items in the -same list is common. If you start with a number other than `1. `, it will use that as the first +numbered automatically by vertical order, so repeating `1.` for all items in the +same list is common. If you start with a number other than `1.`, it will use that as the first number, and count up from there. -Add a `* `, `- ` or `+ ` (with a space) at the start of each line for unordered lists, but +Add a `*`, `-` or `+`, followed by a space, at the start of each line for unordered lists, but you should not use a mix of them. Examples: @@ -1156,7 +1158,9 @@ Examples: 4. And another item. * Unordered lists can use asterisks + - Or minuses + + Or pluses ``` @@ -1170,9 +1174,11 @@ Examples: 1. Next ordered sub-list item 1. And another item. -* Unordered lists can use asterisks +- Unordered lists can use asterisks + - Or minuses -+ Or pluses + +- Or pluses --- diff --git a/doc/user/permissions.md b/doc/user/permissions.md index 044be05b932..e6822f0c52c 100644 --- a/doc/user/permissions.md +++ b/doc/user/permissions.md @@ -47,6 +47,7 @@ The following table depicts the various user permission levels in a project. | View approved/blacklisted licenses **(ULTIMATE)** | ✓ | ✓ | ✓ | ✓ | ✓ | | View license management reports **(ULTIMATE)** | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ | | View Security reports **(ULTIMATE)** | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ | +| View [Design Management](project/issues/design_management.md) pages **(PREMIUM)** | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ | | View project code | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ | | Pull project code | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ | | View GitLab Pages protected by [access control](project/pages/introduction.md#gitlab-pages-access-control-core-only) | ✓ | ✓ | ✓ | ✓ | ✓ | @@ -74,6 +75,7 @@ The following table depicts the various user permission levels in a project. | View Error Tracking list | | ✓ | ✓ | ✓ | ✓ | | Pull from [Maven repository](project/packages/maven_repository.md) or [NPM registry](project/packages/npm_registry.md) **(PREMIUM)** | | ✓ | ✓ | ✓ | ✓ | | Publish to [Maven repository](project/packages/maven_repository.md) or [NPM registry](project/packages/npm_registry.md) **(PREMIUM)** | | | ✓ | ✓ | ✓ || +| Upload [Design Management](project/issues/design_management.md) files **(PREMIUM)** | | | ✓ | ✓ | ✓ | | Create new branches | | | ✓ | ✓ | ✓ | | Push to non-protected branches | | | ✓ | ✓ | ✓ | | Force push to non-protected branches | | | ✓ | ✓ | ✓ | diff --git a/doc/user/profile/account/delete_account.md b/doc/user/profile/account/delete_account.md index 304a7984191..cbee79de493 100644 --- a/doc/user/profile/account/delete_account.md +++ b/doc/user/profile/account/delete_account.md @@ -1,37 +1,71 @@ -# Deleting a User Account +# Deleting a User account + +Users can be deleted from a GitLab instance, either by: + +- The user themselves. +- An administrator. NOTE: **Note:** Deleting a user will delete all projects in that user namespace. -- As a user, you can delete your own account by navigating to **Settings** > **Account** and selecting **Delete account** -- As an admin, you can delete a user account by navigating to the **Admin Area**, selecting the **Users** tab, selecting a user, and clicking on **Delete user** +## As a user + +As a user, you can delete your own account by: + +1. Clicking on your avatar. +1. Navigating to **Settings > Account**. +1. Selecting **Delete account**. + +## As an administrator + +As an administrator, you can delete a user account by: + +1. Navigating to **Admin Area > Overview > Users**. +1. Selecting a user. +1. Under the **Account** tab, clicking: + - **Delete user** to delete only the user but maintaining their + [associated records](#associated-records). + - **Delete user and contributions** to delete the user and + their associated records. + +### Blocking a user + +In addition to blocking a user +[via an abuse report](../../admin_area/abuse_reports.md#blocking-users), +a user can be blocked directly from the Admin area. To do this: + +1. Navigate to **Admin Area > Overview > Users**. +1. Selecting a user. +1. Under the **Account** tab, click **Block user**. ## Associated Records -> Introduced for issues in [GitLab 9.0][ce-7393], and for merge requests, award - emoji, notes, and abuse reports in [GitLab 9.1][ce-10467]. - Hard deletion from abuse reports and spam logs was introduced in - [GitLab 9.1][ce-10273], and from the API in [GitLab 9.3][ce-11853]. +> - Introduced for issues in +> [GitLab 9.0](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7393). +> - Introduced for merge requests, award emoji, notes, and abuse reports in +> [GitLab 9.1](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/10467). +> - Hard deletion from abuse reports and spam logs was introduced in +> [GitLab 9.1](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/10273), +> and from the API in +> [GitLab 9.3](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/11853). When a user account is deleted, not all associated records are deleted with it. Here's a list of things that will **not** be deleted: -- Issues that the user created -- Merge requests that the user created -- Notes that the user created -- Abuse reports that the user reported -- Award emoji that the user created +- Issues that the user created. +- Merge requests that the user created. +- Notes that the user created. +- Abuse reports that the user reported. +- Award emoji that the user created. Instead of being deleted, these records will be moved to a system-wide -user with the username "Ghost User", whose sole purpose is to act as a container for such records. Any commits made by a deleted user will still display the username of the original user. - -When a user is deleted from an [abuse report](../../admin_area/abuse_reports.md) or spam log, these associated -records are not ghosted and will be removed, along with any groups the user -is a sole owner of. Administrators can also request this behaviour when -deleting users from the [API](../../../api/users.md#user-deletion) or the -admin area. - -[ce-7393]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7393 -[ce-10273]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/10273 -[ce-10467]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/10467 -[ce-11853]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/11853 +user with the username "Ghost User", whose sole purpose is to act as a container +for such records. Any commits made by a deleted user will still display the +username of the original user. + +When a user is deleted from an [abuse report](../../admin_area/abuse_reports.md) +or spam log, these associated records are not ghosted and will be removed, along +with any groups the user is a sole owner of. + +Administrators can also request this behavior when deleting users from the +[API](../../../api/users.md#user-deletion) or the Admin Area. diff --git a/doc/user/profile/index.md b/doc/user/profile/index.md index 61a30a775b0..fc5eb8c7b56 100644 --- a/doc/user/profile/index.md +++ b/doc/user/profile/index.md @@ -147,39 +147,40 @@ You can also set your current status [using the API](../../api/users.md#user-sta > [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/21598) in GitLab 11.4. -A commit email, is the email that will be displayed in every Git-related action done through the -GitLab interface. +A commit email is an email address displayed in every Git-related action carried out through the GitLab interface. -You are able to select from the list of your own verified emails which email you want to use as the commit email. +Any of your own verified email addresses can be used as the commit email. -To change it: +To change your commit email: -1. Open the user menu in the top-right corner of the navigation bar. -1. Hit **Commit email** selection box. +1. Click on your avatar at the top-right corner of the navigation bar. +1. From the menu that appears, click **Settings**. +1. In the **Main settings** section, locate **Commit email** dropdown. 1. Select any of the verified emails. -1. Hit **Update profile settings**. +1. Press **Update profile settings**. ### Private commit email > [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/22560) in GitLab 11.5. -GitLab provides the user with an automatically generated private commit email option, +GitLab provides users with an automatically generated private commit email option, which allows the user to not make their email information public. To enable this option: -1. Open the user menu in the top-right corner of the navigation bar. -1. Hit **Commit email** selection box. -1. Select **Use a private email** option. -1. Hit **Update profile settings**. +1. Click on your avatar at the top-right corner of the navigation bar. +1. From the menu that appears, click **Settings**. +1. In the **Main settings** section, locate **Commit email** dropdown. +1. Select the "Use a private email" option. +1. Press **Update profile settings**. Once this option is enabled, every Git-related action will be performed using the private commit email. -In order to stay fully annonymous, you can also copy this private commit email +In order to stay fully anonymous, you can also copy this private commit email and configure it on your local machine using the following command: -``` -git config --global user.email "YOUR_PRIVATE_COMMIT_EMAIL" +```sh +git config --global user.email <YOUR_PRIVATE_COMMIT_EMAIL> ``` ## Troubleshooting diff --git a/doc/user/project/clusters/eks_and_gitlab/index.md b/doc/user/project/clusters/eks_and_gitlab/index.md index 55a9fbabf98..28f3420de35 100644 --- a/doc/user/project/clusters/eks_and_gitlab/index.md +++ b/doc/user/project/clusters/eks_and_gitlab/index.md @@ -253,7 +253,7 @@ With RBAC disabled and services deployed, [Auto DevOps](../../../../topics/autodevops/index.md) can now be leveraged to build, test, and deploy the app. -[Enable Auto DevOps](../../../../topics/autodevops/index.md#enablingdisabling-auto-devops-at-the-project-level) +[Enable Auto DevOps](../../../../topics/autodevops/index.md#at-the-project-level) if not already enabled. If a wildcard DNS entry was created resolving to the Load Balancer, enter it in the `domain` field under the Auto DevOps settings. Otherwise, the deployed app will not be externally available outside of the cluster. diff --git a/doc/user/project/clusters/index.md b/doc/user/project/clusters/index.md index 4c247691757..918944d72a1 100644 --- a/doc/user/project/clusters/index.md +++ b/doc/user/project/clusters/index.md @@ -1,33 +1,113 @@ -# Connecting GitLab with a Kubernetes cluster +# Kubernetes clusters -> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/35954) in GitLab 10.1. +> - [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/35954) in GitLab 10.1 for projects. +> - [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/34758) in +> GitLab 11.6 for [groups](../../group/clusters/index.md). +> - [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/39840) in +> GitLab 11.11 for [instances](../../instance/clusters/index.md). -Connect your project to Google Kubernetes Engine (GKE) or an existing Kubernetes -cluster in a few steps. +GitLab provides many features with a Kubernetes integration. Kubernetes can be +integrated with projects, but also: + +- [Groups](../../group/clusters/index.md). +- [Instances](../../instance/clusters/index.md). NOTE: **Scalable app deployment with GitLab and Google Cloud Platform** [Watch the webcast](https://about.gitlab.com/webcast/scalable-app-deploy/) and learn how to spin up a Kubernetes cluster managed by Google Cloud Platform (GCP) in a few clicks. ## Overview -With one or more Kubernetes clusters associated to your project, you can use -[Review Apps](../../../ci/review_apps/index.md), deploy your applications, run -your pipelines, use it with [Auto DevOps](../../../topics/autodevops/index.md), -and much more, all from within GitLab. +Using the GitLab project Kubernetes integration, you can: + +- Use [Review Apps](../../../ci/review_apps/index.md). +- Run [pipelines](../../../ci/pipelines.md). +- [Deploy](#deploying-to-a-kubernetes-cluster) your applications. +- Detect and [monitor Kubernetes](#kubernetes-monitoring). +- Use it with [Auto DevOps](#auto-devops). +- Use [Web terminals](#web-terminals). +- Use [Deploy Boards](#deploy-boards-premium). **(PREMIUM)** +- Use [Canary Deployments](#canary-deployments-premium). **(PREMIUM)** +- View [Pod logs](#pod-logs-ultimate). **(ULTIMATE)** + +You can also: + +- Connect and deploy to an [Amazon EKS cluster](eks_and_gitlab/index.html). +- Run serverless workloads on [Kubernetes with Knative](serverless/index.md). + +### Deploy Boards **(PREMIUM)** + +GitLab's Deploy Boards offer a consolidated view of the current health and +status of each CI [environment](../../../ci/environments.md) running on Kubernetes, +displaying the status of the pods in the deployment. Developers and other +teammates can view the progress and status of a rollout, pod by pod, in the +workflow they already use without any need to access Kubernetes. + +[Read more about Deploy Boards](../deploy_boards.md) -There are two options when adding a new cluster to your project; either associate -your account with Google Kubernetes Engine (GKE) so that you can [create new -clusters](#adding-and-creating-a-new-gke-cluster-via-gitlab) from within GitLab, -or provide the credentials to an [existing Kubernetes cluster](#adding-an-existing-kubernetes-cluster). +### Canary Deployments **(PREMIUM)** + +Leverage [Kubernetes' Canary deployments](https://kubernetes.io/docs/concepts/cluster-administration/manage-deployment/#canary-deployments) +and visualize your canary deployments right inside the Deploy Board, without +the need to leave GitLab. + +[Read more about Canary Deployments](../canary_deployments.md) + +### Pod logs **(ULTIMATE)** + +GitLab makes it easy to view the logs of running pods in connected Kubernetes clusters. By displaying the logs directly in GitLab, developers can avoid having to manage console tools or jump to a different interface. + +[Read more about Kubernetes pod logs](kubernetes_pod_logs.md) + +### Kubernetes monitoring + +Automatically detect and monitor Kubernetes metrics. Automatic monitoring of +[NGINX ingress](../integrations/prometheus_library/nginx.md) is also supported. + +[Read more about Kubernetes monitoring](../integrations/prometheus_library/kubernetes.md) + +### Auto DevOps + +Auto DevOps automatically detects, builds, tests, deploys, and monitors your +applications. + +To make full use of Auto DevOps(Auto Deploy, Auto Review Apps, and Auto Monitoring) +you will need the Kubernetes project integration enabled. + +[Read more about Auto DevOps](../../../topics/autodevops/index.md) + +NOTE: **Note** +Kubernetes clusters can be used without Auto DevOps. + +### Web terminals NOTE: **Note:** -From [GitLab 11.6](https://gitlab.com/gitlab-org/gitlab-ce/issues/34758) you -can also associate a Kubernetes cluster to your groups and from -[GitLab 11.11](https://gitlab.com/gitlab-org/gitlab-ce/issues/39840), -to the GitLab instance. Learn more about [group-level](../../group/clusters/index.md) -and [instance-level](../../instance/clusters/index.md) Kubernetes clusters. +Introduced in GitLab 8.15. You must be the project owner or have `maintainer` permissions +to use terminals. Support is limited to the first container in the +first pod of your environment. + +When enabled, the Kubernetes service adds [web terminal](../../../ci/environments.md#web-terminals) +support to your [environments](../../../ci/environments.md). This is based on the `exec` functionality found in +Docker and Kubernetes, so you get a new shell session within your existing +containers. To use this integration, you should deploy to Kubernetes using +the deployment variables above, ensuring any deployments, replica sets, and +pods are annotated with: + +- `app.gitlab.com/env: $CI_ENVIRONMENT_SLUG` +- `app.gitlab.com/app: $CI_PROJECT_PATH_SLUG` + +`$CI_ENVIRONMENT_SLUG` and `$CI_PROJECT_PATH_SLUG` are the values of +the CI variables. -## Adding and creating a new GKE cluster via GitLab +## Adding and removing clusters + +There are two options when adding a new cluster to your project: + +- Associate your account with Google Kubernetes Engine (GKE) to + [create new clusters](#add-new-gke-cluster) from within GitLab. +- Provide credentials to an + [existing Kubernetes cluster](#add-existing-kubernetes-cluster). + +### Add new GKE cluster TIP: **Tip:** Every new Google Cloud Platform (GCP) account receives [$300 in credit upon sign up](https://console.cloud.google.com/freetrial), @@ -39,7 +119,7 @@ The [Google authentication integration](../../../integration/google.md) must be enabled in GitLab at the instance level. If that's not the case, ask your GitLab administrator to enable it. On GitLab.com, this is enabled. -### Requirements +#### Requirements Before creating your first cluster on Google Kubernetes Engine with GitLab's integration, make sure the following requirements are met: @@ -49,7 +129,7 @@ integration, make sure the following requirements are met: - The Kubernetes Engine API and related service are enabled. It should work immediately but may take up to 10 minutes after you create a project. For more information see the ["Before you begin" section of the Kubernetes Engine docs](https://cloud.google.com/kubernetes-engine/docs/quickstart#before-you-begin). -### Creating the cluster +#### Creating the cluster If all of the above requirements are met, you can proceed to create and add a new Kubernetes cluster to your project: @@ -57,7 +137,7 @@ new Kubernetes cluster to your project: 1. Navigate to your project's **Operations > Kubernetes** page. NOTE: **Note:** - You need Maintainer [permissions] and above to access the Kubernetes page. + You need Maintainer [permissions](../../permissions.md) and above to access the Kubernetes page. 1. Click **Add Kubernetes cluster**. 1. Click **Create with Google Kubernetes Engine**. @@ -91,14 +171,14 @@ client certificate is enabled. NOTE: **Note:** Starting from [GitLab 12.1](https://gitlab.com/gitlab-org/gitlab-ce/issues/55902), all GKE clusters created by GitLab are RBAC enabled. Take a look at the [RBAC section](#rbac-cluster-resources) for more information. -## Adding an existing Kubernetes cluster +### Add existing Kubernetes cluster To add an existing Kubernetes cluster to your project: 1. Navigate to your project's **Operations > Kubernetes** page. NOTE: **Note:** - You need Maintainer [permissions] and above to access the Kubernetes page. + You need Maintainer [permissions](../../permissions.md) and above to access the Kubernetes page. 1. Click **Add Kubernetes cluster**. 1. Click **Add an existing Kubernetes cluster** and fill in the details: @@ -216,7 +296,36 @@ To add an existing Kubernetes cluster to your project: After a couple of minutes, your cluster will be ready to go. You can now proceed to install some [pre-defined applications](#installing-applications). -## Security implications +### Enabling or disabling integration + +After you have successfully added your cluster information, you can enable the +Kubernetes cluster integration: + +1. Click the **Enabled/Disabled** switch +1. Hit **Save** for the changes to take effect + +To disable the Kubernetes cluster integration, follow the same procedure. + +### Removing integration + +NOTE: **Note:** +You need Maintainer [permissions](../../permissions.md) and above to remove a Kubernetes cluster integration. + +NOTE: **Note:** +When you remove a cluster, you only remove its relation to GitLab, not the +cluster itself. To remove the cluster, you can do so by visiting the GKE +dashboard or using `kubectl`. + +To remove the Kubernetes cluster integration from your project, simply click the +**Remove integration** button. You will then be able to follow the procedure +and add a Kubernetes cluster again. + +## Cluster configuration + +This section covers important considerations for configuring Kubernetes +clusters with GitLab. + +### Security implications CAUTION: **Important:** The whole cluster security is based on a model where [developers](../../permissions.md) @@ -227,7 +336,7 @@ functionalities needed to successfully build and deploy a containerized application. Bear in mind that the same credentials are used for all the applications running on the cluster. -## GitLab-managed clusters +### GitLab-managed clusters > [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/22011) in GitLab 11.5. > Became [optional](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/26565) in GitLab 11.11. @@ -246,7 +355,7 @@ NOTE: **Note:** If you [install applications](#installing-applications) on your cluster, GitLab will create the resources required to run these even if you have chosen to manage your own cluster. -## Base domain +### Base domain > [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/24580) in GitLab 11.8. @@ -264,7 +373,7 @@ you can either: - Create an `A` record that points to the Ingress IP address with your domain provider. - Enter a wildcard DNS address using a service such as nip.io or xip.io. For example, `192.168.1.1.xip.io`. -## Access controls +### Access controls When creating a cluster in GitLab, you will be asked if you would like to create either: @@ -294,12 +403,12 @@ Helm will also create additional service accounts and other resources for each installed application. Consult the documentation of the Helm charts for each application for details. -If you are [adding an existing Kubernetes cluster](#adding-an-existing-kubernetes-cluster), +If you are [adding an existing Kubernetes cluster](#add-existing-kubernetes-cluster), ensure the token of the account has administrator privileges for the cluster. The resources created by GitLab differ depending on the type of cluster. -### ABAC cluster resources +#### ABAC cluster resources GitLab creates the following resources for ABAC clusters. @@ -312,7 +421,7 @@ GitLab creates the following resources for ABAC clusters. | Project namespace | `ServiceAccount` | Uses namespace of Project | Deploying to a cluster | | Project namespace | `Secret` | Token for project ServiceAccount | Deploying to a cluster | -### RBAC cluster resources +#### RBAC cluster resources GitLab creates the following resources for RBAC clusters. @@ -330,11 +439,12 @@ GitLab creates the following resources for RBAC clusters. NOTE: **Note:** Project-specific resources are only created if your cluster is [managed by GitLab](#gitlab-managed-clusters). -### Security of GitLab Runners +#### Security of GitLab Runners GitLab Runners have the [privileged mode](https://docs.gitlab.com/runner/executors/docker.html#the-privileged-mode) enabled by default, which allows them to execute special commands and running -Docker in Docker. This functionality is needed to run some of the [Auto DevOps] +Docker in Docker. This functionality is needed to run some of the +[Auto DevOps](../../../topics/autodevops/index.md) jobs. This implies the containers are running in privileged mode and you should, therefore, be aware of some important details. @@ -343,10 +453,81 @@ turn can do almost everything that the host can do. Be aware of the inherent security risk associated with performing `docker run` operations on arbitrary images as they effectively have root access. -If you don't want to use GitLab Runner in privileged mode, first make sure that -you don't have it installed via the applications, and then use the -[Runner's Helm chart](../../../install/kubernetes/gitlab_runner_chart.md) to -install it manually. +If you don't want to use GitLab Runner in privileged mode, either: + +- Use shared Runners on GitLab.com. They don't have this security issue. +- Set up your own Runners using configuration described at + [Shared Runners](../../gitlab_com/index.md#shared-runners). This involves: + 1. Making sure that you don't have it installed via + [the applications](#installing-applications). + 1. Installing a Runner + [using `docker+machine`](https://docs.gitlab.com/runner/executors/docker_machine.html). + +### Setting the environment scope **(PREMIUM)** + +When adding more than one Kubernetes cluster to your project, you need to differentiate +them with an environment scope. The environment scope associates clusters with [environments](../../../ci/environments.md) similar to how the +[environment-specific variables](../../../ci/variables/README.md#limiting-environment-scopes-of-environment-variables-premium) work. + +The default environment scope is `*`, which means all jobs, regardless of their +environment, will use that cluster. Each scope can only be used by a single +cluster in a project, and a validation error will occur if otherwise. +Also, jobs that don't have an environment keyword set will not be able to access any cluster. + +For example, let's say the following Kubernetes clusters exist in a project: + +| Cluster | Environment scope | +| ----------- | ----------------- | +| Development | `*` | +| Production | `production` | + +And the following environments are set in +[`.gitlab-ci.yml`](../../../ci/yaml/README.md): + +```yaml +stages: +- test +- deploy + +test: + stage: test + script: sh test + +deploy to staging: + stage: deploy + script: make deploy + environment: + name: staging + url: https://staging.example.com/ + +deploy to production: + stage: deploy + script: make deploy + environment: + name: production + url: https://example.com/ +``` + +The result will then be: + +- The Development cluster details will be available in the `deploy to staging` + job. +- The production cluster details will be available in the `deploy to production` + job. +- No cluster details will be available in the `test` job because it doesn't + define any environment. + +### Multiple Kubernetes clusters **(PREMIUM)** + +> Introduced in [GitLab Premium](https://about.gitlab.com/pricing/) 10.3. + +With GitLab Premium, you can associate more than one Kubernetes cluster to your +project. That way you can have different clusters for different environments, +like dev, staging, production, etc. + +Simply add another cluster, like you did the first time, and make sure to +[set an environment scope](#setting-the-environment-scope-premium) that will +differentiate the new cluster with the rest. ## Installing applications @@ -355,7 +536,7 @@ cluster. For more information on installing, upgrading, uninstalling, and troubleshooting applications for your project cluster, see [Gitlab Managed Apps](../../clusters/applications.md). -## Getting the external endpoint +### Getting the external endpoint NOTE: **Note:** With the following procedure, a load balancer must be installed in your cluster @@ -366,7 +547,7 @@ to obtain the endpoint. You can use either In order to publish your web application, you first need to find the endpoint which will be either an IP address or a hostname associated with your load balancer. -### Automatically determining the external endpoint +#### Automatically determining the external endpoint > [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/17052) in GitLab 10.6. @@ -381,7 +562,7 @@ and your cluster runs on Google Kubernetes Engine: If GitLab is still unable to determine the endpoint of your Ingress or Knative application, you can manually determine it by following the steps below. -### Manually determining the external endpoint +#### Manually determining the external endpoint If the cluster is on GKE, click the **Google Kubernetes Engine** link in the **Advanced settings**, or go directly to the @@ -420,7 +601,7 @@ Otherwise, you can list the IP addresses of all load balancers: kubectl get svc --all-namespaces -o jsonpath='{range.items[?(@.status.loadBalancer.ingress)]}{.status.loadBalancer.ingress[*].ip} ' ``` -### Using a static IP +#### Using a static IP By default, an ephemeral external IP address is associated to the cluster's load balancer. If you associate the ephemeral IP with your DNS and the IP changes, @@ -430,79 +611,19 @@ reserved IP. Read how to [promote an ephemeral external IP address in GKE](https://cloud.google.com/compute/docs/ip-addresses/reserve-static-external-ip-address#promote_ephemeral_ip). -### Pointing your DNS at the external endpoint +#### Pointing your DNS at the external endpoint Once you've set up the external endpoint, you should associate it with a [wildcard DNS record](https://en.wikipedia.org/wiki/Wildcard_DNS_record) such as `*.example.com.` in order to be able to reach your apps. If your external endpoint is an IP address, use an A record. If your external endpoint is a hostname, use a CNAME record. -## Multiple Kubernetes clusters **(PREMIUM)** - -> Introduced in [GitLab Premium][ee] 10.3. - -With GitLab Premium, you can associate more than one Kubernetes clusters to your -project. That way you can have different clusters for different environments, -like dev, staging, production, etc. - -Simply add another cluster, like you did the first time, and make sure to -[set an environment scope](#setting-the-environment-scope-premium) that will -differentiate the new cluster with the rest. - -## Setting the environment scope **(PREMIUM)** - -When adding more than one Kubernetes cluster to your project, you need to differentiate -them with an environment scope. The environment scope associates clusters with [environments](../../../ci/environments.md) similar to how the -[environment-specific variables](../../../ci/variables/README.md#limiting-environment-scopes-of-environment-variables-premium) work. - -The default environment scope is `*`, which means all jobs, regardless of their -environment, will use that cluster. Each scope can only be used by a single -cluster in a project, and a validation error will occur if otherwise. -Also, jobs that don't have an environment keyword set will not be able to access any cluster. - ---- - -For example, let's say the following Kubernetes clusters exist in a project: - -| Cluster | Environment scope | -| ----------- | ----------------- | -| Development | `*` | -| Staging | `staging` | -| Production | `production` | - -And the following environments are set in [`.gitlab-ci.yml`](../../../ci/yaml/README.md): - -```yaml -stages: -- test -- deploy - -test: - stage: test - script: sh test - -deploy to staging: - stage: deploy - script: make deploy - environment: - name: staging - url: https://staging.example.com/ - -deploy to production: - stage: deploy - script: make deploy - environment: - name: production - url: https://example.com/ -``` - -The result will then be: +## Deploying to a Kubernetes cluster -- The development cluster will be used for the "test" job. -- The staging cluster will be used for the "deploy to staging" job. -- The production cluster will be used for the "deploy to production" job. +A Kubernetes cluster can be the destination for a deployment job using special +[deployment variables](#deployment-variables). -## Deployment variables +### Deployment variables The Kubernetes cluster integration exposes the following [deployment variables](../../../ci/variables/README.md#deployment-environment-variables) in the @@ -522,7 +643,7 @@ NOTE: **NOTE:** Prior to GitLab 11.5, `KUBE_TOKEN` was the Kubernetes token of the main service account of the cluster integration. -### Troubleshooting failed deployment jobs +### Troubleshooting Before the deployment jobs starts, GitLab creates the following specifically for the deployment job: @@ -554,105 +675,8 @@ namespaces and service accounts yourself. ## Monitoring your Kubernetes cluster **(ULTIMATE)** -> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/4701) in [GitLab Ultimate][ee] 10.6. +> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/4701) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 10.6. When [Prometheus is deployed](#installing-applications), GitLab will automatically monitor the cluster's health. At the top of the cluster settings page, CPU and Memory utilization is displayed, along with the total amount available. Keeping an eye on cluster resources can be important, if the cluster runs out of memory pods may be shutdown or fail to start. ![Cluster Monitoring](img/k8s_cluster_monitoring.png) - -## Enabling or disabling the Kubernetes cluster integration - -After you have successfully added your cluster information, you can enable the -Kubernetes cluster integration: - -1. Click the **Enabled/Disabled** switch -1. Hit **Save** for the changes to take effect - -You can now start using your Kubernetes cluster for your deployments. - -To disable the Kubernetes cluster integration, follow the same procedure. - -## Removing the Kubernetes cluster integration - -NOTE: **Note:** -You need Maintainer [permissions] and above to remove a Kubernetes cluster integration. - -NOTE: **Note:** -When you remove a cluster, you only remove its relation to GitLab, not the -cluster itself. To remove the cluster, you can do so by visiting the GKE -dashboard or using `kubectl`. - -To remove the Kubernetes cluster integration from your project, simply click the -**Remove integration** button. You will then be able to follow the procedure -and add a Kubernetes cluster again. - -## What you can get with the Kubernetes integration - -Here's what you can do with GitLab if you enable the Kubernetes integration. - -### Deploy Boards **(PREMIUM)** - -GitLab's Deploy Boards offer a consolidated view of the current health and -status of each CI [environment](../../../ci/environments.md) running on Kubernetes, -displaying the status of the pods in the deployment. Developers and other -teammates can view the progress and status of a rollout, pod by pod, in the -workflow they already use without any need to access Kubernetes. - -[Read more about Deploy Boards](../deploy_boards.md) - -### Canary Deployments **(PREMIUM)** - -Leverage [Kubernetes' Canary deployments](https://kubernetes.io/docs/concepts/cluster-administration/manage-deployment/#canary-deployments) -and visualize your canary deployments right inside the Deploy Board, without -the need to leave GitLab. - -[Read more about Canary Deployments](../canary_deployments.md) - -### Pod logs **(ULTIMATE)** - -GitLab makes it easy to view the logs of running pods in connected Kubernetes clusters. By displaying the logs directly in GitLab, developers can avoid having to manage console tools or jump to a different interface. - -[Read more about Kubernetes pod logs](kubernetes_pod_logs.md) - -### Kubernetes monitoring - -Automatically detect and monitor Kubernetes metrics. Automatic monitoring of -[NGINX ingress](../integrations/prometheus_library/nginx.md) is also supported. - -[Read more about Kubernetes monitoring](../integrations/prometheus_library/kubernetes.md) - -### Auto DevOps - -Auto DevOps automatically detects, builds, tests, deploys, and monitors your -applications. - -To make full use of Auto DevOps(Auto Deploy, Auto Review Apps, and Auto Monitoring) -you will need the Kubernetes project integration enabled. - -[Read more about Auto DevOps](../../../topics/autodevops/index.md) - -### Web terminals - -NOTE: **Note:** -Introduced in GitLab 8.15. You must be the project owner or have `maintainer` permissions -to use terminals. Support is limited to the first container in the -first pod of your environment. - -When enabled, the Kubernetes service adds [web terminal](../../../ci/environments.md#web-terminals) -support to your [environments](../../../ci/environments.md). This is based on the `exec` functionality found in -Docker and Kubernetes, so you get a new shell session within your existing -containers. To use this integration, you should deploy to Kubernetes using -the deployment variables above, ensuring any pods you create are labelled with -`app=$CI_ENVIRONMENT_SLUG`. GitLab will do the rest! - -### Integrating Amazon EKS cluster with GitLab - -- Learn how to [connect and deploy to an Amazon EKS cluster](eks_and_gitlab/index.md). - -### Serverless - -- [Run serverless workloads on Kubernetes with Knative.](serverless/index.md) - -[permissions]: ../../permissions.md -[ee]: https://about.gitlab.com/pricing/ -[Auto DevOps]: ../../../topics/autodevops/index.md diff --git a/doc/user/project/clusters/kubernetes_pod_logs.md b/doc/user/project/clusters/kubernetes_pod_logs.md index 864cd75823c..163f3befeee 100644 --- a/doc/user/project/clusters/kubernetes_pod_logs.md +++ b/doc/user/project/clusters/kubernetes_pod_logs.md @@ -5,6 +5,10 @@ GitLab makes it easy to view the logs of running pods in [connected Kubernetes clusters](index.md). By displaying the logs directly in GitLab, developers can avoid having to manage console tools or jump to a different interface. +NOTE: **Kubernetes + GitLab** +Everything you need to build, test, deploy, and run your app at scale. +[Learn more](https://about.gitlab.com/solutions/kubernetes/). + ## Overview [Kubernetes](https://kubernetes.io) pod logs can be viewed directly within GitLab. Logs can be displayed by clicking on a specific pod from [Deploy Boards](../deploy_boards.md): diff --git a/doc/user/project/clusters/runbooks/index.md b/doc/user/project/clusters/runbooks/index.md index c021d059d30..8df27976662 100644 --- a/doc/user/project/clusters/runbooks/index.md +++ b/doc/user/project/clusters/runbooks/index.md @@ -35,7 +35,7 @@ for an overview of how this is accomplished in GitLab!** To create an executable runbook, you will need: 1. **Kubernetes** - A Kubernetes cluster is required to deploy the rest of the applications. - The simplest way to get started is to add a cluster using [GitLab's GKE integration](../index.md#adding-and-creating-a-new-gke-cluster-via-gitlab). + The simplest way to get started is to add a cluster using [GitLab's GKE integration](../index.md#add-new-gke-cluster). 1. **Helm Tiller** - Helm is a package manager for Kubernetes and is required to install all the other applications. It is installed in its own pod inside the cluster which can run the helm CLI in a safe environment. @@ -60,7 +60,7 @@ the components outlined above and the preloaded demo runbook. ### 1. Add a Kubernetes cluster -Follow the steps outlined in [Adding and creating a new GKE cluster via GitLab](../index.md#adding-and-creating-a-new-gke-cluster-via-gitlab) +Follow the steps outlined in [Add new GKE cluster](../index.md#add-new-gke-cluster) to add a Kubernetes cluster to your project. ### 2. Install Helm Tiller, Ingress, and JupyterHub diff --git a/doc/user/project/clusters/serverless/index.md b/doc/user/project/clusters/serverless/index.md index a32759c7bdc..92ad49e9448 100644 --- a/doc/user/project/clusters/serverless/index.md +++ b/doc/user/project/clusters/serverless/index.md @@ -28,7 +28,7 @@ To run Knative on Gitlab, you will need: - If you are planning on deploying a serverless application, clone the sample [Knative Ruby App](https://gitlab.com/knative-examples/knative-ruby-app) to get started. 1. **Kubernetes Cluster:** An RBAC-enabled Kubernetes cluster is required to deploy Knative. - The simplest way to get started is to add a cluster using [GitLab's GKE integration](../index.md#adding-and-creating-a-new-gke-cluster-via-gitlab). + The simplest way to get started is to add a cluster using [GitLab's GKE integration](../index.md#add-new-gke-cluster). The set of minimum recommended cluster specifications to run Knative is 3 nodes, 6 vCPUs, and 22.50 GB memory. 1. **Helm Tiller:** Helm is a package manager for Kubernetes and is required to install Knative. @@ -96,7 +96,8 @@ cluster which already has Knative installed. You must do the following: 1. Follow the steps to - [add an existing Kubernetes cluster](../index.md#adding-an-existing-kubernetes-cluster). + [add an existing Kubernetes + cluster](../index.md#add-existing-kubernetes-cluster). 1. Ensure GitLab can manage Knative: - For a non-GitLab managed cluster, ensure that the service account for the token diff --git a/doc/user/project/container_registry.md b/doc/user/project/container_registry.md index 9368c56004d..c9eb81b990c 100644 --- a/doc/user/project/container_registry.md +++ b/doc/user/project/container_registry.md @@ -1,13 +1,8 @@ # GitLab Container Registry -> **Notes:** -> > - [Introduced][ce-4040] in GitLab 8.8. > - Docker Registry manifest `v1` support was added in GitLab 8.9 to support Docker > versions earlier than 1.10. -> - This document is about the user guide. To learn how to enable GitLab Container -> Registry across your GitLab instance, visit the -> [administrator documentation](../../administration/container_registry.md). > - Starting from GitLab 8.12, if you have 2FA enabled in your account, you need > to pass a [personal access token][pat] instead of your password in order to > login to GitLab's Container Registry. @@ -16,28 +11,33 @@ With the Docker Container Registry integrated into GitLab, every project can have its own space to store its Docker images. +This document is the user guide. To learn how to enable GitLab Container +Registry across your GitLab instance, visit the +[administrator documentation](../../administration/container_registry.md). + You can read more about Docker Registry at <https://docs.docker.com/registry/introduction/>. ## Enable the Container Registry for your project -NOTE: **Note:** -If you cannot find the Container Registry entry under your project's settings, -that means that it is not enabled in your GitLab instance. Ask your administrator -to enable it. - -1. First, ask your system administrator to enable GitLab Container Registry - following the [administration documentation](../../administration/container_registry.md). - If you are using GitLab.com, this is enabled by default so you can start using - the Registry immediately. Currently there is a soft (10GB) size restriction for - registry on GitLab.com, as part of the [repository size limit](repository/index.md). -1. Go to your [project's General settings](settings/index.md#sharing-and-permissions) +If you cannot find the **Packages > Container Registry** entry under your +project's sidebar, it is not enabled in your GitLab instance. Ask your +administrator to enable GitLab Container Registry following the +[administration documentation](../../administration/container_registry.md). + +If you are using GitLab.com, this is enabled by default so you can start using +the Registry immediately. Currently there is a soft (10GB) size restriction for +registry on GitLab.com, as part of the [repository size limit](repository/index.md). + +Once enabled for your GitLab instance, to enable Container Registry for your +project: + +1. Go to your project's **Settings > General** page. +1. Expand the **Visibility, project features, permissions** section and enable the **Container Registry** feature on your project. For new projects this might be enabled by default. For existing projects (prior GitLab 8.8), you will have to explicitly enable it. -1. Hit **Save changes** for the changes to take effect. You should now be able - to see the **Registry** link in the sidebar. - -![Container Registry](img/container_registry.png) +1. Press **Save changes** for the changes to take effect. You should now be able + to see the **Packages > Container Registry** link in the sidebar. ## Build and push images @@ -49,14 +49,14 @@ to enable it. > - To move or rename a repository with a container registry you will have to > delete all existing images. -If you visit the **Registry** link under your project's menu, you can see the -explicit instructions to login to the Container Registry using your GitLab -credentials. +If you visit the **Packages > Container Registry** link under your project's +menu, you can see the explicit instructions to login to the Container Registry +using your GitLab credentials. For example if the Registry's URL is `registry.example.com`, then you should be able to login with: -``` +```sh docker login registry.example.com ``` @@ -64,14 +64,14 @@ Building and publishing images should be a straightforward process. Just make sure that you are using the Registry URL with the namespace and project name that is hosted on GitLab: -``` +```sh docker build -t registry.example.com/group/project/image . docker push registry.example.com/group/project/image ``` Your image will be named after the following scheme: -``` +```text <registry URL>/<namespace>/<project>/<image> ``` @@ -79,7 +79,7 @@ GitLab supports up to three levels of image repository names. Following examples of image tags are valid: -``` +```text registry.example.com/group/project:some-tag registry.example.com/group/project/image:latest registry.example.com/group/project/my/image:rc1 @@ -90,7 +90,7 @@ registry.example.com/group/project/my/image:rc1 To download and run a container from images hosted in GitLab Container Registry, use `docker run`: -``` +```sh docker run [options] registry.example.com/group/project/image [arguments] ``` @@ -100,7 +100,7 @@ For more information on running Docker containers, visit the ## Control Container Registry from within GitLab GitLab offers a simple Container Registry management panel. Go to your project -and click **Registry** in the project menu. +and click **Packages > Container Registry** in the project menu. This view will show you all tags in your project and will easily allow you to delete them. @@ -173,9 +173,9 @@ curl localhost:5001/debug/vars A Docker connection error can occur when there are special characters in either the group, project or branch name. Special characters can include: -* Leading underscore -* Trailing hyphen/dash -* Double hyphen/dash +- Leading underscore +- Trailing hyphen/dash +- Double hyphen/dash To get around this, you can [change the group path](../group/index.md#changing-a-groups-path), [change the project path](../project/settings/index.md#renaming-a-repository) or chanage the branch @@ -183,7 +183,8 @@ name. ### Advanced Troubleshooting ->**NOTE:** The following section is only recommended for experts. +NOTE: **Note:** +The following section is only recommended for experts. Sometimes it's not obvious what is wrong, and you may need to dive deeper into the communication between the Docker client and the Registry to find out @@ -195,7 +196,7 @@ diagnose a problem with the S3 setup. A user attempted to enable an S3-backed Registry. The `docker login` step went fine. However, when pushing an image, the output showed: -``` +```text The push refers to a repository [s3-testing.myregistry.com:4567/root/docker-test/docker-image] dc5e59c14160: Pushing [==================================================>] 14.85 kB 03c20c1a019a: Pushing [==================================================>] 2.048 kB @@ -218,7 +219,7 @@ at the communication between the client and the Registry. The REST API between the Docker client and Registry is [described here](https://docs.docker.com/registry/spec/api/). Normally, one would just use Wireshark or tcpdump to capture the traffic and see where things went -wrong. However, since all communications between Docker clients and servers +wrong. However, since all communications between Docker clients and servers are done over HTTPS, it's a bit difficult to decrypt the traffic quickly even if you know the private key. What can we do instead? diff --git a/doc/user/project/img/container_registry.png b/doc/user/project/img/container_registry.png Binary files differdeleted file mode 100644 index abbaf838538..00000000000 --- a/doc/user/project/img/container_registry.png +++ /dev/null diff --git a/doc/user/project/integrations/prometheus.md b/doc/user/project/integrations/prometheus.md index 61c30e0b0ef..e609fe43507 100644 --- a/doc/user/project/integrations/prometheus.md +++ b/doc/user/project/integrations/prometheus.md @@ -323,8 +323,11 @@ Once enabled, an issue will be opened automatically when an alert is triggered w - `starts_at`: Alert start time via `startsAt` - `full_query`: Alert query extracted from `generatorURL` - Optional list of attached annotations extracted from `annotations/*` +- Alert [GFM](../../markdown.md): GitLab Flavored Markdown from `annotations/gitlab_incident_markdown` -To further customize the issue, you can add labels, mentions, or any other supported [quick action](../quick_actions.md) in the selected issue template. +To further customize the issue, you can add labels, mentions, or any other supported [quick action](../quick_actions.md) in the selected issue template, which will apply to all incidents. To limit quick actions or other information to only specific types of alerts, use the `annotations/gitlab_incident_markdown` field. + +Since [version 12.2](https://gitlab.com/gitlab-org/gitlab-ce/issues/63373), GitLab will tag each incident issue with the `incident` label automatically. If the label does not yet exist, it will be created automatically as well. If the metric exceeds the threshold of the alert for over 5 minutes, an email will be sent to all [Maintainers and Owners](../../permissions.md#project-members-permissions) of the project. diff --git a/doc/user/project/integrations/prometheus_library/haproxy.md b/doc/user/project/integrations/prometheus_library/haproxy.md index 6be8fc82431..90a725f271b 100644 --- a/doc/user/project/integrations/prometheus_library/haproxy.md +++ b/doc/user/project/integrations/prometheus_library/haproxy.md @@ -1,4 +1,5 @@ # Monitoring HAProxy + > [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/12621) in GitLab 9.4 GitLab has support for automatically detecting and monitoring HAProxy. This is provided by leveraging the [HAProxy Exporter](https://github.com/prometheus/haproxy_exporter), which translates HAProxy statistics into a Prometheus readable form. diff --git a/doc/user/project/issues/design_management.md b/doc/user/project/issues/design_management.md new file mode 100644 index 00000000000..2327fa84998 --- /dev/null +++ b/doc/user/project/issues/design_management.md @@ -0,0 +1,58 @@ +# Design Management **(PREMIUM)** + +> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/660) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.2. + +CAUTION: **Warning:** +This an __alpha__ feature and is subject to change at any time without +prior notice. + +## Overview + +Design Management allows you to upload design assets (wireframes, mockups, etc.) +to GitLab issues and keep them stored in one single place, accessed by the Design +Management's page within an issue, giving product designers, product managers, and engineers a +way to collaborate on designs over one single source of truth. + +You can easily share mock-ups of designs with your team, or visual regressions can be easily +viewed and addressed. + +<i class="fa fa-youtube-play youtube" aria-hidden="true"></i> +For an overview, see the video [Design Management (GitLab 12.2)](https://www.youtube.com/watch?v=CCMtCqdK_aM). + +## Requirements + +Design Management requires +[Large File Storage (LFS)](../../../workflow/lfs/manage_large_binaries_with_git_lfs.md) +to be enabled: + +- For GitLab.com, LFS is already enabled. +- For self-managed instances, a GitLab administrator must have + [enabled LFS globally](../../../workflow/lfs/lfs_administration.md). +- For both GitLab.com and self-managed instances: LFS must be enabled for the project itself. + If enabled globally, LFS will be enabled by default to all projects. To enable LFS on the + project level, navigate to your project's **Settings > General**, expand **Visibility, project features, permissions** + and enable **Git Large File Storage**. + +## Limitations + +- Files uploaded must have a file extension of either `png`, `jpg`, `jpeg`, `gif`, `bmp`, `tiff` or `ico`. The [`svg` extension is not yet supported](https://gitlab.com/gitlab-org/gitlab-ee/issues/12771). +- [Designs cannot yet be deleted](https://gitlab.com/gitlab-org/gitlab-ee/issues/11089). +- Design Management is [not yet supported in the project export](https://gitlab.com/gitlab-org/gitlab-ee/issues/11090). + +## The Design Management page + +Navigate to the **Design Management** page from any issue by clicking the **Designs** tab: + +![Designs tab](img/design_management_v12_2.png) + +## Adding designs + +To upload design images, click the **Upload Designs** button and select images to upload. + +Designs with the same filename as an existing uploaded design will create a new version +of the design, and will replace the previous version. + +## Viewing designs + +Images on the Design Management page can be enlarged by clicking on them. + diff --git a/doc/user/project/issues/img/design_management_v12_2.png b/doc/user/project/issues/img/design_management_v12_2.png Binary files differnew file mode 100644 index 00000000000..6da747a3f21 --- /dev/null +++ b/doc/user/project/issues/img/design_management_v12_2.png diff --git a/doc/user/project/issues/index.md b/doc/user/project/issues/index.md index 6706e1c2e2b..bf04ed2d2d0 100644 --- a/doc/user/project/issues/index.md +++ b/doc/user/project/issues/index.md @@ -120,6 +120,12 @@ associated label or assignee will change to match that of the new column. The en board can also be filtered to only include issues from a certain milestone or an overarching label. +### Design Management **(PREMIUM)** + +With [Design Management](design_management.md), you can upload design +assets to issues and view them all together to easily share and +collaborate with your team. + ### Epics **(ULTIMATE)** [Epics](../../group/epics/index.md) let you manage your portfolio of projects more diff --git a/doc/user/project/issues/sorting_issue_lists.md b/doc/user/project/issues/sorting_issue_lists.md index ba120783430..0fe86e6f410 100644 --- a/doc/user/project/issues/sorting_issue_lists.md +++ b/doc/user/project/issues/sorting_issue_lists.md @@ -9,7 +9,7 @@ similar to [issue boards](../issue_board.md#issue-ordering-in-a-list). ## Manual sorting -> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/62178) in GitLab 12.1. +> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/62178) in GitLab 12.2. When you select **Manual** sorting, you can change the order by dragging and dropping the issues. The changed order will persist. Everyone who visits the same list will see the reordered list, with some exceptions. diff --git a/doc/user/project/merge_requests/code_quality.md b/doc/user/project/merge_requests/code_quality.md index ad1d79ae5b1..eb6e454062a 100644 --- a/doc/user/project/merge_requests/code_quality.md +++ b/doc/user/project/merge_requests/code_quality.md @@ -9,8 +9,18 @@ in [GitLab Starter](https://about.gitlab.com/pricing/) 9.3. With the help of [GitLab CI/CD](../../../ci/README.md), you can analyze your source code quality using GitLab Code Quality. -Code Quality uses [Code Climate Engines](https://codeclimate.com), which are -free and open source. Code Quality doesn't require a Code Climate subscription. + +Code Quality: + +- Uses [Code Climate Engines](https://codeclimate.com), which are + free and open source. Code Quality doesn't require a Code Climate + subscription. +- Runs in [pipelines](../../../ci/pipelines.md) using an Docker image built in + [GitLab Code + Quality](https://gitlab.com/gitlab-org/security-products/codequality) project. +- Can make use of a [template](#template-and-examples). +- Is available with [Auto + DevOps](../../../topics/autodevops/index.md#auto-code-quality-starter). Going a step further, GitLab can show the Code Quality report right in the merge request widget area: @@ -21,22 +31,48 @@ in the merge request widget area: For instance, consider the following workflow: -1. Your backend team member starts a new implementation for making a certain feature in your app faster -1. With Code Quality reports, they analyze how their implementation is impacting the code quality -1. The metrics show that their code degrade the quality in 10 points -1. You ask a co-worker to help them with this modification -1. They both work on the changes until Code Quality report displays no degradations, only improvements -1. You approve the merge request and authorize its deployment to staging -1. Once verified, their changes are deployed to production +1. Your backend team member starts a new implementation for making a certain + feature in your app faster. +1. With Code Quality reports, they analyze how their implementation is impacting + the code quality. +1. The metrics show that their code degrade the quality in 10 points. +1. You ask a co-worker to help them with this modification. +1. They both work on the changes until Code Quality report displays no + degradations, only improvements. +1. You approve the merge request and authorize its deployment to staging. +1. Once verified, their changes are deployed to production. + +## Template and examples + +For most GitLab instances, the supplied template is the preferred method of +implementing Code Quality. See +[Analyze your project's Code Quality](../../../ci/examples/code_quality.md) for: + +- Information on the builtin GitLab Code Quality template. +- Examples of manual GitLab configuration for earlier GitLab versions. -## How it works +## Configuring jobs using variables -First of all, you need to define a job in your `.gitlab-ci.yml` file that generates the -[Code Quality report artifact](../../../ci/yaml/README.md#artifactsreportscodequality-starter). +The Code Quality job supports environment variables that users can set to +configure job execution at runtime. -The Code Quality report artifact is a subset of the -[Code Climate spec](https://github.com/codeclimate/spec/blob/master/SPEC.md#data-types). -It must be a JSON file containing an array of objects with the following properties: +For a list of available environment variables, see +[Environment variables](https://gitlab.com/gitlab-org/security-products/codequality/blob/master/README.md#environment-variables). + +## Implementing a custom tool + +It's possible to have a custom tool provide Code Quality reports in GitLab. To +do this: + +1. Define a job in your `.gitlab-ci.yml` file that generates the + [Code Quality report + artifact](../../../ci/yaml/README.md#artifactsreportscodequality-starter). +1. Configure your tool to generate the Code Quality report artifact as a JSON + file that implements subset of the [Code Climate + spec](https://github.com/codeclimate/spec/blob/master/SPEC.md#data-types). + +The Code Quality report artifact JSON file must contain an array of objects +with the following properties: | Name | Description | | ---------------------- | -------------------------------------------------------------------------------------- | @@ -63,13 +99,16 @@ Example: ``` NOTE: **Note:** -Although the Code Climate spec supports more properties, those are ignored by GitLab. +Although the Code Climate spec supports more properties, those are ignored by +GitLab. + +## Code Quality reports -For more information on what the Code Quality job should look like, check the -example on [analyzing a project's code quality](../../../ci/examples/code_quality.md). +Once the Code Quality job has completed, GitLab: -GitLab then checks this report, compares the metrics between the source and target -branches, and shows the information right on the merge request. +- Checks the generated report. +- Compares the metrics between the source and target branches. +- Shows the information right on the merge request. If multiple jobs in a pipeline generate a code quality artifact, only the artifact from the last created job (the job with the largest job ID) is used. To avoid confusion, diff --git a/doc/user/project/merge_requests/index.md b/doc/user/project/merge_requests/index.md index d5ca853eff5..f78ec9d96e6 100644 --- a/doc/user/project/merge_requests/index.md +++ b/doc/user/project/merge_requests/index.md @@ -343,6 +343,30 @@ git push -o merge_request.remove_source_branch You can also use this push option in addition to the `merge_request.create` push option. +### Set merge request title using git push options + +To set the title of an existing merge request, use +the `merge_request.title` push option: + +```sh +git push -o merge_request.title="The title I want" +``` + +You can also use this push option in addition to the +`merge_request.create` push option. + +### Set merge request description using git push options + +To set the description of an existing merge request, use +the `merge_request.description` push option: + +```sh +git push -o merge_request.description="The description I want" +``` + +You can also use this push option in addition to the +`merge_request.create` push option. + ## Find the merge request that introduced a change > [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/2383) in GitLab 10.5. diff --git a/doc/user/project/milestones/burndown_charts.md b/doc/user/project/milestones/burndown_charts.md index 84e08b4eeb8..d4dd9c7d4c3 100644 --- a/doc/user/project/milestones/burndown_charts.md +++ b/doc/user/project/milestones/burndown_charts.md @@ -1,6 +1,9 @@ +--- +type: reference +--- + # Burndown Charts **(STARTER)** -> **Notes:** > - [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/1540) in [GitLab Starter](https://about.gitlab.com/pricing/) 9.1 for project milestones. > - [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/5354) in [GitLab Premium](https://about.gitlab.com/pricing/) 10.8 for group milestones. > - [Added](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/6495) to [GitLab Starter](https://about.gitlab.com/pricing/) 11.2 for group milestones. @@ -20,7 +23,8 @@ yourself to have the same sense of progress. GitLab Starter plots it for you and presents it in a clear and beautiful chart. -For an overview, check the video demonstration on [Mapping Work Versus Time, With Burndown Charts](https://about.gitlab.com/2017/04/25/mapping-work-to-do-versus-time-with-burndown-charts/). +<i class="fa fa-youtube-play youtube" aria-hidden="true"></i> +For an overview, check the video demonstration on [Mapping work versus time with Burndown Charts](https://www.youtube.com/watch?v=zJU2MuRChzs). ## Use cases @@ -68,3 +72,15 @@ The Burndown Chart can also be toggled to display the cumulative open issue weight for a given day. When using this feature, make sure issue weights have been properly assigned, since an open issue with no weight adds zero to the cumulative value. + +<!-- ## Troubleshooting + +Include any troubleshooting steps that you can foresee. If you know beforehand what issues +one might have when setting this up, or when something is changed, or on upgrading, it's +important to describe those, too. Think of things that may go wrong and include them here. +This is important to minimize requests for support, and to avoid doc comments with +questions that you know someone might ask. + +Each scenario can be a third-level heading, e.g. `### Getting error message X`. +If you have none to add when creating a doc, leave this section in place +but commented out to help encourage others to add to it in the future. --> diff --git a/doc/user/project/milestones/index.md b/doc/user/project/milestones/index.md index 142462e1879..453983fa882 100644 --- a/doc/user/project/milestones/index.md +++ b/doc/user/project/milestones/index.md @@ -1,3 +1,7 @@ +--- +type: index, reference +--- + # Milestones ## Overview @@ -145,3 +149,15 @@ The milestone sidebar on the milestone view shows the following: For project milestones only, the milestone sidebar shows the total issue weight of all issues that have the milestone assigned. ![Project milestone page](img/milestones_project_milestone_page.png) + +<!-- ## Troubleshooting + +Include any troubleshooting steps that you can foresee. If you know beforehand what issues +one might have when setting this up, or when something is changed, or on upgrading, it's +important to describe those, too. Think of things that may go wrong and include them here. +This is important to minimize requests for support, and to avoid doc comments with +questions that you know someone might ask. + +Each scenario can be a third-level heading, e.g. `### Getting error message X`. +If you have none to add when creating a doc, leave this section in place +but commented out to help encourage others to add to it in the future. --> diff --git a/doc/user/project/new_ci_build_permissions_model.md b/doc/user/project/new_ci_build_permissions_model.md index 494dd539da7..03ae24242e3 100644 --- a/doc/user/project/new_ci_build_permissions_model.md +++ b/doc/user/project/new_ci_build_permissions_model.md @@ -90,8 +90,7 @@ to steal the tokens of other jobs. Since 9.0 [pipeline triggers][triggers] do support the new permission model. The new triggers do impersonate their associated user including their access -to projects and their project permissions. To migrate trigger to use new permission -model use **Take ownership**. +to projects and their project permissions. ## Before GitLab 8.12 diff --git a/doc/user/project/pipelines/job_artifacts.md b/doc/user/project/pipelines/job_artifacts.md index 2411744c874..ef90899c512 100644 --- a/doc/user/project/pipelines/job_artifacts.md +++ b/doc/user/project/pipelines/job_artifacts.md @@ -1,24 +1,24 @@ +--- +type: reference, howto +--- + # Introduction to job artifacts -> **Notes:** -> -> - Since GitLab 8.2 and GitLab Runner 0.7.0, job artifacts that are created by -> GitLab Runner are uploaded to GitLab and are downloadable as a single archive -> (`tar.gz`) using the GitLab UI. -> - Starting with GitLab 8.4 and GitLab Runner 1.0, the artifacts archive format -> changed to `ZIP`, and it is now possible to browse its contents, with the added -> ability of downloading the files separately. -> - Starting with GitLab 8.17, builds are renamed to jobs. -> - The artifacts browser will be available only for new artifacts that are sent -> to GitLab using GitLab Runner version 1.0 and up. It will not be possible to -> browse old artifacts already uploaded to GitLab. ->- This is the user documentation. For the administration guide see -> [administration/job_artifacts](../../../administration/job_artifacts.md). - -Artifacts is a list of files and directories which are attached to a job -after it finishes. This feature is enabled by default in all +> - Introduced in GitLab 8.2 and GitLab Runner 0.7.0. +> - Starting with GitLab 8.4 and GitLab Runner 1.0, the artifacts archive format changed to `ZIP`, and it is now possible to browse its contents, with the added ability of downloading the files separately. +> - In GitLab 8.17, builds were renamed to jobs. +> - The artifacts browser will be available only for new artifacts that are sent to GitLab using GitLab Runner version 1.0 and up. It will not be possible to browse old artifacts already uploaded to GitLab. + +Artifacts are a list of files and directories which created by a job +once it finishes. This feature is [enabled by default](../../../administration/job_artifacts.md) in all GitLab installations. +Job artifacts that are created by GitLab Runner are uploaded to GitLab and are downloadable as a single archive using the GitLab UI. + +<i class="fa fa-youtube-play youtube" aria-hidden="true"></i> +For an overview, watch the video [GitLab CI Pipeline, Artifacts, and Environments](https://www.youtube.com/watch?v=PCKDICEe10s). +Watch also [GitLab CI pipeline tutorial for beginners](https://www.youtube.com/watch?v=Jav4vbUrqII). + ## Defining artifacts in `.gitlab-ci.yml` A simple example of using the artifacts definition in `.gitlab-ci.yml` would be @@ -50,11 +50,8 @@ For more examples on artifacts, follow the [artifacts reference in ## Browsing artifacts -> **Note:** > With GitLab 9.2, PDFs, images, videos and other formats can be previewed > directly in the job artifacts browser without the need to download them. -> -> **Note:** > With [GitLab 10.1][ce-14399], HTML files in a public project can be previewed > directly in a new tab without the need to download them when > [GitLab Pages](../../../administration/pages/index.md) is enabled. @@ -108,7 +105,7 @@ inside GitLab that make that possible. It is possible to download the latest artifacts of a job via a well known URL so you can use it for scripting purposes. ->**Note:** +NOTE: **Note:** The latest artifacts are considered as the artifacts created by jobs in the latest pipeline that succeeded for the specific ref. Artifacts for other pipelines can be accessed with direct access to them. @@ -169,9 +166,9 @@ https://gitlab.com/gitlab-org/gitlab-ce/-/jobs/artifacts/master/file/htmlcov/ind The latest builds are also exposed in the UI in various places. Specifically, look for the download button in: -- the main project's page -- the branches page -- the tags page +- The main project's page +- The branches page +- The tags page If the latest job has failed to upload the artifacts, you can see that information in the UI. @@ -201,3 +198,15 @@ In order to retrieve a job artifact of a different project, you might need to us [expiry date]: ../../../ci/yaml/README.md#artifactsexpire_in [ce-14399]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/14399 + +<!-- ## Troubleshooting + +Include any troubleshooting steps that you can foresee. If you know beforehand what issues +one might have when setting this up, or when something is changed, or on upgrading, it's +important to describe those, too. Think of things that may go wrong and include them here. +This is important to minimize requests for support, and to avoid doc comments with +questions that you know someone might ask. + +Each scenario can be a third-level heading, e.g. `### Getting error message X`. +If you have none to add when creating a doc, leave this section in place +but commented out to help encourage others to add to it in the future. --> diff --git a/doc/user/project/pipelines/schedules.md b/doc/user/project/pipelines/schedules.md index dd5427ab35a..4e25d8545e9 100644 --- a/doc/user/project/pipelines/schedules.md +++ b/doc/user/project/pipelines/schedules.md @@ -1,7 +1,9 @@ +--- +type: reference, howto +--- + # Pipeline schedules -> **Notes**: -> > - Introduced in GitLab 9.1 as [Trigger Schedule](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/10533). > - [Renamed to Pipeline Schedule](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/10853) in GitLab 9.2. > - Cron notation is parsed by [Fugit](https://github.com/floraison/fugit). @@ -118,3 +120,15 @@ on the target branch, the schedule will stop creating new pipelines. This can happen if, for example, the owner is blocked or removed from the project, or the target branch or tag is protected. In this case, someone with sufficient privileges must take ownership of the schedule. + +<!-- ## Troubleshooting + +Include any troubleshooting steps that you can foresee. If you know beforehand what issues +one might have when setting this up, or when something is changed, or on upgrading, it's +important to describe those, too. Think of things that may go wrong and include them here. +This is important to minimize requests for support, and to avoid doc comments with +questions that you know someone might ask. + +Each scenario can be a third-level heading, e.g. `### Getting error message X`. +If you have none to add when creating a doc, leave this section in place +but commented out to help encourage others to add to it in the future. --> diff --git a/doc/user/project/pipelines/settings.md b/doc/user/project/pipelines/settings.md index df82daa3da3..45f27b3c811 100644 --- a/doc/user/project/pipelines/settings.md +++ b/doc/user/project/pipelines/settings.md @@ -1,3 +1,7 @@ +--- +type: reference, howto +--- + # Pipelines settings To reach the pipelines settings navigate to your project's @@ -5,6 +9,10 @@ To reach the pipelines settings navigate to your project's The following settings can be configured per project. +<i class="fa fa-youtube-play youtube" aria-hidden="true"></i> +For an overview, watch the video [GitLab CI Pipeline, Artifacts, and Environments](https://www.youtube.com/watch?v=PCKDICEe10s). +Watch also [GitLab CI pipeline tutorial for beginners](https://www.youtube.com/watch?v=Jav4vbUrqII). + ## Git strategy With Git strategy, you can choose the default way your repository is fetched @@ -216,3 +224,15 @@ https://example.gitlab.com/<namespace>/<project>/badges/<branch>/coverage.svg?st ## Environment Variables [Environment variables](../../../ci/variables/README.html#gitlab-cicd-environment-variables) can be set in an environment to be available to a runner. + +<!-- ## Troubleshooting + +Include any troubleshooting steps that you can foresee. If you know beforehand what issues +one might have when setting this up, or when something is changed, or on upgrading, it's +important to describe those, too. Think of things that may go wrong and include them here. +This is important to minimize requests for support, and to avoid doc comments with +questions that you know someone might ask. + +Each scenario can be a third-level heading, e.g. `### Getting error message X`. +If you have none to add when creating a doc, leave this section in place +but commented out to help encourage others to add to it in the future. --> diff --git a/doc/user/project/protected_branches.md b/doc/user/project/protected_branches.md index 20a03dff2da..e3515711f17 100644 --- a/doc/user/project/protected_branches.md +++ b/doc/user/project/protected_branches.md @@ -1,3 +1,7 @@ +--- +type: reference, howto +--- + # Protected Branches [Permissions](../permissions.md) in GitLab are fundamentally defined around the @@ -9,13 +13,13 @@ created protected branches. By default, a protected branch does four simple things: -- it prevents its creation, if not already created, from everybody except users - with Maintainer permission -- it prevents pushes from everybody except users with Maintainer permission -- it prevents **anyone** from force pushing to the branch -- it prevents **anyone** from deleting the branch +- It prevents its creation, if not already created, from everybody except users + with Maintainer permission. +- It prevents pushes from everybody except users with Maintainer permission. +- It prevents **anyone** from force pushing to the branch. +- It prevents **anyone** from deleting the branch. ->**Note**: +NOTE: **Note:** A GitLab admin is allowed to push to the protected branches. See the [Changelog](#changelog) section for changes over time. @@ -68,7 +72,7 @@ they are set to "Maintainers" by default. ## Restricting push and merge access to certain users **(STARTER)** -> This feature was [introduced][ce-5081] in [GitLab Starter][ee] 8.11. +> [Introduced][ce-5081] in [GitLab Starter][ee] 8.11. With GitLab Enterprise Edition you can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users. From the @@ -174,12 +178,21 @@ for details about the pipelines security model. - Allow developers to merge into a protected branch without having push access [gitlab-org/gitlab-ce!4892][ce-4892] - Allow specifying protected branches using wildcards [gitlab-org/gitlab-ce!4665][ce-4665] ---- - [ce-4665]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/4665 "Allow specifying protected branches using wildcards" [ce-4892]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/4892 "Allow developers to merge into a protected branch without having push access" [ce-5081]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/5081 "Allow creating protected branches that can't be pushed to" [ce-21393]: https://gitlab.com/gitlab-org/gitlab-ce/issues/21393 -[ee-restrict]: https://docs.gitlab.com/ee/user/project/protected_branches.html#restricting-push-and-merge-access-to-certain-users [perm]: ../permissions.md [ee]: https://about.gitlab.com/pricing/ + +<!-- ## Troubleshooting + +Include any troubleshooting steps that you can foresee. If you know beforehand what issues +one might have when setting this up, or when something is changed, or on upgrading, it's +important to describe those, too. Think of things that may go wrong and include them here. +This is important to minimize requests for support, and to avoid doc comments with +questions that you know someone might ask. + +Each scenario can be a third-level heading, e.g. `### Getting error message X`. +If you have none to add when creating a doc, leave this section in place +but commented out to help encourage others to add to it in the future. --> diff --git a/doc/user/project/protected_tags.md b/doc/user/project/protected_tags.md index 26bec323f02..687c4e1ea6f 100644 --- a/doc/user/project/protected_tags.md +++ b/doc/user/project/protected_tags.md @@ -1,3 +1,7 @@ +--- +type: reference, howto +--- + # Protected Tags > [Introduced][ce-10356] in GitLab 9.1. @@ -14,19 +18,19 @@ Protected tags will prevent anyone from updating or deleting the tag, as and wil To protect a tag, you need to have at least Maintainer permission level. -1. Navigate to the project's Settings -> Repository page +1. Navigate to the project's **Settings > Repository**: ![Repository Settings](img/project_repository_settings.png) -1. From the **Tag** dropdown menu, select the tag you want to protect or type and click `Create wildcard`. In the screenshot below, we chose to protect all tags matching `v*`. +1. From the **Tag** dropdown menu, select the tag you want to protect or type and click **Create wildcard**. In the screenshot below, we chose to protect all tags matching `v*`: ![Protected tags page](img/protected_tags_page.png) -1. From the `Allowed to create` dropdown, select who will have permission to create matching tags and then click `Protect`. +1. From the **Allowed to create** dropdown, select who will have permission to create matching tags and then click **Protect**: ![Allowed to create tags dropdown](img/protected_tags_permissions_dropdown.png) -1. Once done, the protected tag will appear in the "Protected tags" list. +1. Once done, the protected tag will appear in the **Protected tags** list: ![Protected tags list](img/protected_tags_list.png) @@ -45,13 +49,23 @@ matching the wildcard. For example: Two different wildcards can potentially match the same tag. For example, `*-stable` and `production-*` would both match a `production-stable` tag. In that case, if _any_ of these protected tags have a setting like -"Allowed to create", then `production-stable` will also inherit this setting. +**Allowed to create**, then `production-stable` will also inherit this setting. If you click on a protected tag's name, you will be presented with a list of all matching tags: ![Protected tag matches](img/protected_tag_matches.png) ---- +<!-- ## Troubleshooting + +Include any troubleshooting steps that you can foresee. If you know beforehand what issues +one might have when setting this up, or when something is changed, or on upgrading, it's +important to describe those, too. Think of things that may go wrong and include them here. +This is important to minimize requests for support, and to avoid doc comments with +questions that you know someone might ask. + +Each scenario can be a third-level heading, e.g. `### Getting error message X`. +If you have none to add when creating a doc, leave this section in place +but commented out to help encourage others to add to it in the future. --> [ce-10356]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/10356 "Protected Tags" diff --git a/doc/user/project/quick_actions.md b/doc/user/project/quick_actions.md index f81669a41c9..b8e0ef8d12f 100644 --- a/doc/user/project/quick_actions.md +++ b/doc/user/project/quick_actions.md @@ -1,13 +1,18 @@ -# GitLab quick actions +--- +type: reference +--- + +# GitLab Quick Actions Quick actions are textual shortcuts for common actions on issues, epics, merge requests, and commits that are usually done by clicking buttons or dropdowns in GitLab's UI. You can enter these commands while creating a new issue or merge request, or in comments of issues, epics, merge requests, and commits. Each command should be on a separate line in order to be properly detected and executed. Once executed, -the commands are removed from the text body and not visible to anyone else. -## Quick actions for issues and merge requests +> From [GitLab 12.1](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/26672), an alert is displayed when a quick action is successfully applied. + +## Quick Actions for issues and merge requests The following quick actions are applicable to both issues and merge requests threads, discussions, and descriptions: @@ -96,3 +101,15 @@ The following quick actions are applicable for epics threads and description: | `/remove_child_epic <&epic | group&epic | Epic URL>` | Removes child epic from epic ([introduced in GitLab 12.0](https://gitlab.com/gitlab-org/gitlab-ee/issues/7330)) | | `/parent_epic <&epic | group&epic | Epic URL>` | Sets parent epic to epic ([introduced in GitLab 12.1](https://gitlab.com/gitlab-org/gitlab-ee/issues/10556)) | | `/remove_parent_epic` | Removes parent epic from epic ([introduced in GitLab 12.1](https://gitlab.com/gitlab-org/gitlab-ee/issues/10556)) | + +<!-- ## Troubleshooting + +Include any troubleshooting steps that you can foresee. If you know beforehand what issues +one might have when setting this up, or when something is changed, or on upgrading, it's +important to describe those, too. Think of things that may go wrong and include them here. +This is important to minimize requests for support, and to avoid doc comments with +questions that you know someone might ask. + +Each scenario can be a third-level heading, e.g. `### Getting error message X`. +If you have none to add when creating a doc, leave this section in place +but commented out to help encourage others to add to it in the future. --> diff --git a/doc/user/project/releases/index.md b/doc/user/project/releases/index.md index 00a4f6c6a6b..aae253467f0 100644 --- a/doc/user/project/releases/index.md +++ b/doc/user/project/releases/index.md @@ -1,3 +1,7 @@ +--- +type: reference, howto +--- + # Releases > [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/41766) in GitLab 11.7. @@ -60,3 +64,15 @@ Navigate to **Project > Releases** in order to see the list of releases for a gi project. ![Releases list](img/releases.png) + +<!-- ## Troubleshooting + +Include any troubleshooting steps that you can foresee. If you know beforehand what issues +one might have when setting this up, or when something is changed, or on upgrading, it's +important to describe those, too. Think of things that may go wrong and include them here. +This is important to minimize requests for support, and to avoid doc comments with +questions that you know someone might ask. + +Each scenario can be a third-level heading, e.g. `### Getting error message X`. +If you have none to add when creating a doc, leave this section in place +but commented out to help encourage others to add to it in the future. --> diff --git a/doc/user/project/repository/img/compare_branches.png b/doc/user/project/repository/branches/img/compare_branches.png Binary files differindex 52d5c518c45..52d5c518c45 100644 --- a/doc/user/project/repository/img/compare_branches.png +++ b/doc/user/project/repository/branches/img/compare_branches.png diff --git a/doc/user/project/repository/branches/index.md b/doc/user/project/repository/branches/index.md index a81c9197ec1..a864665602e 100644 --- a/doc/user/project/repository/branches/index.md +++ b/doc/user/project/repository/branches/index.md @@ -1,17 +1,41 @@ +--- +type: concepts, howto +--- + # Branches -Read through GiLab's branching documentation: +A branch is a version of a project's working tree. You create a branch for each +set of related changes you make. This keeps each set of changes separate from +each other, allowing changes to be made in parallel, without affecting each +other. + +After pushing your changes to a new branch, you can: + +- Create a [merge request](../../merge_requests/index.md) +- Perform inline code review +- [Discuss](../../../discussions/index.md) your implementation with your team +- Preview changes submitted to a new branch with [Review Apps](../../../../ci/review_apps/index.md). + +With [GitLab Starter](https://about.gitlab.com/pricing/), you can also request +[approval](../../merge_requests/merge_request_approvals.md) from your managers. + +For more information on managing branches using the GitLab UI, see: + +- [Default branches](#default-branch) +- [Create a branch](../web_editor.md#create-a-new-branch) +- [Protected branches](../../protected_branches.md#protected-branches) +- [Delete merged branches](#delete-merged-branches) +- [Branch filter search box](#branch-filter-search-box) + +You can also manage branches using the +[command line](../../../../gitlab-basics/start-using-git.md#create-a-branch). -- [Create a branch](../web_editor.md#create-a-new-branch). -- [Default branch](#default-branch). -- [Protected branches](../../protected_branches.md#protected-branches). -- [Delete merged branches](#delete-merged-branches). -- [Branch filter search box](#branch-filter-search-box). +<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>Watch the video [GitLab Flow](https://www.youtube.com/watch?v=InKNIvky2KE). See also: - [Branches API](../../../../api/branches.md), for information on operating on repository branches using the GitLab API. -- [GitLab Flow](../../../../university/training/gitlab_flow.md). Use the best of GitLab for your branching strategies. +- [GitLab Flow](../../../../university/training/gitlab_flow.md) documentation. - [Getting started with Git](../../../../topics/git/index.md) and GitLab. ## Default branch @@ -29,6 +53,17 @@ The default branch is also protected against accidental deletion. Read through the documentation on [protected branches](../../protected_branches.md#protected-branches) to learn more. +## Compare + +To compare branches in a repository: + +1. Navigate to your project's repository. +1. Select **Repository > Compare** in the sidebar. +1. Select branches to compare using the [branch filter search box](#branch-filter-search-box) +1. Click **Compare** to view the changes inline: + +![compare branches](img/compare_branches.png) + ## Delete merged branches > [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/6449) in GitLab 8.14. @@ -57,3 +92,15 @@ Sometimes when you have hundreds of branches you may want a more flexible matchi - `^feature` will only match branch names that begin with 'feature'. - `feature$` will only match branch names that end with 'feature'. + +<!-- ## Troubleshooting + +Include any troubleshooting steps that you can foresee. If you know beforehand what issues +one might have when setting this up, or when something is changed, or on upgrading, it's +important to describe those, too. Think of things that may go wrong and include them here. +This is important to minimize requests for support, and to avoid doc comments with +questions that you know someone might ask. + +Each scenario can be a third-level heading, e.g. `### Getting error message X`. +If you have none to add when creating a doc, leave this section in place +but commented out to help encourage others to add to it in the future. --> diff --git a/doc/user/project/repository/gpg_signed_commits/index.md b/doc/user/project/repository/gpg_signed_commits/index.md index 3b0a045ef9c..b929c6a681a 100644 --- a/doc/user/project/repository/gpg_signed_commits/index.md +++ b/doc/user/project/repository/gpg_signed_commits/index.md @@ -1,38 +1,39 @@ -# Signing commits with GPG +--- +type: concepts, howto +--- -NOTE: **Note:** -The term GPG is used for all OpenPGP/PGP/GPG related material and -implementations. +# Signing commits with GPG > - [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9546) in GitLab 9.5. > - Subkeys support was added in GitLab 10.1. -GitLab can show whether a commit is verified or not when signed with a GPG key. -All you need to do is upload the public GPG key in your profile settings. +You can use a GPG key to sign Git commits made in a GitLab repository. Signed +commits are labeled **Verified** if the identity of the committer can be +verified. To verify the identity of a committer, GitLab requires their public +GPG key. -GPG verified tags are not supported yet. +NOTE: **Note:** +The term GPG is used for all OpenPGP/PGP/GPG related material and +implementations. -## Getting started with GPG +GPG verified tags are not supported yet. -Here are a few guides to get you started with GPG: - -- [Git Tools - Signing Your Work](https://git-scm.com/book/en/v2/Git-Tools-Signing-Your-Work) -- [Managing OpenPGP Keys](https://riseup.net/en/security/message-security/openpgp/gpg-keys) -- [OpenPGP Best Practices](https://riseup.net/en/security/message-security/openpgp/best-practices) -- [Creating a new GPG key with subkeys](https://www.void.gr/kargig/blog/2013/12/02/creating-a-new-gpg-key-with-subkeys/) (advanced) +See the [further reading](#further-reading) section for more details on GPG. ## How GitLab handles GPG GitLab uses its own keyring to verify the GPG signature. It does not access any public key server. -In order to have a commit verified on GitLab the corresponding public key needs -to be uploaded to GitLab. For a signature to be verified three conditions need -to be met: +For a commit to be verified by GitLab: -1. The public key needs to be added your GitLab account -1. One of the emails in the GPG key matches a **verified** email address you use in GitLab -1. The committer's email matches the verified email from the gpg key +- The committer must have a GPG public/private key pair. +- The committer's public key must have been uploaded to their GitLab + account. +- One of the emails in the GPG key must match a **verified** email address + used by the committer in GitLab. +- The committer's email address must match the verified email address from the + GPG key. ## Generating a GPG key @@ -65,8 +66,7 @@ started: Your selection? 1 ``` -1. The next question is key length. We recommend to choose the highest value - which is `4096`: +1. The next question is key length. We recommend you choose `4096`: ``` RSA keys may be between 1024 and 4096 bits long. @@ -74,8 +74,8 @@ started: Requested keysize is 4096 bits ``` -1. Next, you need to specify the validity period of your key. This is something - subjective, and you can use the default value which is to never expire: +1. Specify the validity period of your key. This is something + subjective, and you can use the default value, which is to never expire: ``` Please specify how long the key should be valid. @@ -94,9 +94,9 @@ started: Is this correct? (y/N) y ``` -1. Enter you real name, the email address to be associated with this key (should - match a verified email address you use in GitLab) and an optional comment - (press <kbd>Enter</kbd> to skip): +1. Enter your real name, the email address to be associated with this key + (should match a verified email address you use in GitLab) and an optional + comment (press <kbd>Enter</kbd> to skip): ``` GnuPG needs to construct a user ID to identify your key. @@ -270,3 +270,24 @@ via [push rules](../../../../push_rules/push_rules.md). ## GPG signing API Learn how to [get the GPG signature from a commit via API](../../../../api/commits.md#get-gpg-signature-of-a-commit). + +## Further reading + +For more details about GPG, see: + +- [Git Tools - Signing Your Work](https://git-scm.com/book/en/v2/Git-Tools-Signing-Your-Work) +- [Managing OpenPGP Keys](https://riseup.net/en/security/message-security/openpgp/gpg-keys) +- [OpenPGP Best Practices](https://riseup.net/en/security/message-security/openpgp/best-practices) +- [Creating a new GPG key with subkeys](https://www.void.gr/kargig/blog/2013/12/02/creating-a-new-gpg-key-with-subkeys/) (advanced) + +<!-- ## Troubleshooting + +Include any troubleshooting steps that you can foresee. If you know beforehand what issues +one might have when setting this up, or when something is changed, or on upgrading, it's +important to describe those, too. Think of things that may go wrong and include them here. +This is important to minimize requests for support, and to avoid doc comments with +questions that you know someone might ask. + +Each scenario can be a third-level heading, e.g. `### Getting error message X`. +If you have none to add when creating a doc, leave this section in place +but commented out to help encourage others to add to it in the future. --> diff --git a/doc/user/project/repository/index.md b/doc/user/project/repository/index.md index 5b5685b3418..84d63d29929 100644 --- a/doc/user/project/repository/index.md +++ b/doc/user/project/repository/index.md @@ -1,3 +1,7 @@ +--- +type: concepts, howto +--- + # Repository A [repository](https://git-scm.com/book/en/v2/Git-Basics-Getting-a-Git-Repository) @@ -111,33 +115,7 @@ GitLab. ## Branches -When you submit changes in a new [branch](branches/index.md), you create a new version -of that project's file tree. Your branch contains all the changes -you are presenting, which are detected by Git line by line. - -To continue your workflow, once you pushed your changes to a new branch, -you can create a [merge request](../merge_requests/index.md), perform -inline code review, and [discuss](../../discussions/index.md) -your implementation with your team. -You can live preview changes submitted to a new branch with -[Review Apps](../../../ci/review_apps/index.md). - -With [GitLab Starter](https://about.gitlab.com/pricing/), you can also request -[approval](../merge_requests/merge_request_approvals.md) from your managers. - -To create, delete, and view [branches](branches/index.md) via GitLab's UI: - -- [Default branches](branches/index.md#default-branch) -- [Create a branch](web_editor.md#create-a-new-branch) -- [Protected branches](../protected_branches.md#protected-branches) -- [Delete merged branches](branches/index.md#delete-merged-branches) -- [Branch filter search box](branches/index.md#branch-filter-search-box) - -Alternatively, you can use the -[command line](../../../gitlab-basics/start-using-git.md#create-a-branch). - -To learn more about branching strategies read through the -[GitLab Flow](../../../university/training/gitlab_flow.md) documentation. +For details, see [Branches](branches/index.md). ## Commits @@ -213,14 +191,6 @@ detected, add the following to `.gitattributes` in the root of your repository. > *.proto linguist-detectable=true -## Compare - -Select branches to compare using the [branch filter search box](branches/index.md#branch-filter-search-box), then click the **Compare** button to view the changes inline: - -![compare branches](img/compare_branches.png) - -Find it under your project's **Repository > Compare**. - ## Locked files **(PREMIUM)** Use [File Locking](../file_lock.md) to @@ -256,3 +226,15 @@ By clicking the download icon, a dropdown will open with links to download the f `tar`, `tar.gz`, and `tar.bz2`. - **Artifacts:** allows users to download the artifacts of the latest CI build. + +<!-- ## Troubleshooting + +Include any troubleshooting steps that you can foresee. If you know beforehand what issues +one might have when setting this up, or when something is changed, or on upgrading, it's +important to describe those, too. Think of things that may go wrong and include them here. +This is important to minimize requests for support, and to avoid doc comments with +questions that you know someone might ask. + +Each scenario can be a third-level heading, e.g. `### Getting error message X`. +If you have none to add when creating a doc, leave this section in place +but commented out to help encourage others to add to it in the future. --> diff --git a/doc/user/project/repository/reducing_the_repo_size_using_git.md b/doc/user/project/repository/reducing_the_repo_size_using_git.md index 7c711bc0b3b..3adf66e4b6f 100644 --- a/doc/user/project/repository/reducing_the_repo_size_using_git.md +++ b/doc/user/project/repository/reducing_the_repo_size_using_git.md @@ -1,3 +1,7 @@ +--- +type: howto +--- + # Reducing the repository size using Git A GitLab Enterprise Edition administrator can set a [repository size limit](../../admin_area/settings/account_and_limit_settings.md) @@ -139,3 +143,15 @@ purposes! ``` Your repository should now be below the size limit. + +<!-- ## Troubleshooting + +Include any troubleshooting steps that you can foresee. If you know beforehand what issues +one might have when setting this up, or when something is changed, or on upgrading, it's +important to describe those, too. Think of things that may go wrong and include them here. +This is important to minimize requests for support, and to avoid doc comments with +questions that you know someone might ask. + +Each scenario can be a third-level heading, e.g. `### Getting error message X`. +If you have none to add when creating a doc, leave this section in place +but commented out to help encourage others to add to it in the future. --> diff --git a/doc/user/project/repository/web_editor.md b/doc/user/project/repository/web_editor.md index 0116f0fe7ca..09a5cdabc00 100644 --- a/doc/user/project/repository/web_editor.md +++ b/doc/user/project/repository/web_editor.md @@ -1,3 +1,7 @@ +--- +type: howto +--- + # GitLab Web Editor Sometimes it's easier to make quick changes directly from the GitLab interface @@ -169,3 +173,15 @@ through the web editor, you can choose to use another of your linked email addresses from the **User Settings > Edit Profile** page. [ce-2808]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/2808 + +<!-- ## Troubleshooting + +Include any troubleshooting steps that you can foresee. If you know beforehand what issues +one might have when setting this up, or when something is changed, or on upgrading, it's +important to describe those, too. Think of things that may go wrong and include them here. +This is important to minimize requests for support, and to avoid doc comments with +questions that you know someone might ask. + +Each scenario can be a third-level heading, e.g. `### Getting error message X`. +If you have none to add when creating a doc, leave this section in place +but commented out to help encourage others to add to it in the future. --> diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 10b4f8934d7..2d6dd18d4ea 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -2,6 +2,19 @@ module API module Entities + class BlameRangeCommit < Grape::Entity + expose :id + expose :parent_ids + expose :message + expose :authored_date, :author_name, :author_email + expose :committed_date, :committer_name, :committer_email + end + + class BlameRange < Grape::Entity + expose :commit, using: BlameRangeCommit + expose :lines + end + class WikiPageBasic < Grape::Entity expose :format expose :slug @@ -366,10 +379,7 @@ module API end expose :request_access_enabled expose :full_name, :full_path - - if ::Group.supports_nested_objects? - expose :parent_id - end + expose :parent_id expose :custom_attributes, using: 'API::Entities::CustomAttribute', if: :with_custom_attributes diff --git a/lib/api/files.rb b/lib/api/files.rb index ca59d330e1c..0b438fb5bbc 100644 --- a/lib/api/files.rb +++ b/lib/api/files.rb @@ -83,6 +83,31 @@ module API resource :projects, requirements: FILE_ENDPOINT_REQUIREMENTS do allow_access_with_scope :read_repository, if: -> (request) { request.get? || request.head? } + desc 'Get blame file metadata from repository' + params do + requires :file_path, type: String, desc: 'The url encoded path to the file. Ex. lib%2Fclass%2Erb' + requires :ref, type: String, desc: 'The name of branch, tag or commit', allow_blank: false + end + head ":id/repository/files/:file_path/blame", requirements: FILE_ENDPOINT_REQUIREMENTS do + assign_file_vars! + + set_http_headers(blob_data) + end + + desc 'Get blame file from the repository' + params do + requires :file_path, type: String, desc: 'The url encoded path to the file. Ex. lib%2Fclass%2Erb' + requires :ref, type: String, desc: 'The name of branch, tag or commit', allow_blank: false + end + get ":id/repository/files/:file_path/blame", requirements: FILE_ENDPOINT_REQUIREMENTS do + assign_file_vars! + + set_http_headers(blob_data) + + blame_ranges = Gitlab::Blame.new(@blob, @commit).groups(highlight: false) + present blame_ranges, with: Entities::BlameRange + end + desc 'Get raw file metadata from repository' params do requires :file_path, type: String, desc: 'The url encoded path to the file. Ex. lib%2Fclass%2Erb' diff --git a/lib/api/groups.rb b/lib/api/groups.rb index ec1020c7c78..f545f33c06b 100644 --- a/lib/api/groups.rb +++ b/lib/api/groups.rb @@ -114,10 +114,7 @@ module API params do requires :name, type: String, desc: 'The name of the group' requires :path, type: String, desc: 'The path of the group' - - if ::Group.supports_nested_objects? - optional :parent_id, type: Integer, desc: 'The parent group id for creating nested group' - end + optional :parent_id, type: Integer, desc: 'The parent group id for creating nested group' use :optional_params end diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index 8ae42c6dadd..1aa6dc44bf7 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -544,5 +544,9 @@ module API params[:archived] end + + def ip_address + env["action_dispatch.remote_ip"].to_s || request.ip + end end end diff --git a/lib/api/helpers/runner.rb b/lib/api/helpers/runner.rb index 100463fcb95..5b87eccf860 100644 --- a/lib/api/helpers/runner.rb +++ b/lib/api/helpers/runner.rb @@ -25,7 +25,7 @@ module API end def get_runner_ip - { ip_address: env["action_dispatch.remote_ip"].to_s || request.ip } + { ip_address: ip_address } end def current_runner diff --git a/lib/api/job_artifacts.rb b/lib/api/job_artifacts.rb index e7fed55170e..b35aa952f81 100644 --- a/lib/api/job_artifacts.rb +++ b/lib/api/job_artifacts.rb @@ -27,7 +27,7 @@ module API requirements: { ref_name: /.+/ } do authorize_download_artifacts! - latest_build = user_project.latest_successful_build_for!(params[:job], params[:ref_name]) + latest_build = user_project.latest_successful_build_for_ref!(params[:job], params[:ref_name]) present_carrierwave_file!(latest_build.artifacts_file) end @@ -45,7 +45,7 @@ module API requirements: { ref_name: /.+/ } do authorize_download_artifacts! - build = user_project.latest_successful_build_for!(params[:job], params[:ref_name]) + build = user_project.latest_successful_build_for_ref!(params[:job], params[:ref_name]) path = Gitlab::Ci::Build::Artifacts::Path .new(params[:artifact_path]) diff --git a/lib/api/triggers.rb b/lib/api/triggers.rb index 0e829c5699b..eeecc390256 100644 --- a/lib/api/triggers.rb +++ b/lib/api/triggers.rb @@ -112,27 +112,6 @@ module API end end - desc 'Take ownership of trigger' do - success Entities::Trigger - end - params do - requires :trigger_id, type: Integer, desc: 'The trigger ID' - end - post ':id/triggers/:trigger_id/take_ownership' do - authenticate! - authorize! :admin_build, user_project - - trigger = user_project.triggers.find(params.delete(:trigger_id)) - break not_found!('Trigger') unless trigger - - if trigger.update(owner: current_user) - status :ok - present trigger, with: Entities::Trigger, current_user: current_user - else - render_validation_error!(trigger) - end - end - desc 'Delete a trigger' do success Entities::Trigger end diff --git a/lib/api/validations/types/labels_list.rb b/lib/api/validations/types/labels_list.rb index 47cd83c29cf..60277b99106 100644 --- a/lib/api/validations/types/labels_list.rb +++ b/lib/api/validations/types/labels_list.rb @@ -10,7 +10,7 @@ module API when String value.split(',').map(&:strip) when Array - value.map { |v| v.to_s.split(',').map(&:strip) }.flatten + value.flat_map { |v| v.to_s.split(',').map(&:strip) } when LabelsList value else diff --git a/lib/banzai/filter/autolink_filter.rb b/lib/banzai/filter/autolink_filter.rb index 56214043d87..5f2cbc24c60 100644 --- a/lib/banzai/filter/autolink_filter.rb +++ b/lib/banzai/filter/autolink_filter.rb @@ -18,6 +18,7 @@ module Banzai # class AutolinkFilter < HTML::Pipeline::Filter include ActionView::Helpers::TagHelper + include Gitlab::Utils::SanitizeNodeLink # Pattern to match text that should be autolinked. # @@ -72,19 +73,11 @@ module Banzai private - # Return true if any of the UNSAFE_PROTOCOLS strings are included in the URI scheme - def contains_unsafe?(scheme) - return false unless scheme - - scheme = scheme.strip.downcase - Banzai::Filter::SanitizationFilter::UNSAFE_PROTOCOLS.any? { |protocol| scheme.include?(protocol) } - end - def autolink_match(match) # start by stripping out dangerous links begin uri = Addressable::URI.parse(match) - return match if contains_unsafe?(uri.scheme) + return match unless safe_protocol?(uri.scheme) rescue Addressable::URI::InvalidURIError return match end diff --git a/lib/banzai/filter/base_sanitization_filter.rb b/lib/banzai/filter/base_sanitization_filter.rb index 420e92cb1e8..2dabca3552d 100644 --- a/lib/banzai/filter/base_sanitization_filter.rb +++ b/lib/banzai/filter/base_sanitization_filter.rb @@ -11,6 +11,7 @@ module Banzai # Extends HTML::Pipeline::SanitizationFilter with common rules. class BaseSanitizationFilter < HTML::Pipeline::SanitizationFilter include Gitlab::Utils::StrongMemoize + extend Gitlab::Utils::SanitizeNodeLink UNSAFE_PROTOCOLS = %w(data javascript vbscript).freeze @@ -40,7 +41,7 @@ module Banzai # Allow any protocol in `a` elements # and then remove links with unsafe protocols whitelist[:protocols].delete('a') - whitelist[:transformers].push(self.class.remove_unsafe_links) + whitelist[:transformers].push(self.class.method(:remove_unsafe_links)) # Remove `rel` attribute from `a` elements whitelist[:transformers].push(self.class.remove_rel) @@ -54,35 +55,6 @@ module Banzai end class << self - def remove_unsafe_links - lambda do |env| - node = env[:node] - - return unless node.name == 'a' - return unless node.has_attribute?('href') - - begin - node['href'] = node['href'].strip - uri = Addressable::URI.parse(node['href']) - - return unless uri.scheme - - # Remove all invalid scheme characters before checking against the - # list of unsafe protocols. - # - # See https://tools.ietf.org/html/rfc3986#section-3.1 - scheme = uri.scheme - .strip - .downcase - .gsub(/[^A-Za-z0-9\+\.\-]+/, '') - - node.remove_attribute('href') if UNSAFE_PROTOCOLS.include?(scheme) - rescue Addressable::URI::InvalidURIError - node.remove_attribute('href') - end - end - end - def remove_rel lambda do |env| if env[:node_name] == 'a' diff --git a/lib/banzai/filter/wiki_link_filter.rb b/lib/banzai/filter/wiki_link_filter.rb index 1728a442533..18947679b69 100644 --- a/lib/banzai/filter/wiki_link_filter.rb +++ b/lib/banzai/filter/wiki_link_filter.rb @@ -8,15 +8,19 @@ module Banzai # Context options: # :project_wiki class WikiLinkFilter < HTML::Pipeline::Filter + include Gitlab::Utils::SanitizeNodeLink + def call return doc unless project_wiki? - doc.search('a:not(.gfm)').each { |el| process_link_attr(el.attribute('href')) } - doc.search('video').each { |el| process_link_attr(el.attribute('src')) } + doc.search('a:not(.gfm)').each { |el| process_link(el.attribute('href'), el) } + + doc.search('video').each { |el| process_link(el.attribute('src'), el) } + doc.search('img').each do |el| attr = el.attribute('data-src') || el.attribute('src') - process_link_attr(attr) + process_link(attr, el) end doc @@ -24,6 +28,11 @@ module Banzai protected + def process_link(link_attr, node) + process_link_attr(link_attr) + remove_unsafe_links({ node: node }, remove_invalid_links: false) + end + def project_wiki? !context[:project_wiki].nil? end diff --git a/lib/banzai/filter/wiki_link_filter/rewriter.rb b/lib/banzai/filter/wiki_link_filter/rewriter.rb index 77b5053f38c..f4cc8beeb52 100644 --- a/lib/banzai/filter/wiki_link_filter/rewriter.rb +++ b/lib/banzai/filter/wiki_link_filter/rewriter.rb @@ -4,8 +4,6 @@ module Banzai module Filter class WikiLinkFilter < HTML::Pipeline::Filter class Rewriter - UNSAFE_SLUG_REGEXES = [/\Ajavascript:/i].freeze - def initialize(link_string, wiki:, slug:) @uri = Addressable::URI.parse(link_string) @wiki_base_path = wiki && wiki.wiki_base_path @@ -37,8 +35,6 @@ module Banzai # Of the form `./link`, `../link`, or similar def apply_hierarchical_link_rules! - return if slug_considered_unsafe? - @uri = Addressable::URI.join(@slug, @uri) if @uri.to_s[0] == '.' end @@ -58,10 +54,6 @@ module Banzai def repository_upload? @uri.relative? && @uri.path.starts_with?(Wikis::CreateAttachmentService::ATTACHMENT_PATH) end - - def slug_considered_unsafe? - UNSAFE_SLUG_REGEXES.any? { |r| r.match?(@slug) } - end end end end diff --git a/lib/banzai/reference_redactor.rb b/lib/banzai/reference_redactor.rb index eb5c35da375..936436982e7 100644 --- a/lib/banzai/reference_redactor.rb +++ b/lib/banzai/reference_redactor.rb @@ -33,7 +33,7 @@ module Banzai # # data - An Array of a Hashes mapping an HTML document to nodes to redact. def redact_document_nodes(all_document_nodes) - all_nodes = all_document_nodes.map { |x| x[:nodes] }.flatten + all_nodes = all_document_nodes.flat_map { |x| x[:nodes] } visible = nodes_visible_to_user(all_nodes) metadata = [] diff --git a/lib/container_registry/client.rb b/lib/container_registry/client.rb index c80f49f5ae0..82810ea4076 100644 --- a/lib/container_registry/client.rb +++ b/lib/container_registry/client.rb @@ -7,7 +7,9 @@ module ContainerRegistry class Client attr_accessor :uri - MANIFEST_VERSION = 'application/vnd.docker.distribution.manifest.v2+json'.freeze + DOCKER_DISTRIBUTION_MANIFEST_V2_TYPE = 'application/vnd.docker.distribution.manifest.v2+json' + OCI_MANIFEST_V1_TYPE = 'application/vnd.oci.image.manifest.v1+json' + ACCEPTED_TYPES = [DOCKER_DISTRIBUTION_MANIFEST_V2_TYPE, OCI_MANIFEST_V1_TYPE].freeze # Taken from: FaradayMiddleware::FollowRedirects REDIRECT_CODES = Set.new [301, 302, 303, 307] @@ -60,12 +62,13 @@ module ContainerRegistry end def accept_manifest(conn) - conn.headers['Accept'] = MANIFEST_VERSION + conn.headers['Accept'] = ACCEPTED_TYPES conn.response :json, content_type: 'application/json' conn.response :json, content_type: 'application/vnd.docker.distribution.manifest.v1+prettyjws' conn.response :json, content_type: 'application/vnd.docker.distribution.manifest.v1+json' - conn.response :json, content_type: 'application/vnd.docker.distribution.manifest.v2+json' + conn.response :json, content_type: DOCKER_DISTRIBUTION_MANIFEST_V2_TYPE + conn.response :json, content_type: OCI_MANIFEST_V1_TYPE end def response_body(response, allow_redirect: false) @@ -79,7 +82,10 @@ module ContainerRegistry def redirect_response(location) return unless location - faraday_redirect.get(location) + uri = URI(@base_uri).merge(location) + raise ArgumentError, "Invalid scheme for #{location}" unless %w[http https].include?(uri.scheme) + + faraday_redirect.get(uri) end def faraday diff --git a/lib/gitlab.rb b/lib/gitlab.rb index c62d1071dba..d9d8dcf7900 100644 --- a/lib/gitlab.rb +++ b/lib/gitlab.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require_dependency File.expand_path('gitlab/popen', __dir__) +require 'pathname' module Gitlab def self.root @@ -61,7 +61,7 @@ module Gitlab def self.ee? @is_ee ||= - if ENV['IS_GITLAB_EE'].present? + if ENV['IS_GITLAB_EE'] && !ENV['IS_GITLAB_EE'].empty? Gitlab::Utils.to_boolean(ENV['IS_GITLAB_EE']) else # We may use this method when the Rails environment is not loaded. This diff --git a/lib/gitlab/action_rate_limiter.rb b/lib/gitlab/action_rate_limiter.rb index c442211e073..fdb06d00548 100644 --- a/lib/gitlab/action_rate_limiter.rb +++ b/lib/gitlab/action_rate_limiter.rb @@ -33,16 +33,48 @@ module Gitlab # Increments the given key and returns true if the action should # be throttled. # - # key - An array of ActiveRecord instances - # threshold_value - The maximum number of times this action should occur in the given time interval + # key - An array of ActiveRecord instances or strings + # threshold_value - The maximum number of times this action should occur in the given time interval. If number is zero is considered disabled. def throttled?(key, threshold_value) - self.increment(key) > threshold_value + threshold_value > 0 && + self.increment(key) > threshold_value + end + + # Logs request into auth.log + # + # request - Web request to be logged + # type - A symbol key that represents the request. + # current_user - Current user of the request, it can be nil. + def log_request(request, type, current_user) + request_information = { + message: 'Action_Rate_Limiter_Request', + env: type, + ip: request.ip, + request_method: request.request_method, + fullpath: request.fullpath + } + + if current_user + request_information.merge!({ + user_id: current_user.id, + username: current_user.username + }) + end + + Gitlab::AuthLogger.error(request_information) end private def action_key(key) - serialized = key.map { |obj| "#{obj.class.model_name.to_s.underscore}:#{obj.id}" }.join(":") + serialized = key.map do |obj| + if obj.is_a?(String) + "#{obj}" + else + "#{obj.class.model_name.to_s.underscore}:#{obj.id}" + end + end.join(":") + "action_rate_limiter:#{action}:#{serialized}" end end diff --git a/lib/gitlab/auth/activity.rb b/lib/gitlab/auth/activity.rb index 558628b5422..988ff196193 100644 --- a/lib/gitlab/auth/activity.rb +++ b/lib/gitlab/auth/activity.rb @@ -37,14 +37,17 @@ module Gitlab def user_authenticated! self.class.user_authenticated_counter_increment! + + case @opts[:message] + when :two_factor_authenticated + self.class.user_two_factor_authenticated_counter_increment! + end end def user_session_override! self.class.user_session_override_counter_increment! case @opts[:message] - when :two_factor_authenticated - self.class.user_two_factor_authenticated_counter_increment! when :sessionless_sign_in self.class.user_sessionless_authentication_counter_increment! end diff --git a/lib/gitlab/auth/o_auth/auth_hash.rb b/lib/gitlab/auth/o_auth/auth_hash.rb index 72a187377d0..91b9ddc0d00 100644 --- a/lib/gitlab/auth/o_auth/auth_hash.rb +++ b/lib/gitlab/auth/o_auth/auth_hash.rb @@ -60,8 +60,7 @@ module Gitlab def get_info(key) value = info[key] - Gitlab::Utils.force_utf8(value) if value - value + value.is_a?(String) ? Gitlab::Utils.force_utf8(value) : value end def username_and_email diff --git a/lib/gitlab/background_migration/backfill_project_repositories.rb b/lib/gitlab/background_migration/backfill_project_repositories.rb index c8d83cc1803..1d9aa050041 100644 --- a/lib/gitlab/background_migration/backfill_project_repositories.rb +++ b/lib/gitlab/background_migration/backfill_project_repositories.rb @@ -40,7 +40,7 @@ module Gitlab end def reload! - @shards = Hash[*Shard.all.map { |shard| [shard.name, shard.id] }.flatten] + @shards = Hash[*Shard.all.flat_map { |shard| [shard.name, shard.id] }] end end diff --git a/lib/gitlab/background_migration/migrate_stage_index.rb b/lib/gitlab/background_migration/migrate_stage_index.rb index f921233460d..55608529cee 100644 --- a/lib/gitlab/background_migration/migrate_stage_index.rb +++ b/lib/gitlab/background_migration/migrate_stage_index.rb @@ -13,34 +13,22 @@ module Gitlab private def migrate_stage_index_sql(start_id, stop_id) - if Gitlab::Database.postgresql? - <<~SQL - WITH freqs AS ( - SELECT stage_id, stage_idx, COUNT(*) AS freq FROM ci_builds - WHERE stage_id BETWEEN #{start_id} AND #{stop_id} - AND stage_idx IS NOT NULL - GROUP BY stage_id, stage_idx - ), indexes AS ( - SELECT DISTINCT stage_id, first_value(stage_idx) - OVER (PARTITION BY stage_id ORDER BY freq DESC) AS index - FROM freqs - ) + <<~SQL + WITH freqs AS ( + SELECT stage_id, stage_idx, COUNT(*) AS freq FROM ci_builds + WHERE stage_id BETWEEN #{start_id} AND #{stop_id} + AND stage_idx IS NOT NULL + GROUP BY stage_id, stage_idx + ), indexes AS ( + SELECT DISTINCT stage_id, first_value(stage_idx) + OVER (PARTITION BY stage_id ORDER BY freq DESC) AS index + FROM freqs + ) - UPDATE ci_stages SET position = indexes.index - FROM indexes WHERE indexes.stage_id = ci_stages.id - AND ci_stages.position IS NULL; - SQL - else - <<~SQL - UPDATE ci_stages - SET position = - (SELECT stage_idx FROM ci_builds - WHERE ci_builds.stage_id = ci_stages.id - GROUP BY ci_builds.stage_idx ORDER BY COUNT(*) DESC LIMIT 1) - WHERE ci_stages.id BETWEEN #{start_id} AND #{stop_id} - AND ci_stages.position IS NULL - SQL - end + UPDATE ci_stages SET position = indexes.index + FROM indexes WHERE indexes.stage_id = ci_stages.id + AND ci_stages.position IS NULL; + SQL end end end diff --git a/lib/gitlab/background_migration/prepare_untracked_uploads.rb b/lib/gitlab/background_migration/prepare_untracked_uploads.rb index 7d40b459c9a..2ac51dd7b55 100644 --- a/lib/gitlab/background_migration/prepare_untracked_uploads.rb +++ b/lib/gitlab/background_migration/prepare_untracked_uploads.rb @@ -55,7 +55,7 @@ module Gitlab def ensure_temporary_tracking_table_exists table_name = :untracked_files_for_uploads - unless ActiveRecord::Base.connection.data_source_exists?(table_name) + unless ActiveRecord::Base.connection.table_exists?(table_name) UntrackedFile.connection.create_table table_name do |t| t.string :path, limit: 600, null: false t.index :path, unique: true @@ -147,19 +147,13 @@ module Gitlab "#{UntrackedFile.table_name} (path) VALUES #{values}" end - def postgresql? - strong_memoize(:postgresql) do - Gitlab::Database.postgresql? - end - end - def can_bulk_insert_and_ignore_duplicates? !postgresql_pre_9_5? end def postgresql_pre_9_5? strong_memoize(:postgresql_pre_9_5) do - postgresql? && Gitlab::Database.version.to_f < 9.5 + Gitlab::Database.version.to_f < 9.5 end end diff --git a/lib/gitlab/background_migration/remove_restricted_todos.rb b/lib/gitlab/background_migration/remove_restricted_todos.rb index 47579d46c1b..9ef6d8654ae 100644 --- a/lib/gitlab/background_migration/remove_restricted_todos.rb +++ b/lib/gitlab/background_migration/remove_restricted_todos.rb @@ -50,14 +50,7 @@ module Gitlab private def remove_non_members_todos(project_id) - if Gitlab::Database.postgresql? - batch_remove_todos_cte(project_id) - else - unauthorized_project_todos(project_id) - .each_batch(of: 5000) do |batch| - batch.delete_all - end - end + batch_remove_todos_cte(project_id) end def remove_confidential_issue_todos(project_id) @@ -90,13 +83,7 @@ module Gitlab next if target_types.empty? - if Gitlab::Database.postgresql? - batch_remove_todos_cte(project_id, target_types) - else - unauthorized_project_todos(project_id) - .where(target_type: target_types) - .delete_all - end + batch_remove_todos_cte(project_id, target_types) end end diff --git a/lib/gitlab/badge/coverage/report.rb b/lib/gitlab/badge/coverage/report.rb index 7f7cc62c8ef..15cccc6f287 100644 --- a/lib/gitlab/badge/coverage/report.rb +++ b/lib/gitlab/badge/coverage/report.rb @@ -14,7 +14,7 @@ module Gitlab @ref = ref @job = job - @pipeline = @project.ci_pipelines.latest_successful_for(@ref) + @pipeline = @project.ci_pipelines.latest_successful_for_ref(@ref) end def entity diff --git a/lib/gitlab/ci/charts.rb b/lib/gitlab/ci/charts.rb index 7cabaadb122..3fbfdffe277 100644 --- a/lib/gitlab/ci/charts.rb +++ b/lib/gitlab/ci/charts.rb @@ -21,16 +21,10 @@ module Gitlab module MonthlyInterval # rubocop: disable CodeReuse/ActiveRecord def grouped_count(query) - if Gitlab::Database.postgresql? - query - .group("to_char(#{::Ci::Pipeline.table_name}.created_at, '01 Month YYYY')") - .count(:created_at) - .transform_keys(&:squish) - else - query - .group("DATE_FORMAT(#{::Ci::Pipeline.table_name}.created_at, '01 %M %Y')") - .count(:created_at) - end + query + .group("to_char(#{::Ci::Pipeline.table_name}.created_at, '01 Month YYYY')") + .count(:created_at) + .transform_keys(&:squish) end # rubocop: enable CodeReuse/ActiveRecord diff --git a/lib/gitlab/ci/config/normalizer.rb b/lib/gitlab/ci/config/normalizer.rb index 191f5d09645..99356226ef9 100644 --- a/lib/gitlab/ci/config/normalizer.rb +++ b/lib/gitlab/ci/config/normalizer.rb @@ -46,7 +46,7 @@ module Gitlab parallelized_job_names = @parallelized_jobs.keys.map(&:to_s) parallelized_config.each_with_object({}) do |(job_name, config), hash| if config[:dependencies] && (intersection = config[:dependencies] & parallelized_job_names).any? - parallelized_deps = intersection.map { |dep| @parallelized_jobs[dep.to_sym].map(&:first) }.flatten + parallelized_deps = intersection.flat_map { |dep| @parallelized_jobs[dep.to_sym].map(&:first) } deps = config[:dependencies] - intersection + parallelized_deps hash[job_name] = config.merge(dependencies: deps) else diff --git a/lib/gitlab/ci/status/build/manual.rb b/lib/gitlab/ci/status/build/manual.rb index d01b09f1398..df572188194 100644 --- a/lib/gitlab/ci/status/build/manual.rb +++ b/lib/gitlab/ci/status/build/manual.rb @@ -10,7 +10,7 @@ module Gitlab image: 'illustrations/manual_action.svg', size: 'svg-394', title: _('This job requires a manual action'), - content: _('This job depends on a user to trigger its process. Often they are used to deploy code to production environments') + content: _('This job requires manual intervention to start. Before starting this job, you can add variables below for last-minute configuration changes.') } end diff --git a/lib/gitlab/ci/status/factory.rb b/lib/gitlab/ci/status/factory.rb index 3446644eff8..2a0bf060c9b 100644 --- a/lib/gitlab/ci/status/factory.rb +++ b/lib/gitlab/ci/status/factory.rb @@ -34,11 +34,9 @@ module Gitlab def extended_statuses return @extended_statuses if defined?(@extended_statuses) - groups = self.class.extended_statuses.map do |group| + @extended_statuses = self.class.extended_statuses.flat_map do |group| Array(group).find { |status| status.matches?(@subject, @user) } - end - - @extended_statuses = groups.flatten.compact + end.compact end def self.extended_statuses diff --git a/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml b/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml index cf3d261c1cb..5c1c0c142e5 100644 --- a/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml @@ -50,13 +50,12 @@ variables: POSTGRES_DB: $CI_ENVIRONMENT_SLUG POSTGRES_VERSION: 9.6.2 - KUBERNETES_VERSION: 1.11.10 - HELM_VERSION: 2.14.0 - DOCKER_DRIVER: overlay2 ROLLOUT_RESOURCE_TYPE: deployment + DOCKER_TLS_CERTDIR: "" # https://gitlab.com/gitlab-org/gitlab-runner/issues/4501 + stages: - build - test diff --git a/lib/gitlab/ci/templates/Jobs/Browser-Performance-Testing.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Browser-Performance-Testing.gitlab-ci.yml index a09217e8cf0..b0a79950667 100644 --- a/lib/gitlab/ci/templates/Jobs/Browser-Performance-Testing.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Jobs/Browser-Performance-Testing.gitlab-ci.yml @@ -2,6 +2,8 @@ performance: stage: performance image: docker:stable allow_failure: true + variables: + DOCKER_TLS_CERTDIR: "" services: - docker:stable-dind script: diff --git a/lib/gitlab/ci/templates/Jobs/Build.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Build.gitlab-ci.yml index 18f7290e1d9..8061da968ed 100644 --- a/lib/gitlab/ci/templates/Jobs/Build.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Jobs/Build.gitlab-ci.yml @@ -1,6 +1,8 @@ build: stage: build image: "registry.gitlab.com/gitlab-org/cluster-integration/auto-build-image/master:stable" + variables: + DOCKER_TLS_CERTDIR: "" services: - docker:stable-dind script: diff --git a/lib/gitlab/ci/templates/Jobs/Code-Quality.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Code-Quality.gitlab-ci.yml index 005ea4b7a46..3adc6a72874 100644 --- a/lib/gitlab/ci/templates/Jobs/Code-Quality.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Jobs/Code-Quality.gitlab-ci.yml @@ -6,6 +6,7 @@ code_quality: - docker:stable-dind variables: DOCKER_DRIVER: overlay2 + DOCKER_TLS_CERTDIR: "" script: - | if ! docker info &>/dev/null; then diff --git a/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml index 6ead127e7b6..a8ec2d4781d 100644 --- a/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml @@ -1,14 +1,17 @@ +.auto-deploy: + image: "registry.gitlab.com/gitlab-org/cluster-integration/auto-deploy-image:v0.1.0" + review: + extends: .auto-deploy stage: review script: - - check_kube_domain - - install_dependencies - - download_chart - - ensure_namespace - - initialize_tiller - - create_secret - - deploy - - persist_environment_url + - auto-deploy check_kube_domain + - auto-deploy download_chart + - auto-deploy ensure_namespace + - auto-deploy initialize_tiller + - auto-deploy create_secret + - auto-deploy deploy + - auto-deploy persist_environment_url environment: name: review/$CI_COMMIT_REF_NAME url: http://$CI_PROJECT_ID-$CI_ENVIRONMENT_SLUG.$KUBE_INGRESS_BASE_DOMAIN @@ -27,13 +30,13 @@ review: - $REVIEW_DISABLED stop_review: + extends: .auto-deploy stage: cleanup variables: GIT_STRATEGY: none script: - - install_dependencies - - initialize_tiller - - delete + - auto-deploy initialize_tiller + - auto-deploy delete environment: name: review/$CI_COMMIT_REF_NAME action: stop @@ -57,15 +60,15 @@ stop_review: # STAGING_ENABLED. staging: + extends: .auto-deploy stage: staging script: - - check_kube_domain - - install_dependencies - - download_chart - - ensure_namespace - - initialize_tiller - - create_secret - - deploy + - auto-deploy check_kube_domain + - auto-deploy download_chart + - auto-deploy ensure_namespace + - auto-deploy initialize_tiller + - auto-deploy create_secret + - auto-deploy deploy environment: name: staging url: http://$CI_PROJECT_PATH_SLUG-staging.$KUBE_INGRESS_BASE_DOMAIN @@ -81,15 +84,15 @@ staging: # CANARY_ENABLED. canary: + extends: .auto-deploy stage: canary script: - - check_kube_domain - - install_dependencies - - download_chart - - ensure_namespace - - initialize_tiller - - create_secret - - deploy canary + - auto-deploy check_kube_domain + - auto-deploy download_chart + - auto-deploy ensure_namespace + - auto-deploy initialize_tiller + - auto-deploy create_secret + - auto-deploy deploy canary environment: name: production url: http://$CI_PROJECT_PATH_SLUG.$KUBE_INGRESS_BASE_DOMAIN @@ -102,18 +105,18 @@ canary: - $CANARY_ENABLED .production: &production_template + extends: .auto-deploy stage: production script: - - check_kube_domain - - install_dependencies - - download_chart - - ensure_namespace - - initialize_tiller - - create_secret - - deploy - - delete canary - - delete rollout - - persist_environment_url + - auto-deploy check_kube_domain + - auto-deploy download_chart + - auto-deploy ensure_namespace + - auto-deploy initialize_tiller + - auto-deploy create_secret + - auto-deploy deploy + - auto-deploy delete canary + - auto-deploy delete rollout + - auto-deploy persist_environment_url environment: name: production url: http://$CI_PROJECT_PATH_SLUG.$KUBE_INGRESS_BASE_DOMAIN @@ -152,17 +155,17 @@ production_manual: # This job implements incremental rollout on for every push to `master`. .rollout: &rollout_template + extends: .auto-deploy script: - - check_kube_domain - - install_dependencies - - download_chart - - ensure_namespace - - initialize_tiller - - create_secret - - deploy rollout $ROLLOUT_PERCENTAGE - - scale stable $((100-ROLLOUT_PERCENTAGE)) - - delete canary - - persist_environment_url + - auto-deploy check_kube_domain + - auto-deploy download_chart + - auto-deploy ensure_namespace + - auto-deploy initialize_tiller + - auto-deploy create_secret + - auto-deploy deploy rollout $ROLLOUT_PERCENTAGE + - auto-deploy scale stable $((100-ROLLOUT_PERCENTAGE)) + - auto-deploy delete canary + - auto-deploy persist_environment_url environment: name: production url: http://$CI_PROJECT_PATH_SLUG.$KUBE_INGRESS_BASE_DOMAIN @@ -240,331 +243,3 @@ rollout 100%: <<: *manual_rollout_template <<: *production_template allow_failure: false - -.deploy_helpers: &deploy_helpers | - [[ "$TRACE" ]] && set -x - export RELEASE_NAME=${HELM_RELEASE_NAME:-$CI_ENVIRONMENT_SLUG} - auto_database_url=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${RELEASE_NAME}-postgres:5432/${POSTGRES_DB} - export DATABASE_URL=${DATABASE_URL-$auto_database_url} - export TILLER_NAMESPACE=$KUBE_NAMESPACE - - function get_replicas() { - track="${1:-stable}" - percentage="${2:-100}" - - env_track=$( echo $track | tr -s '[:lower:]' '[:upper:]' ) - env_slug=$( echo ${CI_ENVIRONMENT_SLUG//-/_} | tr -s '[:lower:]' '[:upper:]' ) - - if [[ "$track" == "stable" ]] || [[ "$track" == "rollout" ]]; then - # for stable track get number of replicas from `PRODUCTION_REPLICAS` - eval new_replicas=\$${env_slug}_REPLICAS - if [[ -z "$new_replicas" ]]; then - new_replicas=$REPLICAS - fi - else - # for all tracks get number of replicas from `CANARY_PRODUCTION_REPLICAS` - eval new_replicas=\$${env_track}_${env_slug}_REPLICAS - if [[ -z "$new_replicas" ]]; then - eval new_replicas=\${env_track}_REPLICAS - fi - fi - - replicas="${new_replicas:-1}" - replicas="$(($replicas * $percentage / 100))" - - # always return at least one replicas - if [[ $replicas -gt 0 ]]; then - echo "$replicas" - else - echo 1 - fi - } - - # Extracts variables prefixed with K8S_SECRET_ - # and creates a Kubernetes secret. - # - # e.g. If we have the following environment variables: - # K8S_SECRET_A=value1 - # K8S_SECRET_B=multi\ word\ value - # - # Then we will create a secret with the following key-value pairs: - # data: - # A: dmFsdWUxCg== - # B: bXVsdGkgd29yZCB2YWx1ZQo= - function create_application_secret() { - track="${1-stable}" - export APPLICATION_SECRET_NAME=$(application_secret_name "$track") - - env | sed -n "s/^K8S_SECRET_\(.*\)$/\1/p" > k8s_prefixed_variables - - kubectl create secret \ - -n "$KUBE_NAMESPACE" generic "$APPLICATION_SECRET_NAME" \ - --from-env-file k8s_prefixed_variables -o yaml --dry-run | - kubectl replace -n "$KUBE_NAMESPACE" --force -f - - - export APPLICATION_SECRET_CHECKSUM=$(cat k8s_prefixed_variables | sha256sum | cut -d ' ' -f 1) - - rm k8s_prefixed_variables - } - - function deploy_name() { - name="$RELEASE_NAME" - track="${1-stable}" - - if [[ "$track" != "stable" ]]; then - name="$name-$track" - fi - - echo $name - } - - function application_secret_name() { - track="${1-stable}" - name=$(deploy_name "$track") - - echo "${name}-secret" - } - - function deploy() { - track="${1-stable}" - percentage="${2:-100}" - name=$(deploy_name "$track") - - if [[ -z "$CI_COMMIT_TAG" ]]; then - image_repository=${CI_APPLICATION_REPOSITORY:-$CI_REGISTRY_IMAGE/$CI_COMMIT_REF_SLUG} - image_tag=${CI_APPLICATION_TAG:-$CI_COMMIT_SHA} - else - image_repository=${CI_APPLICATION_REPOSITORY:-$CI_REGISTRY_IMAGE} - image_tag=${CI_APPLICATION_TAG:-$CI_COMMIT_TAG} - fi - - service_enabled="true" - postgres_enabled="$POSTGRES_ENABLED" - - # if track is different than stable, - # re-use all attached resources - if [[ "$track" != "stable" ]]; then - service_enabled="false" - postgres_enabled="false" - fi - - replicas=$(get_replicas "$track" "$percentage") - - if [[ "$CI_PROJECT_VISIBILITY" != "public" ]]; then - secret_name='gitlab-registry' - else - secret_name='' - fi - - create_application_secret "$track" - - env_slug=$(echo ${CI_ENVIRONMENT_SLUG//-/_} | tr -s '[:lower:]' '[:upper:]') - eval env_ADDITIONAL_HOSTS=\$${env_slug}_ADDITIONAL_HOSTS - if [ -n "$env_ADDITIONAL_HOSTS" ]; then - additional_hosts="{$env_ADDITIONAL_HOSTS}" - elif [ -n "$ADDITIONAL_HOSTS" ]; then - additional_hosts="{$ADDITIONAL_HOSTS}" - fi - - if [[ -n "$DB_INITIALIZE" && -z "$(helm ls -q "^$name$")" ]]; then - echo "Deploying first release with database initialization..." - helm upgrade --install \ - --wait \ - --set service.enabled="$service_enabled" \ - --set gitlab.app="$CI_PROJECT_PATH_SLUG" \ - --set gitlab.env="$CI_ENVIRONMENT_SLUG" \ - --set releaseOverride="$RELEASE_NAME" \ - --set image.repository="$image_repository" \ - --set image.tag="$image_tag" \ - --set image.pullPolicy=IfNotPresent \ - --set image.secrets[0].name="$secret_name" \ - --set application.track="$track" \ - --set application.database_url="$DATABASE_URL" \ - --set application.secretName="$APPLICATION_SECRET_NAME" \ - --set application.secretChecksum="$APPLICATION_SECRET_CHECKSUM" \ - --set service.commonName="le-$CI_PROJECT_ID.$KUBE_INGRESS_BASE_DOMAIN" \ - --set service.url="$CI_ENVIRONMENT_URL" \ - --set service.additionalHosts="$additional_hosts" \ - --set replicaCount="$replicas" \ - --set postgresql.enabled="$postgres_enabled" \ - --set postgresql.nameOverride="postgres" \ - --set postgresql.postgresUser="$POSTGRES_USER" \ - --set postgresql.postgresPassword="$POSTGRES_PASSWORD" \ - --set postgresql.postgresDatabase="$POSTGRES_DB" \ - --set postgresql.imageTag="$POSTGRES_VERSION" \ - --set application.initializeCommand="$DB_INITIALIZE" \ - $HELM_UPGRADE_EXTRA_ARGS \ - --namespace="$KUBE_NAMESPACE" \ - "$name" \ - chart/ - - echo "Deploying second release..." - helm upgrade --reuse-values \ - --wait \ - --set application.initializeCommand="" \ - --set application.migrateCommand="$DB_MIGRATE" \ - $HELM_UPGRADE_EXTRA_ARGS \ - --namespace="$KUBE_NAMESPACE" \ - "$name" \ - chart/ - else - echo "Deploying new release..." - helm upgrade --install \ - --wait \ - --set service.enabled="$service_enabled" \ - --set gitlab.app="$CI_PROJECT_PATH_SLUG" \ - --set gitlab.env="$CI_ENVIRONMENT_SLUG" \ - --set releaseOverride="$RELEASE_NAME" \ - --set image.repository="$image_repository" \ - --set image.tag="$image_tag" \ - --set image.pullPolicy=IfNotPresent \ - --set image.secrets[0].name="$secret_name" \ - --set application.track="$track" \ - --set application.database_url="$DATABASE_URL" \ - --set application.secretName="$APPLICATION_SECRET_NAME" \ - --set application.secretChecksum="$APPLICATION_SECRET_CHECKSUM" \ - --set service.commonName="le-$CI_PROJECT_ID.$KUBE_INGRESS_BASE_DOMAIN" \ - --set service.url="$CI_ENVIRONMENT_URL" \ - --set service.additionalHosts="$additional_hosts" \ - --set replicaCount="$replicas" \ - --set postgresql.enabled="$postgres_enabled" \ - --set postgresql.nameOverride="postgres" \ - --set postgresql.postgresUser="$POSTGRES_USER" \ - --set postgresql.postgresPassword="$POSTGRES_PASSWORD" \ - --set postgresql.postgresDatabase="$POSTGRES_DB" \ - --set postgresql.imageTag="$POSTGRES_VERSION" \ - --set application.migrateCommand="$DB_MIGRATE" \ - $HELM_UPGRADE_EXTRA_ARGS \ - --namespace="$KUBE_NAMESPACE" \ - "$name" \ - chart/ - fi - - if [[ -z "$ROLLOUT_STATUS_DISABLED" ]]; then - kubectl rollout status -n "$KUBE_NAMESPACE" -w "$ROLLOUT_RESOURCE_TYPE/$name" - fi - } - - function scale() { - track="${1-stable}" - percentage="${2-100}" - name=$(deploy_name "$track") - - replicas=$(get_replicas "$track" "$percentage") - - if [[ -n "$(helm ls -q "^$name$")" ]]; then - helm upgrade --reuse-values \ - --wait \ - --set replicaCount="$replicas" \ - --namespace="$KUBE_NAMESPACE" \ - "$name" \ - chart/ - fi - } - - function install_dependencies() { - apk add -U openssl curl tar gzip bash ca-certificates git - curl -sSL -o /etc/apk/keys/sgerrand.rsa.pub https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub - curl -sSL -O https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.28-r0/glibc-2.28-r0.apk - apk add glibc-2.28-r0.apk - rm glibc-2.28-r0.apk - - curl -sS "https://kubernetes-helm.storage.googleapis.com/helm-v${HELM_VERSION}-linux-amd64.tar.gz" | tar zx - mv linux-amd64/helm /usr/bin/ - mv linux-amd64/tiller /usr/bin/ - helm version --client - tiller -version - - curl -sSL -o /usr/bin/kubectl "https://storage.googleapis.com/kubernetes-release/release/v${KUBERNETES_VERSION}/bin/linux/amd64/kubectl" - chmod +x /usr/bin/kubectl - kubectl version --client - } - - function download_chart() { - if [[ ! -d chart ]]; then - auto_chart=${AUTO_DEVOPS_CHART:-gitlab/auto-deploy-app} - auto_chart_name=$(basename $auto_chart) - auto_chart_name=${auto_chart_name%.tgz} - auto_chart_name=${auto_chart_name%.tar.gz} - else - auto_chart="chart" - auto_chart_name="chart" - fi - - helm init --client-only - helm repo add ${AUTO_DEVOPS_CHART_REPOSITORY_NAME:-gitlab} ${AUTO_DEVOPS_CHART_REPOSITORY:-https://charts.gitlab.io} ${AUTO_DEVOPS_CHART_REPOSITORY_USERNAME:+"--username" "$AUTO_DEVOPS_CHART_REPOSITORY_USERNAME"} ${AUTO_DEVOPS_CHART_REPOSITORY_PASSWORD:+"--password" "$AUTO_DEVOPS_CHART_REPOSITORY_PASSWORD"} - if [[ ! -d "$auto_chart" ]]; then - helm fetch ${auto_chart} --untar - fi - if [ "$auto_chart_name" != "chart" ]; then - mv ${auto_chart_name} chart - fi - - helm dependency update chart/ - helm dependency build chart/ - } - - function ensure_namespace() { - kubectl get namespace "$KUBE_NAMESPACE" || kubectl create namespace "$KUBE_NAMESPACE" - } - - function check_kube_domain() { - if [[ -z "$KUBE_INGRESS_BASE_DOMAIN" ]]; then - echo "In order to deploy or use Review Apps," - echo "KUBE_INGRESS_BASE_DOMAIN variables must be set" - echo "From 11.8, you can set KUBE_INGRESS_BASE_DOMAIN in cluster settings" - echo "or by defining a variable at group or project level." - echo "You can also manually add it in .gitlab-ci.yml" - false - else - true - fi - } - - function initialize_tiller() { - echo "Checking Tiller..." - - export HELM_HOST="localhost:44134" - tiller -listen ${HELM_HOST} -alsologtostderr > /dev/null 2>&1 & - echo "Tiller is listening on ${HELM_HOST}" - - if ! helm version --debug; then - echo "Failed to init Tiller." - return 1 - fi - echo "" - } - - function create_secret() { - echo "Create secret..." - if [[ "$CI_PROJECT_VISIBILITY" == "public" ]]; then - return - fi - - kubectl create secret -n "$KUBE_NAMESPACE" \ - docker-registry gitlab-registry \ - --docker-server="$CI_REGISTRY" \ - --docker-username="${CI_DEPLOY_USER:-$CI_REGISTRY_USER}" \ - --docker-password="${CI_DEPLOY_PASSWORD:-$CI_REGISTRY_PASSWORD}" \ - --docker-email="$GITLAB_USER_EMAIL" \ - -o yaml --dry-run | kubectl replace -n "$KUBE_NAMESPACE" --force -f - - } - - function persist_environment_url() { - echo $CI_ENVIRONMENT_URL > environment_url.txt - } - - function delete() { - track="${1-stable}" - name=$(deploy_name "$track") - - if [[ -n "$(helm ls -q "^$name$")" ]]; then - helm delete --purge "$name" - fi - - secret_name=$(application_secret_name "$track") - kubectl delete secret --ignore-not-found -n "$KUBE_NAMESPACE" "$secret_name" - } - -before_script: - - *deploy_helpers diff --git a/lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml index 600762dd39f..15b84f1540d 100644 --- a/lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml @@ -9,6 +9,7 @@ dependency_scanning: image: docker:stable variables: DOCKER_DRIVER: overlay2 + DOCKER_TLS_CERTDIR: "" allow_failure: true services: - docker:stable-dind diff --git a/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml index 0a97a16b83c..4190de73e1f 100644 --- a/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml @@ -9,6 +9,7 @@ sast: image: docker:stable variables: DOCKER_DRIVER: overlay2 + DOCKER_TLS_CERTDIR: "" allow_failure: true services: - docker:stable-dind diff --git a/lib/gitlab/contributions_calendar.rb b/lib/gitlab/contributions_calendar.rb index f7d046600e8..5b0b91de5da 100644 --- a/lib/gitlab/contributions_calendar.rb +++ b/lib/gitlab/contributions_calendar.rb @@ -84,11 +84,7 @@ module Gitlab .and(t[:created_at].lteq(Date.current.end_of_day)) .and(t[:author_id].eq(contributor.id)) - date_interval = if Gitlab::Database.postgresql? - "INTERVAL '#{Time.zone.now.utc_offset} seconds'" - else - "INTERVAL #{Time.zone.now.utc_offset} SECOND" - end + date_interval = "INTERVAL '#{Time.zone.now.utc_offset} seconds'" Event.reorder(nil) .select(t[:project_id], t[:target_type], t[:action], "date(created_at + #{date_interval}) AS date", 'count(id) as total_amount') diff --git a/lib/gitlab/database.rb b/lib/gitlab/database.rb index eef63536de4..cbdff0ab060 100644 --- a/lib/gitlab/database.rb +++ b/lib/gitlab/database.rb @@ -46,6 +46,7 @@ module Gitlab end end + # @deprecated def self.postgresql? adapter_name.casecmp('postgresql').zero? end @@ -79,19 +80,19 @@ module Gitlab end def self.postgresql_9_or_less? - postgresql? && version.to_f < 10 + version.to_f < 10 end def self.join_lateral_supported? - postgresql? && version.to_f >= 9.3 + version.to_f >= 9.3 end def self.replication_slots_supported? - postgresql? && version.to_f >= 9.4 + version.to_f >= 9.4 end def self.postgresql_minimum_supported_version? - postgresql? && version.to_f >= 9.6 + version.to_f >= 9.6 end # map some of the function names that changed between PostgreSQL 9 and 10 diff --git a/lib/gitlab/database/count.rb b/lib/gitlab/database/count.rb index f3d37ccd72a..eac61254bdf 100644 --- a/lib/gitlab/database/count.rb +++ b/lib/gitlab/database/count.rb @@ -37,16 +37,14 @@ module Gitlab # @return [Hash] of Model -> count mapping def self.approximate_counts(models, strategies: [TablesampleCountStrategy, ReltuplesCountStrategy, ExactCountStrategy]) strategies.each_with_object({}) do |strategy, counts_by_model| - if strategy.enabled? - models_with_missing_counts = models - counts_by_model.keys + models_with_missing_counts = models - counts_by_model.keys - break counts_by_model if models_with_missing_counts.empty? + break counts_by_model if models_with_missing_counts.empty? - counts = strategy.new(models_with_missing_counts).count + counts = strategy.new(models_with_missing_counts).count - counts.each do |model, count| - counts_by_model[model] = count - end + counts.each do |model, count| + counts_by_model[model] = count end end end diff --git a/lib/gitlab/database/count/exact_count_strategy.rb b/lib/gitlab/database/count/exact_count_strategy.rb index fa6951eda22..0b8fe640bf8 100644 --- a/lib/gitlab/database/count/exact_count_strategy.rb +++ b/lib/gitlab/database/count/exact_count_strategy.rb @@ -23,10 +23,6 @@ module Gitlab rescue *CONNECTION_ERRORS {} end - - def self.enabled? - true - end end end end diff --git a/lib/gitlab/database/count/reltuples_count_strategy.rb b/lib/gitlab/database/count/reltuples_count_strategy.rb index 695f6fa766e..6cd90c01ab2 100644 --- a/lib/gitlab/database/count/reltuples_count_strategy.rb +++ b/lib/gitlab/database/count/reltuples_count_strategy.rb @@ -31,10 +31,6 @@ module Gitlab {} end - def self.enabled? - Gitlab::Database.postgresql? - end - private # Models using single-type inheritance (STI) don't work with diff --git a/lib/gitlab/database/count/tablesample_count_strategy.rb b/lib/gitlab/database/count/tablesample_count_strategy.rb index 7777f31f702..e9387a91a14 100644 --- a/lib/gitlab/database/count/tablesample_count_strategy.rb +++ b/lib/gitlab/database/count/tablesample_count_strategy.rb @@ -28,10 +28,6 @@ module Gitlab {} end - def self.enabled? - Gitlab::Database.postgresql? && Feature.enabled?(:tablesample_counts) - end - private def perform_count(model, estimate) diff --git a/lib/gitlab/database/grant.rb b/lib/gitlab/database/grant.rb index 26adf4e221b..1f47f320a29 100644 --- a/lib/gitlab/database/grant.rb +++ b/lib/gitlab/database/grant.rb @@ -6,47 +6,25 @@ module Gitlab class Grant < ActiveRecord::Base include FromUnion - self.table_name = - if Database.postgresql? - 'information_schema.role_table_grants' - else - 'information_schema.schema_privileges' - end + self.table_name = 'information_schema.role_table_grants' # Returns true if the current user can create and execute triggers on the # given table. def self.create_and_execute_trigger?(table) - if Database.postgresql? - # We _must not_ use quote_table_name as this will produce double - # quotes on PostgreSQL and for "has_table_privilege" we need single - # quotes. - quoted_table = connection.quote(table) - - begin - from(nil) - .pluck(Arel.sql("has_table_privilege(#{quoted_table}, 'TRIGGER')")) - .first - rescue ActiveRecord::StatementInvalid - # This error is raised when using a non-existing table name. In this - # case we just want to return false as a user technically can't - # create triggers for such a table. - false - end - else - queries = [ - Grant.select(1) - .from('information_schema.user_privileges') - .where("PRIVILEGE_TYPE = 'SUPER'") - .where("GRANTEE = CONCAT('\\'', REPLACE(CURRENT_USER(), '@', '\\'@\\''), '\\'')"), - - Grant.select(1) - .from('information_schema.schema_privileges') - .where("PRIVILEGE_TYPE = 'TRIGGER'") - .where('TABLE_SCHEMA = ?', Gitlab::Database.database_name) - .where("GRANTEE = CONCAT('\\'', REPLACE(CURRENT_USER(), '@', '\\'@\\''), '\\'')") - ] + # We _must not_ use quote_table_name as this will produce double + # quotes on PostgreSQL and for "has_table_privilege" we need single + # quotes. + quoted_table = connection.quote(table) - Grant.from_union(queries, alias_as: 'privs').any? + begin + from(nil) + .pluck(Arel.sql("has_table_privilege(#{quoted_table}, 'TRIGGER')")) + .first + rescue ActiveRecord::StatementInvalid + # This error is raised when using a non-existing table name. In this + # case we just want to return false as a user technically can't + # create triggers for such a table. + false end end end diff --git a/lib/gitlab/database/median.rb b/lib/gitlab/database/median.rb index 391c1e85a7d..603b125d8b4 100644 --- a/lib/gitlab/database/median.rb +++ b/lib/gitlab/database/median.rb @@ -137,8 +137,6 @@ module Gitlab end def extract_diff_epoch(diff) - return diff unless Gitlab::Database.postgresql? - Arel.sql(%Q{EXTRACT(EPOCH FROM (#{diff.to_sql}))}) end diff --git a/lib/gitlab/database/migration_helpers.rb b/lib/gitlab/database/migration_helpers.rb index 4bd09163bf2..9bba4f6ce1e 100644 --- a/lib/gitlab/database/migration_helpers.rb +++ b/lib/gitlab/database/migration_helpers.rb @@ -152,8 +152,6 @@ module Gitlab # Only available on Postgresql >= 9.2 def supports_drop_index_concurrently? - return false unless Database.postgresql? - version = select_one("SELECT current_setting('server_version_num') AS v")['v'].to_i version >= 90200 diff --git a/lib/gitlab/database/sha_attribute.rb b/lib/gitlab/database/sha_attribute.rb index 109ae7893da..ddbabc9098e 100644 --- a/lib/gitlab/database/sha_attribute.rb +++ b/lib/gitlab/database/sha_attribute.rb @@ -2,14 +2,9 @@ module Gitlab module Database - BINARY_TYPE = - if Gitlab::Database.postgresql? - # PostgreSQL defines its own class with slightly different - # behaviour from the default Binary type. - ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Bytea - else - ActiveModel::Type::Binary - end + # PostgreSQL defines its own class with slightly different + # behaviour from the default Binary type. + BINARY_TYPE = ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Bytea # Class for casting binary data to hexadecimal SHA1 hashes (and vice-versa). # diff --git a/lib/gitlab/database/subquery.rb b/lib/gitlab/database/subquery.rb index 10971d2b274..2a6f39c6a27 100644 --- a/lib/gitlab/database/subquery.rb +++ b/lib/gitlab/database/subquery.rb @@ -6,11 +6,7 @@ module Gitlab class << self def self_join(relation) t = relation.arel_table - # Work around a bug in Rails 5, where LIMIT causes trouble - # See https://gitlab.com/gitlab-org/gitlab-ce/issues/51729 - r = relation.limit(nil).arel - r.take(relation.limit_value) if relation.limit_value - t2 = r.as('t2') + t2 = relation.arel.as('t2') relation.unscoped.joins(t.join(t2).on(t[:id].eq(t2[:id])).join_sources.first) end diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb index 6e8aa5d578e..27032602828 100644 --- a/lib/gitlab/git/repository.rb +++ b/lib/gitlab/git/repository.rb @@ -55,6 +55,10 @@ module Gitlab @name = @relative_path.split("/").last end + def to_s + "<#{self.class.name}: #{self.gl_project_path}>" + end + def ==(other) other.is_a?(self.class) && [storage, relative_path] == [other.storage, other.relative_path] end diff --git a/lib/gitlab/git/rugged_impl/blob.rb b/lib/gitlab/git/rugged_impl/blob.rb index 9aea736527b..5c73c0c66a9 100644 --- a/lib/gitlab/git/rugged_impl/blob.rb +++ b/lib/gitlab/git/rugged_impl/blob.rb @@ -16,7 +16,7 @@ module Gitlab override :tree_entry def tree_entry(repository, sha, path, limit) if use_rugged?(repository, :rugged_tree_entry) - wrap_rugged_call { rugged_tree_entry(repository, sha, path, limit) } + execute_rugged_call(:rugged_tree_entry, repository, sha, path, limit) else super end diff --git a/lib/gitlab/git/rugged_impl/commit.rb b/lib/gitlab/git/rugged_impl/commit.rb index 29ae9bdd851..0eff35ab1c4 100644 --- a/lib/gitlab/git/rugged_impl/commit.rb +++ b/lib/gitlab/git/rugged_impl/commit.rb @@ -36,7 +36,7 @@ module Gitlab override :find_commit def find_commit(repo, commit_id) if use_rugged?(repo, :rugged_find_commit) - wrap_rugged_call { rugged_find(repo, commit_id) } + execute_rugged_call(:rugged_find, repo, commit_id) else super end @@ -45,7 +45,7 @@ module Gitlab override :batch_by_oid def batch_by_oid(repo, oids) if use_rugged?(repo, :rugged_list_commits_by_oid) - wrap_rugged_call { rugged_batch_by_oid(repo, oids) } + execute_rugged_call(:rugged_batch_by_oid, repo, oids) else super end @@ -68,7 +68,7 @@ module Gitlab override :commit_tree_entry def commit_tree_entry(path) if use_rugged?(@repository, :rugged_commit_tree_entry) - wrap_rugged_call { rugged_tree_entry(path) } + execute_rugged_call(:rugged_tree_entry, path) else super end diff --git a/lib/gitlab/git/rugged_impl/repository.rb b/lib/gitlab/git/rugged_impl/repository.rb index 7bed553393c..8fde93e71e2 100644 --- a/lib/gitlab/git/rugged_impl/repository.rb +++ b/lib/gitlab/git/rugged_impl/repository.rb @@ -48,7 +48,7 @@ module Gitlab override :ancestor? def ancestor?(from, to) if use_rugged?(self, :rugged_commit_is_ancestor) - wrap_rugged_call { rugged_is_ancestor?(from, to) } + execute_rugged_call(:rugged_is_ancestor?, from, to) else super end diff --git a/lib/gitlab/git/rugged_impl/tree.rb b/lib/gitlab/git/rugged_impl/tree.rb index 479c5f9d8b7..389c9d32ccb 100644 --- a/lib/gitlab/git/rugged_impl/tree.rb +++ b/lib/gitlab/git/rugged_impl/tree.rb @@ -16,7 +16,7 @@ module Gitlab override :tree_entries def tree_entries(repository, sha, path, recursive) if use_rugged?(repository, :rugged_tree_entries) - wrap_rugged_call { tree_entries_with_flat_path_from_rugged(repository, sha, path, recursive) } + execute_rugged_call(:tree_entries_with_flat_path_from_rugged, repository, sha, path, recursive) else super end diff --git a/lib/gitlab/git/rugged_impl/use_rugged.rb b/lib/gitlab/git/rugged_impl/use_rugged.rb index badf943e39c..80b75689334 100644 --- a/lib/gitlab/git/rugged_impl/use_rugged.rb +++ b/lib/gitlab/git/rugged_impl/use_rugged.rb @@ -11,17 +11,23 @@ module Gitlab Gitlab::GitalyClient.can_use_disk?(repo.storage) end - def wrap_rugged_call(&block) + def execute_rugged_call(method_name, *args) Gitlab::GitalyClient::StorageSettings.allow_disk_access do start = Gitlab::Metrics::System.monotonic_time - result = yield + result = send(method_name, *args) # rubocop:disable GitlabSecurity/PublicSend duration = Gitlab::Metrics::System.monotonic_time - start if Gitlab::RuggedInstrumentation.active? Gitlab::RuggedInstrumentation.increment_query_count Gitlab::RuggedInstrumentation.query_time += duration + + Gitlab::RuggedInstrumentation.add_call_details( + feature: method_name, + args: args, + duration: duration, + backtrace: Gitlab::Profiler.clean_backtrace(caller)) end result diff --git a/lib/gitlab/gitaly_client.rb b/lib/gitlab/gitaly_client.rb index c98de722fe1..4783832961d 100644 --- a/lib/gitlab/gitaly_client.rb +++ b/lib/gitlab/gitaly_client.rb @@ -413,7 +413,7 @@ module Gitlab metadata_file = File.read(storage_metadata_file_path(storage)) metadata_hash = JSON.parse(metadata_file) metadata_hash['gitaly_filesystem_id'] - rescue Errno::ENOENT, Errno::ACCESS, JSON::ParserError + rescue Errno::ENOENT, Errno::EACCES, JSON::ParserError nil end diff --git a/lib/gitlab/github_import/client.rb b/lib/gitlab/github_import/client.rb index a61beafae0d..826b35d685c 100644 --- a/lib/gitlab/github_import/client.rb +++ b/lib/gitlab/github_import/client.rb @@ -40,7 +40,7 @@ module Gitlab # otherwise hitting the rate limit will result in a thread # being blocked in a `sleep()` call for up to an hour. def initialize(token, per_page: 100, parallel: true) - @octokit = Octokit::Client.new( + @octokit = ::Octokit::Client.new( access_token: token, per_page: per_page, api_endpoint: api_endpoint @@ -139,7 +139,7 @@ module Gitlab begin yield - rescue Octokit::TooManyRequests + rescue ::Octokit::TooManyRequests raise_or_wait_for_rate_limit # This retry will only happen when running in sequential mode as we'll diff --git a/lib/gitlab/health_checks/db_check.rb b/lib/gitlab/health_checks/db_check.rb index 2bcd25cd3cc..ec4b97eaca4 100644 --- a/lib/gitlab/health_checks/db_check.rb +++ b/lib/gitlab/health_checks/db_check.rb @@ -18,11 +18,7 @@ module Gitlab def check catch_timeout 10.seconds do - if Gitlab::Database.postgresql? - ActiveRecord::Base.connection.execute('SELECT 1 as ping')&.first&.[]('ping')&.to_s - else - ActiveRecord::Base.connection.execute('SELECT 1 as ping')&.first&.first&.to_s - end + ActiveRecord::Base.connection.execute('SELECT 1 as ping')&.first&.[]('ping')&.to_s end end end diff --git a/lib/gitlab/import_export.rb b/lib/gitlab/import_export.rb index f63a5ece71e..bb46bd657e8 100644 --- a/lib/gitlab/import_export.rb +++ b/lib/gitlab/import_export.rb @@ -4,7 +4,9 @@ module Gitlab module ImportExport extend self - # For every version update, the version history in import_export.md has to be kept up to date. + # For every version update the version history in these docs must be kept up to date: + # - development/import_export.md + # - user/project/settings/import_export.md VERSION = '0.2.4'.freeze FILENAME_LIMIT = 50 @@ -28,6 +30,14 @@ module Gitlab "project.bundle" end + def lfs_objects_filename + "lfs-objects.json" + end + + def lfs_objects_storage + "lfs-objects" + end + def config_file Rails.root.join('lib/gitlab/import_export/import_export.yml') end diff --git a/lib/gitlab/import_export/attributes_finder.rb b/lib/gitlab/import_export/attributes_finder.rb index 409243e68a5..42cd94add79 100644 --- a/lib/gitlab/import_export/attributes_finder.rb +++ b/lib/gitlab/import_export/attributes_finder.rb @@ -45,7 +45,7 @@ module Gitlab end def key_from_hash(value) - value.is_a?(Hash) ? value.keys.first : value + value.is_a?(Hash) ? value.first.first : value end end end diff --git a/lib/gitlab/import_export/json_hash_builder.rb b/lib/gitlab/import_export/json_hash_builder.rb index b145f37c052..a92e3862361 100644 --- a/lib/gitlab/import_export/json_hash_builder.rb +++ b/lib/gitlab/import_export/json_hash_builder.rb @@ -27,7 +27,7 @@ module Gitlab # {:merge_requests=>[:merge_request_diff, :notes]} def process_model_objects(model_object_hash) json_config_hash = {} - current_key = model_object_hash.keys.first + current_key = model_object_hash.first.first model_object_hash.values.flatten.each do |model_object| @attributes_finder.parse(current_key) { |hash| json_config_hash[current_key] ||= hash } diff --git a/lib/gitlab/import_export/lfs_restorer.rb b/lib/gitlab/import_export/lfs_restorer.rb index 345c7880e30..1de8a5bf9ec 100644 --- a/lib/gitlab/import_export/lfs_restorer.rb +++ b/lib/gitlab/import_export/lfs_restorer.rb @@ -3,6 +3,10 @@ module Gitlab module ImportExport class LfsRestorer + include Gitlab::Utils::StrongMemoize + + attr_accessor :project, :shared + def initialize(project:, shared:) @project = project @shared = shared @@ -17,7 +21,7 @@ module Gitlab true rescue => e - @shared.error(e) + shared.error(e) false end @@ -29,16 +33,57 @@ module Gitlab lfs_object = LfsObject.find_or_initialize_by(oid: oid, size: size) lfs_object.file = File.open(path) unless lfs_object.file&.exists? + lfs_object.save! if lfs_object.changed? - @project.all_lfs_objects << lfs_object + repository_types(oid).each do |repository_type| + LfsObjectsProject.create!( + project: project, + lfs_object: lfs_object, + repository_type: repository_type + ) + end + end + + def repository_types(oid) + # We allow support for imports created before the `lfs-objects.json` + # file was generated. In this case, the restorer will link an LFS object + # with a single `lfs_objects_projects` relation. + # + # This allows us backwards-compatibility without version bumping. + # See https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/30830#note_192608870 + return ['project'] unless has_lfs_json? + + lfs_json[oid] end def lfs_file_paths @lfs_file_paths ||= Dir.glob("#{lfs_storage_path}/*") end + def has_lfs_json? + strong_memoize(:has_lfs_json) do + File.exist?(lfs_json_path) + end + end + + def lfs_json + return {} unless has_lfs_json? + + @lfs_json ||= + begin + json = IO.read(lfs_json_path) + ActiveSupport::JSON.decode(json) + rescue + raise Gitlab::ImportExport::Error.new('Incorrect JSON format') + end + end + def lfs_storage_path - File.join(@shared.export_path, 'lfs-objects') + File.join(shared.export_path, ImportExport.lfs_objects_storage) + end + + def lfs_json_path + File.join(shared.export_path, ImportExport.lfs_objects_filename) end end end diff --git a/lib/gitlab/import_export/lfs_saver.rb b/lib/gitlab/import_export/lfs_saver.rb index 954f6f00078..18c590e1ca9 100644 --- a/lib/gitlab/import_export/lfs_saver.rb +++ b/lib/gitlab/import_export/lfs_saver.rb @@ -5,25 +5,40 @@ module Gitlab class LfsSaver include Gitlab::ImportExport::CommandLineUtil + attr_accessor :lfs_json, :project, :shared + + BATCH_SIZE = 100 + def initialize(project:, shared:) @project = project @shared = shared + @lfs_json = {} end def save - @project.all_lfs_objects.each do |lfs_object| - save_lfs_object(lfs_object) + project.all_lfs_objects.find_in_batches(batch_size: BATCH_SIZE) do |batch| + batch.each do |lfs_object| + save_lfs_object(lfs_object) + end + + append_lfs_json_for_batch(batch) if write_lfs_json_enabled? end + write_lfs_json if write_lfs_json_enabled? + true rescue => e - @shared.error(e) + shared.error(e) false end private + def write_lfs_json_enabled? + ::Feature.enabled?(:export_lfs_objects_projects, default_enabled: true) + end + def save_lfs_object(lfs_object) if lfs_object.local_store? copy_file_for_lfs_object(lfs_object) @@ -45,12 +60,36 @@ module Gitlab copy_files(lfs_object.file.path, destination_path_for_object(lfs_object)) end + def append_lfs_json_for_batch(lfs_objects_batch) + lfs_objects_projects = LfsObjectsProject + .select('lfs_objects.oid, array_agg(distinct lfs_objects_projects.repository_type) as repository_types') + .joins(:lfs_object) + .where(project: project, lfs_object: lfs_objects_batch) + .group('lfs_objects.oid') + + lfs_objects_projects.each do |group| + oid = group.oid + + lfs_json[oid] ||= [] + lfs_json[oid] += group.repository_types + end + end + + def write_lfs_json + mkdir_p(shared.export_path) + File.write(lfs_json_path, lfs_json.to_json) + end + def destination_path_for_object(lfs_object) File.join(lfs_export_path, lfs_object.oid) end def lfs_export_path - File.join(@shared.export_path, 'lfs-objects') + File.join(shared.export_path, ImportExport.lfs_objects_storage) + end + + def lfs_json_path + File.join(shared.export_path, ImportExport.lfs_objects_filename) end end end diff --git a/lib/gitlab/import_export/members_mapper.rb b/lib/gitlab/import_export/members_mapper.rb index ab19a509310..4e976cfca3a 100644 --- a/lib/gitlab/import_export/members_mapper.rb +++ b/lib/gitlab/import_export/members_mapper.rb @@ -35,7 +35,7 @@ module Gitlab end def include?(old_author_id) - map.keys.include?(old_author_id) && map[old_author_id] != default_user_id + map.has_key?(old_author_id) && map[old_author_id] != default_user_id end private diff --git a/lib/gitlab/import_export/relation_factory.rb b/lib/gitlab/import_export/relation_factory.rb index 1b545b1d049..0be49e27acb 100644 --- a/lib/gitlab/import_export/relation_factory.rb +++ b/lib/gitlab/import_export/relation_factory.rb @@ -185,7 +185,7 @@ module Gitlab return unless EXISTING_OBJECT_CHECK.include?(@relation_name) return unless @relation_hash['group_id'] - @relation_hash['group_id'] = @project.group&.id + @relation_hash['group_id'] = @project.namespace_id end def reset_tokens! diff --git a/lib/gitlab/legacy_github_import/client.rb b/lib/gitlab/legacy_github_import/client.rb index bbdd094e33b..b23efd64dee 100644 --- a/lib/gitlab/legacy_github_import/client.rb +++ b/lib/gitlab/legacy_github_import/client.rb @@ -101,7 +101,7 @@ module Gitlab # GitHub Rate Limit API returns 404 when the rate limit is # disabled. In this case we just want to return gracefully # instead of spitting out an error. - rescue Octokit::NotFound + rescue ::Octokit::NotFound nil end diff --git a/lib/gitlab/metrics/dashboard/base_service.rb b/lib/gitlab/metrics/dashboard/base_service.rb deleted file mode 100644 index 0628e82e592..00000000000 --- a/lib/gitlab/metrics/dashboard/base_service.rb +++ /dev/null @@ -1,72 +0,0 @@ -# frozen_string_literal: true - -# Searches a projects repository for a metrics dashboard and formats the output. -# Expects any custom dashboards will be located in `.gitlab/dashboards` -module Gitlab - module Metrics - module Dashboard - class BaseService < ::BaseService - PROCESSING_ERROR = Gitlab::Metrics::Dashboard::Stages::BaseStage::DashboardProcessingError - NOT_FOUND_ERROR = Gitlab::Template::Finders::RepoTemplateFinder::FileNotFoundError - - def get_dashboard - return error('Insufficient permissions.', :unauthorized) unless allowed? - - success(dashboard: process_dashboard) - rescue NOT_FOUND_ERROR - error("#{dashboard_path} could not be found.", :not_found) - rescue PROCESSING_ERROR => e - error(e.message, :unprocessable_entity) - end - - # Summary of all known dashboards for the service. - # @return [Array<Hash>] ex) [{ path: String, default: Boolean }] - def self.all_dashboard_paths(_project) - raise NotImplementedError - end - - # Returns an un-processed dashboard from the cache. - def raw_dashboard - Gitlab::Metrics::Dashboard::Cache.fetch(cache_key) { get_raw_dashboard } - end - - private - - # Determines whether users should be able to view - # dashboards at all. - def allowed? - Ability.allowed?(current_user, :read_environment, project) - end - - # Returns a new dashboard Hash, supplemented with DB info - def process_dashboard - Gitlab::Metrics::Dashboard::Processor - .new(project, params[:environment], raw_dashboard) - .process(insert_project_metrics: insert_project_metrics?) - end - - # @return [String] Relative filepath of the dashboard yml - def dashboard_path - params[:dashboard_path] - end - - # @return [Hash] an unmodified dashboard - def get_raw_dashboard - raise NotImplementedError - end - - # @return [String] - def cache_key - raise NotImplementedError - end - - # Determines whether custom metrics should be included - # in the processed output. - # @return [Boolean] - def insert_project_metrics? - false - end - end - end - end -end diff --git a/lib/gitlab/metrics/dashboard/dynamic_dashboard_service.rb b/lib/gitlab/metrics/dashboard/dynamic_dashboard_service.rb deleted file mode 100644 index 81ed8922e17..00000000000 --- a/lib/gitlab/metrics/dashboard/dynamic_dashboard_service.rb +++ /dev/null @@ -1,65 +0,0 @@ -# frozen_string_literal: true - -# Responsible for returning a filtered system dashboard -# containing only the default embedded metrics. In future, -# this class may be updated to support filtering to -# alternate metrics/panels. -# -# Why isn't this filtering in a processing stage? By filtering -# here, we ensure the dynamically-determined dashboard is cached. -# -# Use Gitlab::Metrics::Dashboard::Finder to retrive dashboards. -module Gitlab - module Metrics - module Dashboard - class DynamicDashboardService < Gitlab::Metrics::Dashboard::BaseService - # For the default filtering for embedded metrics, - # uses the 'id' key in dashboard-yml definition for - # identification. - DEFAULT_EMBEDDED_METRICS_IDENTIFIERS = %w( - system_metrics_kubernetes_container_memory_total - system_metrics_kubernetes_container_cores_total - ).freeze - - # Returns a new dashboard with only the matching - # metrics from the system dashboard, stripped of groups. - # @return [Hash] - def raw_dashboard - panels = panel_groups.each_with_object([]) do |group, panels| - matched_panels = group['panels'].select { |panel| matching_panel?(panel) } - - panels.concat(matched_panels) - end - - { 'panel_groups' => [{ 'panels' => panels }] } - end - - def cache_key - "dynamic_metrics_dashboard_#{metric_identifiers.join('_')}" - end - - private - - # Returns an array of the panels groups on the - # system dashboard - def panel_groups - Gitlab::Metrics::Dashboard::SystemDashboardService - .new(project, nil) - .raw_dashboard['panel_groups'] - end - - # Identifies a panel as "matching" if any metric ids in - # the panel is in the list of identifiers to collect. - def matching_panel?(panel) - panel['metrics'].any? do |metric| - metric_identifiers.include?(metric['id']) - end - end - - def metric_identifiers - DEFAULT_EMBEDDED_METRICS_IDENTIFIERS - end - end - end - end -end diff --git a/lib/gitlab/metrics/dashboard/finder.rb b/lib/gitlab/metrics/dashboard/finder.rb index d7491d1553d..1373830844b 100644 --- a/lib/gitlab/metrics/dashboard/finder.rb +++ b/lib/gitlab/metrics/dashboard/finder.rb @@ -47,22 +47,22 @@ module Gitlab private def service_for_path(dashboard_path, embedded:) - return dynamic_service if embedded + return embed_service if embedded return system_service if system_dashboard?(dashboard_path) project_service end def system_service - Gitlab::Metrics::Dashboard::SystemDashboardService + ::Metrics::Dashboard::SystemDashboardService end def project_service - Gitlab::Metrics::Dashboard::ProjectDashboardService + ::Metrics::Dashboard::ProjectDashboardService end - def dynamic_service - Gitlab::Metrics::Dashboard::DynamicDashboardService + def embed_service + ::Metrics::Dashboard::DefaultEmbedService end def system_dashboard?(filepath) diff --git a/lib/gitlab/metrics/dashboard/project_dashboard_service.rb b/lib/gitlab/metrics/dashboard/project_dashboard_service.rb deleted file mode 100644 index 5a1c4ecf886..00000000000 --- a/lib/gitlab/metrics/dashboard/project_dashboard_service.rb +++ /dev/null @@ -1,50 +0,0 @@ -# frozen_string_literal: true - -# Searches a projects repository for a metrics dashboard and formats the output. -# Expects any custom dashboards will be located in `.gitlab/dashboards` -# Use Gitlab::Metrics::Dashboard::Finder to retrive dashboards. -module Gitlab - module Metrics - module Dashboard - class ProjectDashboardService < Gitlab::Metrics::Dashboard::BaseService - DASHBOARD_ROOT = ".gitlab/dashboards" - - class << self - def all_dashboard_paths(project) - file_finder(project) - .list_files_for(DASHBOARD_ROOT) - .map do |filepath| - { - path: filepath, - display_name: name_for_path(filepath), - default: false - } - end - end - - def file_finder(project) - Gitlab::Template::Finders::RepoTemplateFinder.new(project, DASHBOARD_ROOT, '.yml') - end - - # Grabs the filepath after the base directory. - def name_for_path(filepath) - filepath.delete_prefix("#{DASHBOARD_ROOT}/") - end - end - - private - - # Searches the project repo for a custom-defined dashboard. - def get_raw_dashboard - yml = self.class.file_finder(project).read(dashboard_path) - - YAML.safe_load(yml) - end - - def cache_key - "project_#{project.id}_metrics_dashboard_#{dashboard_path}" - end - end - end - end -end diff --git a/lib/gitlab/metrics/dashboard/system_dashboard_service.rb b/lib/gitlab/metrics/dashboard/system_dashboard_service.rb deleted file mode 100644 index 82421572f4a..00000000000 --- a/lib/gitlab/metrics/dashboard/system_dashboard_service.rb +++ /dev/null @@ -1,49 +0,0 @@ -# frozen_string_literal: true - -# Fetches the system metrics dashboard and formats the output. -# Use Gitlab::Metrics::Dashboard::Finder to retrive dashboards. -module Gitlab - module Metrics - module Dashboard - class SystemDashboardService < Gitlab::Metrics::Dashboard::BaseService - SYSTEM_DASHBOARD_PATH = 'config/prometheus/common_metrics.yml' - SYSTEM_DASHBOARD_NAME = 'Default' - - class << self - def all_dashboard_paths(_project) - [{ - path: SYSTEM_DASHBOARD_PATH, - display_name: SYSTEM_DASHBOARD_NAME, - default: true - }] - end - - def system_dashboard?(filepath) - filepath == SYSTEM_DASHBOARD_PATH - end - end - - private - - def dashboard_path - SYSTEM_DASHBOARD_PATH - end - - # Returns the base metrics shipped with every GitLab service. - def get_raw_dashboard - yml = File.read(Rails.root.join(dashboard_path)) - - YAML.safe_load(yml) - end - - def cache_key - "metrics_dashboard_#{dashboard_path}" - end - - def insert_project_metrics? - true - end - end - end - end -end diff --git a/lib/gitlab/object_hierarchy.rb b/lib/gitlab/object_hierarchy.rb index 38b32770e90..c06f106ffe1 100644 --- a/lib/gitlab/object_hierarchy.rb +++ b/lib/gitlab/object_hierarchy.rb @@ -32,11 +32,6 @@ module Gitlab # Returns the maximum depth starting from the base # A base object with no children has a maximum depth of `1` def max_descendants_depth - unless hierarchy_supported? - # This makes the return value consistent with the case where hierarchy is supported - return descendants_base.exists? ? 1 : nil - end - base_and_descendants(with_depth: true).maximum(DEPTH_COLUMN) end @@ -66,8 +61,6 @@ module Gitlab # each parent. # rubocop: disable CodeReuse/ActiveRecord def base_and_ancestors(upto: nil, hierarchy_order: nil) - return ancestors_base unless hierarchy_supported? - recursive_query = base_and_ancestors_cte(upto, hierarchy_order).apply_to(model.all) recursive_query = recursive_query.order(depth: hierarchy_order) if hierarchy_order @@ -81,10 +74,6 @@ module Gitlab # When `with_depth` is `true`, a `depth` column is included where it starts with `1` for the base objects # and incremented as we go down the descendant tree def base_and_descendants(with_depth: false) - unless hierarchy_supported? - return with_depth ? descendants_base.select("1 as #{DEPTH_COLUMN}", objects_table[Arel.star]) : descendants_base - end - read_only(base_and_descendants_cte(with_depth: with_depth).apply_to(model.all)) end @@ -112,8 +101,6 @@ module Gitlab # If nested objects are not supported, ancestors_base is returned. # rubocop: disable CodeReuse/ActiveRecord def all_objects - return ancestors_base unless hierarchy_supported? - ancestors = base_and_ancestors_cte descendants = base_and_descendants_cte @@ -135,10 +122,6 @@ module Gitlab private - def hierarchy_supported? - Gitlab::Database.postgresql? - end - # rubocop: disable CodeReuse/ActiveRecord def base_and_ancestors_cte(stop_id = nil, hierarchy_order = nil) cte = SQL::RecursiveCTE.new(:base_and_ancestors) diff --git a/lib/gitlab/octokit/middleware.rb b/lib/gitlab/octokit/middleware.rb new file mode 100644 index 00000000000..2f762957d1b --- /dev/null +++ b/lib/gitlab/octokit/middleware.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +module Gitlab + module Octokit + class Middleware + def initialize(app) + @app = app + end + + def call(env) + Gitlab::UrlBlocker.validate!(env[:url], { allow_localhost: allow_local_requests?, allow_local_network: allow_local_requests? }) + + @app.call(env) + end + + private + + def allow_local_requests? + Gitlab::CurrentSettings.allow_local_requests_from_hooks_and_services? + end + end + end +end diff --git a/lib/gitlab/path_regex.rb b/lib/gitlab/path_regex.rb index a13b3f9e069..f96466b2b00 100644 --- a/lib/gitlab/path_regex.rb +++ b/lib/gitlab/path_regex.rb @@ -175,6 +175,10 @@ module Gitlab @project_git_route_regex ||= /#{project_route_regex}\.git/.freeze end + def project_wiki_git_route_regex + @project_wiki_git_route_regex ||= /#{PATH_REGEX_STR}\.wiki/.freeze + end + def full_namespace_path_regex @full_namespace_path_regex ||= %r{\A#{full_namespace_route_regex}/\z} end diff --git a/lib/gitlab/performance_bar/peek_query_tracker.rb b/lib/gitlab/performance_bar/peek_query_tracker.rb deleted file mode 100644 index 3a27e26eaba..00000000000 --- a/lib/gitlab/performance_bar/peek_query_tracker.rb +++ /dev/null @@ -1,45 +0,0 @@ -# frozen_string_literal: true - -# Inspired by https://github.com/peek/peek-pg/blob/master/lib/peek/views/pg.rb -# PEEK_DB_CLIENT is a constant set in config/initializers/peek.rb -module Gitlab - module PerformanceBar - module PeekQueryTracker - def sorted_queries - PEEK_DB_CLIENT.query_details - .sort { |a, b| b[:duration] <=> a[:duration] } - end - - def results - super.merge(queries: sorted_queries) - end - - private - - def setup_subscribers - super - - # Reset each counter when a new request starts - before_request do - PEEK_DB_CLIENT.query_details = [] - end - - subscribe('sql.active_record') do |_, start, finish, _, data| - if Gitlab::SafeRequestStore.store[:peek_enabled] - unless data[:cached] - backtrace = Gitlab::Profiler.clean_backtrace(caller) - track_query(data[:sql].strip, data[:binds], backtrace, start, finish) - end - end - end - end - - def track_query(raw_query, bindings, backtrace, start, finish) - duration = (finish - start) * 1000.0 - query_info = { duration: duration.round(3), sql: raw_query, backtrace: backtrace } - - PEEK_DB_CLIENT.query_details << query_info - end - end - end -end diff --git a/lib/gitlab/profiler.rb b/lib/gitlab/profiler.rb index 890228e5e78..615c0ec374c 100644 --- a/lib/gitlab/profiler.rb +++ b/lib/gitlab/profiler.rb @@ -166,7 +166,7 @@ module Gitlab [model, times.count, times.sum] end - summarised_load_times.sort_by(&:last).reverse.each do |(model, query_count, time)| + summarised_load_times.sort_by(&:last).reverse_each do |(model, query_count, time)| logger.info("#{model} total (#{query_count}): #{time.round(2)}ms") end end diff --git a/lib/gitlab/project_authorizations.rb b/lib/gitlab/project_authorizations.rb new file mode 100644 index 00000000000..a9270cd536e --- /dev/null +++ b/lib/gitlab/project_authorizations.rb @@ -0,0 +1,121 @@ +# frozen_string_literal: true + +# This class relies on Common Table Expressions to efficiently get all data, +# including data for nested groups. +module Gitlab + class ProjectAuthorizations + attr_reader :user + + # user - The User object for which to calculate the authorizations. + def initialize(user) + @user = user + end + + def calculate + cte = recursive_cte + cte_alias = cte.table.alias(Group.table_name) + projects = Project.arel_table + links = ProjectGroupLink.arel_table + + relations = [ + # The project a user has direct access to. + user.projects.select_for_project_authorization, + + # The personal projects of the user. + user.personal_projects.select_as_maintainer_for_project_authorization, + + # Projects that belong directly to any of the groups the user has + # access to. + Namespace + .unscoped + .select([alias_as_column(projects[:id], 'project_id'), + cte_alias[:access_level]]) + .from(cte_alias) + .joins(:projects), + + # Projects shared with any of the namespaces the user has access to. + Namespace + .unscoped + .select([ + links[:project_id], + least(cte_alias[:access_level], links[:group_access], 'access_level') + ]) + .from(cte_alias) + .joins('INNER JOIN project_group_links ON project_group_links.group_id = namespaces.id') + .joins('INNER JOIN projects ON projects.id = project_group_links.project_id') + .joins('INNER JOIN namespaces p_ns ON p_ns.id = projects.namespace_id') + .where('p_ns.share_with_group_lock IS FALSE') + ] + + ProjectAuthorization + .unscoped + .with + .recursive(cte.to_arel) + .select_from_union(relations) + end + + private + + # Builds a recursive CTE that gets all the groups the current user has + # access to, including any nested groups. + def recursive_cte + cte = Gitlab::SQL::RecursiveCTE.new(:namespaces_cte) + members = Member.arel_table + namespaces = Namespace.arel_table + + # Namespaces the user is a member of. + cte << user.groups + .select([namespaces[:id], members[:access_level]]) + .except(:order) + + # Sub groups of any groups the user is a member of. + cte << Group.select([ + namespaces[:id], + greatest(members[:access_level], cte.table[:access_level], 'access_level') + ]) + .joins(join_cte(cte)) + .joins(join_members) + .except(:order) + + cte + end + + # Builds a LEFT JOIN to join optional memberships onto the CTE. + def join_members + members = Member.arel_table + namespaces = Namespace.arel_table + + cond = members[:source_id] + .eq(namespaces[:id]) + .and(members[:source_type].eq('Namespace')) + .and(members[:requested_at].eq(nil)) + .and(members[:user_id].eq(user.id)) + + Arel::Nodes::OuterJoin.new(members, Arel::Nodes::On.new(cond)) + end + + # Builds an INNER JOIN to join namespaces onto the CTE. + def join_cte(cte) + namespaces = Namespace.arel_table + cond = cte.table[:id].eq(namespaces[:parent_id]) + + Arel::Nodes::InnerJoin.new(cte.table, Arel::Nodes::On.new(cond)) + end + + def greatest(left, right, column_alias) + sql_function('GREATEST', [left, right], column_alias) + end + + def least(left, right, column_alias) + sql_function('LEAST', [left, right], column_alias) + end + + def sql_function(name, args, column_alias) + alias_as_column(Arel::Nodes::NamedFunction.new(name, args), column_alias) + end + + def alias_as_column(value, alias_to) + Arel::Nodes::As.new(value, Arel::Nodes::SqlLiteral.new(alias_to)) + end + end +end diff --git a/lib/gitlab/project_authorizations/with_nested_groups.rb b/lib/gitlab/project_authorizations/with_nested_groups.rb deleted file mode 100644 index 2372a316ab0..00000000000 --- a/lib/gitlab/project_authorizations/with_nested_groups.rb +++ /dev/null @@ -1,125 +0,0 @@ -# frozen_string_literal: true - -module Gitlab - module ProjectAuthorizations - # Calculating new project authorizations when supporting nested groups. - # - # This class relies on Common Table Expressions to efficiently get all data, - # including data for nested groups. As a result this class can only be used - # on PostgreSQL. - class WithNestedGroups - attr_reader :user - - # user - The User object for which to calculate the authorizations. - def initialize(user) - @user = user - end - - def calculate - cte = recursive_cte - cte_alias = cte.table.alias(Group.table_name) - projects = Project.arel_table - links = ProjectGroupLink.arel_table - - relations = [ - # The project a user has direct access to. - user.projects.select_for_project_authorization, - - # The personal projects of the user. - user.personal_projects.select_as_maintainer_for_project_authorization, - - # Projects that belong directly to any of the groups the user has - # access to. - Namespace - .unscoped - .select([alias_as_column(projects[:id], 'project_id'), - cte_alias[:access_level]]) - .from(cte_alias) - .joins(:projects), - - # Projects shared with any of the namespaces the user has access to. - Namespace - .unscoped - .select([links[:project_id], - least(cte_alias[:access_level], - links[:group_access], - 'access_level')]) - .from(cte_alias) - .joins('INNER JOIN project_group_links ON project_group_links.group_id = namespaces.id') - .joins('INNER JOIN projects ON projects.id = project_group_links.project_id') - .joins('INNER JOIN namespaces p_ns ON p_ns.id = projects.namespace_id') - .where('p_ns.share_with_group_lock IS FALSE') - ] - - ProjectAuthorization - .unscoped - .with - .recursive(cte.to_arel) - .select_from_union(relations) - end - - private - - # Builds a recursive CTE that gets all the groups the current user has - # access to, including any nested groups. - def recursive_cte - cte = Gitlab::SQL::RecursiveCTE.new(:namespaces_cte) - members = Member.arel_table - namespaces = Namespace.arel_table - - # Namespaces the user is a member of. - cte << user.groups - .select([namespaces[:id], members[:access_level]]) - .except(:order) - - # Sub groups of any groups the user is a member of. - cte << Group.select([namespaces[:id], - greatest(members[:access_level], - cte.table[:access_level], 'access_level')]) - .joins(join_cte(cte)) - .joins(join_members) - .except(:order) - - cte - end - - # Builds a LEFT JOIN to join optional memberships onto the CTE. - def join_members - members = Member.arel_table - namespaces = Namespace.arel_table - - cond = members[:source_id] - .eq(namespaces[:id]) - .and(members[:source_type].eq('Namespace')) - .and(members[:requested_at].eq(nil)) - .and(members[:user_id].eq(user.id)) - - Arel::Nodes::OuterJoin.new(members, Arel::Nodes::On.new(cond)) - end - - # Builds an INNER JOIN to join namespaces onto the CTE. - def join_cte(cte) - namespaces = Namespace.arel_table - cond = cte.table[:id].eq(namespaces[:parent_id]) - - Arel::Nodes::InnerJoin.new(cte.table, Arel::Nodes::On.new(cond)) - end - - def greatest(left, right, column_alias) - sql_function('GREATEST', [left, right], column_alias) - end - - def least(left, right, column_alias) - sql_function('LEAST', [left, right], column_alias) - end - - def sql_function(name, args, column_alias) - alias_as_column(Arel::Nodes::NamedFunction.new(name, args), column_alias) - end - - def alias_as_column(value, alias_to) - Arel::Nodes::As.new(value, Arel::Nodes::SqlLiteral.new(alias_to)) - end - end - end -end diff --git a/lib/gitlab/project_authorizations/without_nested_groups.rb b/lib/gitlab/project_authorizations/without_nested_groups.rb deleted file mode 100644 index 50b41b17649..00000000000 --- a/lib/gitlab/project_authorizations/without_nested_groups.rb +++ /dev/null @@ -1,35 +0,0 @@ -# frozen_string_literal: true - -module Gitlab - module ProjectAuthorizations - # Calculating new project authorizations when not supporting nested groups. - class WithoutNestedGroups - attr_reader :user - - # user - The User object for which to calculate the authorizations. - def initialize(user) - @user = user - end - - def calculate - relations = [ - # Projects the user is a direct member of - user.projects.select_for_project_authorization, - - # Personal projects - user.personal_projects.select_as_maintainer_for_project_authorization, - - # Projects of groups the user is a member of - user.groups_projects.select_for_project_authorization, - - # Projects shared with groups the user is a member of - user.groups.joins(:shared_projects).select_for_project_authorization - ] - - ProjectAuthorization - .unscoped - .select_from_union(relations) - end - end - end -end diff --git a/lib/gitlab/project_template.rb b/lib/gitlab/project_template.rb index 99885be8755..dbf469a44c1 100644 --- a/lib/gitlab/project_template.rb +++ b/lib/gitlab/project_template.rb @@ -13,11 +13,15 @@ module Gitlab end def archive_path - Rails.root.join("vendor/project_templates/#{name}.tar.gz") + self.class.archive_directory.join(archive_filename) + end + + def archive_filename + "#{name}.tar.gz" end def clone_url - "https://gitlab.com/gitlab-org/project-templates/#{name}.git" + "#{preview}.git" end def ==(other) @@ -54,7 +58,7 @@ module Gitlab end def archive_directory - Rails.root.join("vendor_directory/project_templates") + Rails.root.join("vendor/project_templates") end end end diff --git a/lib/gitlab/push_options.rb b/lib/gitlab/push_options.rb index b96590af08e..682edfc4259 100644 --- a/lib/gitlab/push_options.rb +++ b/lib/gitlab/push_options.rb @@ -6,9 +6,11 @@ module Gitlab merge_request: { keys: [ :create, + :description, :merge_when_pipeline_succeeds, :remove_source_branch, - :target + :target, + :title ] }, ci: { diff --git a/lib/gitlab/quick_actions/command_definition.rb b/lib/gitlab/quick_actions/command_definition.rb index 93030fd454e..ebdae139315 100644 --- a/lib/gitlab/quick_actions/command_definition.rb +++ b/lib/gitlab/quick_actions/command_definition.rb @@ -3,8 +3,8 @@ module Gitlab module QuickActions class CommandDefinition - attr_accessor :name, :aliases, :description, :explanation, :params, - :condition_block, :parse_params_block, :action_block, :warning, :types + attr_accessor :name, :aliases, :description, :explanation, :execution_message, + :params, :condition_block, :parse_params_block, :action_block, :warning, :types def initialize(name, attributes = {}) @name = name @@ -13,6 +13,7 @@ module Gitlab @description = attributes[:description] || '' @warning = attributes[:warning] || '' @explanation = attributes[:explanation] || '' + @execution_message = attributes[:execution_message] || '' @params = attributes[:params] || [] @condition_block = attributes[:condition_block] @parse_params_block = attributes[:parse_params_block] @@ -48,13 +49,23 @@ module Gitlab end def execute(context, arg) - return if noop? || !available?(context) + return unless executable?(context) count_commands_executed_in(context) execute_block(action_block, context, arg) end + def execute_message(context, arg) + return unless executable?(context) + + if execution_message.respond_to?(:call) + execute_block(execution_message, context, arg) + else + execution_message + end + end + def to_h(context) desc = description if desc.respond_to?(:call) @@ -77,6 +88,10 @@ module Gitlab private + def executable?(context) + !noop? && available?(context) + end + def count_commands_executed_in(context) return unless context.respond_to?(:commands_executed_count=) diff --git a/lib/gitlab/quick_actions/commit_actions.rb b/lib/gitlab/quick_actions/commit_actions.rb index 1018910e8e9..49f5ddf24eb 100644 --- a/lib/gitlab/quick_actions/commit_actions.rb +++ b/lib/gitlab/quick_actions/commit_actions.rb @@ -16,6 +16,13 @@ module Gitlab _("Tags this commit to %{tag_name}.") % { tag_name: tag_name } end end + execution_message do |tag_name, message| + if message.present? + _("Tagged this commit to %{tag_name} with \"%{message}\".") % { tag_name: tag_name, message: message } + else + _("Tagged this commit to %{tag_name}.") % { tag_name: tag_name } + end + end params 'v1.2.3 <message>' parse_params do |tag_name_and_message| tag_name_and_message.split(' ', 2) diff --git a/lib/gitlab/quick_actions/dsl.rb b/lib/gitlab/quick_actions/dsl.rb index ecb2169151e..5abbd377642 100644 --- a/lib/gitlab/quick_actions/dsl.rb +++ b/lib/gitlab/quick_actions/dsl.rb @@ -66,6 +66,35 @@ module Gitlab @explanation = block_given? ? block : text end + # Allows to provide a message about quick action execution result, success or failure. + # This message is shown after quick action execution and after saving the note. + # + # Example: + # + # execution_message do |arguments| + # "Added label(s) #{arguments.join(' ')}" + # end + # command :command_key do |arguments| + # # Awesome code block + # end + # + # Note: The execution_message won't be executed unless the condition block returns true. + # execution_message block is executed always after the command block has run, + # for this reason if the condition block doesn't return true after the command block has + # run you need to set the @execution_message variable inside the command block instead as + # shown in the following example. + # + # Example using instance variable: + # + # command :command_key do |arguments| + # # Awesome code block + # @execution_message[:command_key] = 'command_key executed successfully' + # end + # + def execution_message(text = '', &block) + @execution_message = block_given? ? block : text + end + # Allows to define type(s) that must be met in order for the command # to be returned by `.command_names` & `.command_definitions`. # @@ -121,10 +150,16 @@ module Gitlab # comment. # It accepts aliases and takes a block. # + # You can also set the @execution_message instance variable, on conflicts with + # execution_message method the instance variable has precedence. + # # Example: # # command :my_command, :alias_for_my_command do |arguments| # # Awesome code block + # @updates[:my_command] = 'foo' + # + # @execution_message[:my_command] = 'my_command executed successfully' # end def command(*command_names, &block) define_command(CommandDefinition, *command_names, &block) @@ -158,6 +193,7 @@ module Gitlab description: @description, warning: @warning, explanation: @explanation, + execution_message: @execution_message, params: @params, condition_block: @condition_block, parse_params_block: @parse_params_block, @@ -173,6 +209,7 @@ module Gitlab @description = nil @explanation = nil + @execution_message = nil @params = nil @condition_block = nil @warning = nil diff --git a/lib/gitlab/quick_actions/issuable_actions.rb b/lib/gitlab/quick_actions/issuable_actions.rb index f7f89d4e897..b975a967d03 100644 --- a/lib/gitlab/quick_actions/issuable_actions.rb +++ b/lib/gitlab/quick_actions/issuable_actions.rb @@ -12,10 +12,16 @@ module Gitlab included do # Issue, MergeRequest, Epic: quick actions definitions desc do - "Close this #{quick_action_target.to_ability_name.humanize(capitalize: false)}" + _('Close this %{quick_action_target}') % + { quick_action_target: quick_action_target.to_ability_name.humanize(capitalize: false) } end explanation do - "Closes this #{quick_action_target.to_ability_name.humanize(capitalize: false)}." + _('Closes this %{quick_action_target}.') % + { quick_action_target: quick_action_target.to_ability_name.humanize(capitalize: false) } + end + execution_message do + _('Closed this %{quick_action_target}.') % + { quick_action_target: quick_action_target.to_ability_name.humanize(capitalize: false) } end types Issuable condition do @@ -28,10 +34,16 @@ module Gitlab end desc do - "Reopen this #{quick_action_target.to_ability_name.humanize(capitalize: false)}" + _('Reopen this %{quick_action_target}') % + { quick_action_target: quick_action_target.to_ability_name.humanize(capitalize: false) } end explanation do - "Reopens this #{quick_action_target.to_ability_name.humanize(capitalize: false)}." + _('Reopens this %{quick_action_target}.') % + { quick_action_target: quick_action_target.to_ability_name.humanize(capitalize: false) } + end + execution_message do + _('Reopened this %{quick_action_target}.') % + { quick_action_target: quick_action_target.to_ability_name.humanize(capitalize: false) } end types Issuable condition do @@ -45,7 +57,10 @@ module Gitlab desc _('Change title') explanation do |title_param| - _("Changes the title to \"%{title_param}\".") % { title_param: title_param } + _('Changes the title to "%{title_param}".') % { title_param: title_param } + end + execution_message do |title_param| + _('Changed the title to "%{title_param}".') % { title_param: title_param } end params '<New title>' types Issuable @@ -61,7 +76,10 @@ module Gitlab explanation do |labels_param| labels = find_label_references(labels_param) - "Adds #{labels.join(' ')} #{'label'.pluralize(labels.count)}." if labels.any? + if labels.any? + _("Adds %{labels} %{label_text}.") % + { labels: labels.join(' '), label_text: 'label'.pluralize(labels.count) } + end end params '~label1 ~"label 2"' types Issuable @@ -71,21 +89,15 @@ module Gitlab find_labels.any? end command :label do |labels_param| - label_ids = find_label_ids(labels_param) - - if label_ids.any? - @updates[:add_label_ids] ||= [] - @updates[:add_label_ids] += label_ids - - @updates[:add_label_ids].uniq! - end + run_label_command(labels: find_labels(labels_param), command: :label, updates_key: :add_label_ids) end desc _('Remove all or specific label(s)') explanation do |labels_param = nil| - if labels_param.present? - labels = find_label_references(labels_param) - "Removes #{labels.join(' ')} #{'label'.pluralize(labels.count)}." if labels.any? + label_references = labels_param.present? ? find_label_references(labels_param) : [] + if label_references.any? + _("Removes %{label_references} %{label_text}.") % + { label_references: label_references.join(' '), label_text: 'label'.pluralize(label_references.count) } else _('Removes all labels.') end @@ -99,7 +111,9 @@ module Gitlab end command :unlabel do |labels_param = nil| if labels_param.present? - label_ids = find_label_ids(labels_param) + labels = find_labels(labels_param) + label_ids = labels.map(&:id) + label_references = labels_to_reference(labels, :name) if label_ids.any? @updates[:remove_label_ids] ||= [] @@ -109,7 +123,10 @@ module Gitlab end else @updates[:label_ids] = [] + label_references = [] end + + @execution_message[:unlabel] = remove_label_message(label_references) end desc _('Replace all label(s)') @@ -125,18 +142,12 @@ module Gitlab current_user.can?(:"admin_#{quick_action_target.to_ability_name}", parent) end command :relabel do |labels_param| - label_ids = find_label_ids(labels_param) - - if label_ids.any? - @updates[:label_ids] ||= [] - @updates[:label_ids] += label_ids - - @updates[:label_ids].uniq! - end + run_label_command(labels: find_labels(labels_param), command: :relabel, updates_key: :label_ids) end desc _('Add a todo') explanation _('Adds a todo.') + execution_message _('Added a todo.') types Issuable condition do quick_action_target.persisted? && @@ -148,6 +159,7 @@ module Gitlab desc _('Mark to do as done') explanation _('Marks to do as done.') + execution_message _('Marked to do as done.') types Issuable condition do quick_action_target.persisted? && @@ -159,7 +171,12 @@ module Gitlab desc _('Subscribe') explanation do - "Subscribes to this #{quick_action_target.to_ability_name.humanize(capitalize: false)}." + _('Subscribes to this %{quick_action_target}.') % + { quick_action_target: quick_action_target.to_ability_name.humanize(capitalize: false) } + end + execution_message do + _('Subscribed to this %{quick_action_target}.') % + { quick_action_target: quick_action_target.to_ability_name.humanize(capitalize: false) } end types Issuable condition do @@ -172,7 +189,12 @@ module Gitlab desc _('Unsubscribe') explanation do - "Unsubscribes from this #{quick_action_target.to_ability_name.humanize(capitalize: false)}." + _('Unsubscribes from this %{quick_action_target}.') % + { quick_action_target: quick_action_target.to_ability_name.humanize(capitalize: false) } + end + execution_message do + _('Unsubscribed from this %{quick_action_target}.') % + { quick_action_target: quick_action_target.to_ability_name.humanize(capitalize: false) } end types Issuable condition do @@ -187,6 +209,9 @@ module Gitlab explanation do |name| _("Toggles :%{name}: emoji award.") % { name: name } if name end + execution_message do |name| + _("Toggled :%{name}: emoji award.") % { name: name } if name + end params ':emoji:' types Issuable condition do @@ -215,6 +240,41 @@ module Gitlab substitution :tableflip do |comment| "#{comment} #{TABLEFLIP}" end + + private + + def run_label_command(labels:, command:, updates_key:) + return if labels.empty? + + @updates[updates_key] ||= [] + @updates[updates_key] += labels.map(&:id) + @updates[updates_key].uniq! + + label_references = labels_to_reference(labels, :name) + @execution_message[command] = case command + when :relabel + _('Replaced all labels with %{label_references} %{label_text}.') % + { + label_references: label_references.join(' '), + label_text: 'label'.pluralize(label_references.count) + } + when :label + _('Added %{label_references} %{label_text}.') % + { + label_references: label_references.join(' '), + label_text: 'label'.pluralize(labels.count) + } + end + end + + def remove_label_message(label_references) + if label_references.any? + _("Removed %{label_references} %{label_text}.") % + { label_references: label_references.join(' '), label_text: 'label'.pluralize(label_references.count) } + else + _('Removed all labels.') + end + end end end end diff --git a/lib/gitlab/quick_actions/issue_actions.rb b/lib/gitlab/quick_actions/issue_actions.rb index 85e62f950c8..0868bd85600 100644 --- a/lib/gitlab/quick_actions/issue_actions.rb +++ b/lib/gitlab/quick_actions/issue_actions.rb @@ -12,6 +12,9 @@ module Gitlab explanation do |due_date| _("Sets the due date to %{due_date}.") % { due_date: due_date.strftime('%b %-d, %Y') } if due_date end + execution_message do |due_date| + _("Set the due date to %{due_date}.") % { due_date: due_date.strftime('%b %-d, %Y') } if due_date + end params '<in 2 days | this Friday | December 31st>' types Issue condition do @@ -27,6 +30,7 @@ module Gitlab desc _('Remove due date') explanation _('Removes the due date.') + execution_message _('Removed the due date.') types Issue condition do quick_action_target.persisted? && @@ -49,22 +53,27 @@ module Gitlab current_user.can?(:"update_#{quick_action_target.to_ability_name}", quick_action_target) && quick_action_target.project.boards.count == 1 end - # rubocop: disable CodeReuse/ActiveRecord command :board_move do |target_list_name| - label_ids = find_label_ids(target_list_name) + labels = find_labels(target_list_name) + label_ids = labels.map(&:id) if label_ids.size == 1 label_id = label_ids.first # Ensure this label corresponds to a list on the board - next unless Label.on_project_boards(quick_action_target.project_id).where(id: label_id).exists? + next unless Label.on_project_board?(quick_action_target.project_id, label_id) @updates[:remove_label_ids] = - quick_action_target.labels.on_project_boards(quick_action_target.project_id).where.not(id: label_id).pluck(:id) + quick_action_target.labels.on_project_boards(quick_action_target.project_id).where.not(id: label_id).pluck(:id) # rubocop: disable CodeReuse/ActiveRecord @updates[:add_label_ids] = [label_id] + + message = _("Moved issue to %{label} column in the board.") % { label: labels_to_reference(labels).first } + else + message = _('Move this issue failed because you need to specify only one label.') end + + @execution_message[:board_move] = message end - # rubocop: enable CodeReuse/ActiveRecord desc _('Mark this issue as a duplicate of another issue') explanation do |duplicate_reference| @@ -81,7 +90,13 @@ module Gitlab if canonical_issue.present? @updates[:canonical_issue_id] = canonical_issue.id + + message = _("Marked this issue as a duplicate of %{duplicate_param}.") % { duplicate_param: duplicate_param } + else + message = _('Mark as duplicate failed because referenced issue was not found') end + + @execution_message[:duplicate] = message end desc _('Move this issue to another project.') @@ -99,13 +114,22 @@ module Gitlab if target_project.present? @updates[:target_project] = target_project + + message = _("Moved this issue to %{path_to_project}.") % { path_to_project: target_project_path } + else + message = _("Move this issue failed because target project doesn't exists") end + + @execution_message[:move] = message end desc _('Make issue confidential.') explanation do _('Makes this issue confidential') end + execution_message do + _('Made this issue confidential') + end types Issue condition do current_user.can?(:"admin_#{quick_action_target.to_ability_name}", quick_action_target) @@ -119,7 +143,14 @@ module Gitlab if branch_name _("Creates branch '%{branch_name}' and a merge request to resolve this issue") % { branch_name: branch_name } else - "Creates a branch and a merge request to resolve this issue" + _('Creates a branch and a merge request to resolve this issue') + end + end + execution_message do |branch_name = nil| + if branch_name + _("Created branch '%{branch_name}' and a merge request to resolve this issue") % { branch_name: branch_name } + else + _('Created a branch and a merge request to resolve this issue') end end params "<branch name>" diff --git a/lib/gitlab/quick_actions/issue_and_merge_request_actions.rb b/lib/gitlab/quick_actions/issue_and_merge_request_actions.rb index e1579cfddc0..41ffd51cde8 100644 --- a/lib/gitlab/quick_actions/issue_and_merge_request_actions.rb +++ b/lib/gitlab/quick_actions/issue_and_merge_request_actions.rb @@ -9,12 +9,9 @@ module Gitlab included do # Issue, MergeRequest: quick actions definitions desc _('Assign') - # rubocop: disable CodeReuse/ActiveRecord explanation do |users| - users = quick_action_target.allows_multiple_assignees? ? users : users.take(1) - "Assigns #{users.map(&:to_reference).to_sentence}." + _('Assigns %{assignee_users_sentence}.') % { assignee_users_sentence: assignee_users_sentence(users) } end - # rubocop: enable CodeReuse/ActiveRecord params do quick_action_target.allows_multiple_assignees? ? '@user1 @user2' : '@user' end @@ -26,7 +23,10 @@ module Gitlab extract_users(assignee_param) end command :assign do |users| - next if users.empty? + if users.empty? + @execution_message[:assign] = _("Assign command failed because no user was found") + next + end if quick_action_target.allows_multiple_assignees? @updates[:assignee_ids] ||= quick_action_target.assignees.map(&:id) @@ -34,6 +34,8 @@ module Gitlab else @updates[:assignee_ids] = [users.first.id] end + + @execution_message[:assign] = _('Assigned %{assignee_users_sentence}.') % { assignee_users_sentence: assignee_users_sentence(users) } end desc do @@ -44,9 +46,14 @@ module Gitlab end end explanation do |users = nil| - assignees = quick_action_target.assignees - assignees &= users if users.present? && quick_action_target.allows_multiple_assignees? - "Removes #{'assignee'.pluralize(assignees.size)} #{assignees.map(&:to_reference).to_sentence}." + assignees = assignees_for_removal(users) + _("Removes %{assignee_text} %{assignee_references}.") % + { assignee_text: 'assignee'.pluralize(assignees.size), assignee_references: assignees.map(&:to_reference).to_sentence } + end + execution_message do |users = nil| + assignees = assignees_for_removal(users) + _("Removed %{assignee_text} %{assignee_references}.") % + { assignee_text: 'assignee'.pluralize(assignees.size), assignee_references: assignees.map(&:to_reference).to_sentence } end params do quick_action_target.allows_multiple_assignees? ? '@user1 @user2' : '' @@ -74,6 +81,9 @@ module Gitlab explanation do |milestone| _("Sets the milestone to %{milestone_reference}.") % { milestone_reference: milestone.to_reference } if milestone end + execution_message do |milestone| + _("Set the milestone to %{milestone_reference}.") % { milestone_reference: milestone.to_reference } if milestone + end params '%"milestone"' types Issue, MergeRequest condition do @@ -92,6 +102,9 @@ module Gitlab explanation do _("Removes %{milestone_reference} milestone.") % { milestone_reference: quick_action_target.milestone.to_reference(format: :name) } end + execution_message do + _("Removed %{milestone_reference} milestone.") % { milestone_reference: quick_action_target.milestone.to_reference(format: :name) } + end types Issue, MergeRequest condition do quick_action_target.persisted? && @@ -116,17 +129,22 @@ module Gitlab extract_references(issuable_param, :merge_request).first end command :copy_metadata do |source_issuable| - if source_issuable.present? && source_issuable.project.id == quick_action_target.project.id + if can_copy_metadata?(source_issuable) @updates[:add_label_ids] = source_issuable.labels.map(&:id) @updates[:milestone_id] = source_issuable.milestone.id if source_issuable.milestone + + @execution_message[:copy_metadata] = _("Copied labels and milestone from %{source_issuable_reference}.") % { source_issuable_reference: source_issuable.to_reference } end end desc _('Set time estimate') explanation do |time_estimate| - time_estimate = Gitlab::TimeTrackingFormatter.output(time_estimate) - - _("Sets time estimate to %{time_estimate}.") % { time_estimate: time_estimate } if time_estimate + formatted_time_estimate = format_time_estimate(time_estimate) + _("Sets time estimate to %{time_estimate}.") % { time_estimate: formatted_time_estimate } if formatted_time_estimate + end + execution_message do |time_estimate| + formatted_time_estimate = format_time_estimate(time_estimate) + _("Set time estimate to %{time_estimate}.") % { time_estimate: formatted_time_estimate } if formatted_time_estimate end params '<1w 3d 2h 14m>' types Issue, MergeRequest @@ -144,18 +162,12 @@ module Gitlab desc _('Add or subtract spent time') explanation do |time_spent, time_spent_date| - if time_spent - if time_spent > 0 - verb = _('Adds') - value = time_spent - else - verb = _('Subtracts') - value = -time_spent - end - - _("%{verb} %{time_spent_value} spent time.") % { verb: verb, time_spent_value: Gitlab::TimeTrackingFormatter.output(value) } - end + spend_time_message(time_spent, time_spent_date, false) end + execution_message do |time_spent, time_spent_date| + spend_time_message(time_spent, time_spent_date, true) + end + params '<time(1h30m | -1h30m)> <date(YYYY-MM-DD)>' types Issue, MergeRequest condition do @@ -176,6 +188,7 @@ module Gitlab desc _('Remove time estimate') explanation _('Removes time estimate.') + execution_message _('Removed time estimate.') types Issue, MergeRequest condition do quick_action_target.persisted? && @@ -187,6 +200,7 @@ module Gitlab desc _('Remove spent time') explanation _('Removes spent time.') + execution_message _('Removed spent time.') condition do quick_action_target.persisted? && current_user.can?(:"admin_#{quick_action_target.to_ability_name}", project) @@ -198,6 +212,7 @@ module Gitlab desc _("Lock the discussion") explanation _("Locks the discussion") + execution_message _("Locked the discussion") types Issue, MergeRequest condition do quick_action_target.persisted? && @@ -210,6 +225,7 @@ module Gitlab desc _("Unlock the discussion") explanation _("Unlocks the discussion") + execution_message _("Unlocked the discussion") types Issue, MergeRequest condition do quick_action_target.persisted? && @@ -219,6 +235,47 @@ module Gitlab command :unlock do @updates[:discussion_locked] = false end + + private + + def assignee_users_sentence(users) + if quick_action_target.allows_multiple_assignees? + users + else + [users.first] + end.map(&:to_reference).to_sentence + end + + def assignees_for_removal(users) + assignees = quick_action_target.assignees + if users.present? && quick_action_target.allows_multiple_assignees? + assignees & users + else + assignees + end + end + + def can_copy_metadata?(source_issuable) + source_issuable.present? && source_issuable.project_id == quick_action_target.project_id + end + + def format_time_estimate(time_estimate) + Gitlab::TimeTrackingFormatter.output(time_estimate) + end + + def spend_time_message(time_spent, time_spent_date, paste_tense) + return unless time_spent + + if time_spent > 0 + verb = paste_tense ? _('Added') : _('Adds') + value = time_spent + else + verb = paste_tense ? _('Subtracted') : _('Subtracts') + value = -time_spent + end + + _("%{verb} %{time_spent_value} spent time.") % { verb: verb, time_spent_value: format_time_estimate(value) } + end end end end diff --git a/lib/gitlab/quick_actions/merge_request_actions.rb b/lib/gitlab/quick_actions/merge_request_actions.rb index bade59182a1..e9127095a0d 100644 --- a/lib/gitlab/quick_actions/merge_request_actions.rb +++ b/lib/gitlab/quick_actions/merge_request_actions.rb @@ -8,8 +8,9 @@ module Gitlab included do # MergeRequest only quick actions definitions - desc 'Merge (when the pipeline succeeds)' - explanation 'Merges this merge request when the pipeline succeeds.' + desc _('Merge (when the pipeline succeeds)') + explanation _('Merges this merge request when the pipeline succeeds.') + execution_message _('Scheduled to merge this merge request when the pipeline succeeds.') types MergeRequest condition do last_diff_sha = params && params[:merge_request_diff_head_sha] @@ -22,10 +23,22 @@ module Gitlab desc 'Toggle the Work In Progress status' explanation do - verb = quick_action_target.work_in_progress? ? 'Unmarks' : 'Marks' noun = quick_action_target.to_ability_name.humanize(capitalize: false) - "#{verb} this #{noun} as Work In Progress." + if quick_action_target.work_in_progress? + _("Unmarks this %{noun} as Work In Progress.") + else + _("Marks this %{noun} as Work In Progress.") + end % { noun: noun } end + execution_message do + noun = quick_action_target.to_ability_name.humanize(capitalize: false) + if quick_action_target.work_in_progress? + _("Unmarked this %{noun} as Work In Progress.") + else + _("Marked this %{noun} as Work In Progress.") + end % { noun: noun } + end + types MergeRequest condition do quick_action_target.respond_to?(:work_in_progress?) && @@ -36,9 +49,12 @@ module Gitlab @updates[:wip_event] = quick_action_target.work_in_progress? ? 'unwip' : 'wip' end - desc 'Set target branch' + desc _('Set target branch') explanation do |branch_name| - "Sets target branch to #{branch_name}." + _('Sets target branch to %{branch_name}.') % { branch_name: branch_name } + end + execution_message do |branch_name| + _('Set target branch to %{branch_name}.') % { branch_name: branch_name } end params '<Local branch name>' types MergeRequest diff --git a/lib/gitlab/regex.rb b/lib/gitlab/regex.rb index e43147a3f37..21614ea003e 100644 --- a/lib/gitlab/regex.rb +++ b/lib/gitlab/regex.rb @@ -94,6 +94,12 @@ module Gitlab }mx end + # Based on Jira's project key format + # https://confluence.atlassian.com/adminjiraserver073/changing-the-project-key-format-861253229.html + def jira_issue_key_regex + @jira_issue_key_regex ||= /[A-Z][A-Z_0-9]+-\d+/ + end + def jira_transition_id_regex @jira_transition_id_regex ||= /\d+/ end diff --git a/lib/gitlab/rugged_instrumentation.rb b/lib/gitlab/rugged_instrumentation.rb index 70c06e8b308..8bb8c547ae1 100644 --- a/lib/gitlab/rugged_instrumentation.rb +++ b/lib/gitlab/rugged_instrumentation.rb @@ -24,7 +24,24 @@ module Gitlab end def self.active? - Gitlab::SafeRequestStore.active? + SafeRequestStore.active? + end + + def self.peek_enabled? + SafeRequestStore[:peek_enabled] + end + + def self.add_call_details(details) + return unless peek_enabled? + + Gitlab::SafeRequestStore[:rugged_call_details] ||= [] + Gitlab::SafeRequestStore[:rugged_call_details] << details + end + + def self.list_call_details + return [] unless peek_enabled? + + Gitlab::SafeRequestStore[:rugged_call_details] || [] end end end diff --git a/lib/gitlab/sherlock/query.rb b/lib/gitlab/sherlock/query.rb index 159ce27e702..cbd89b7629f 100644 --- a/lib/gitlab/sherlock/query.rb +++ b/lib/gitlab/sherlock/query.rb @@ -96,12 +96,7 @@ module Gitlab private def raw_explain(query) - explain = - if Gitlab::Database.postgresql? - "EXPLAIN ANALYZE #{query};" - else - "EXPLAIN #{query};" - end + explain = "EXPLAIN ANALYZE #{query};" ActiveRecord::Base.connection.execute(explain) end diff --git a/lib/gitlab/sidekiq_middleware/memory_killer.rb b/lib/gitlab/sidekiq_middleware/memory_killer.rb index 671d795ec33..4b10f921ed8 100644 --- a/lib/gitlab/sidekiq_middleware/memory_killer.rb +++ b/lib/gitlab/sidekiq_middleware/memory_killer.rb @@ -14,9 +14,12 @@ module Gitlab # shut Sidekiq down MUTEX = Mutex.new + attr_reader :worker + def call(worker, job, queue) yield + @worker = worker current_rss = get_rss return unless MAX_RSS > 0 && current_rss > MAX_RSS @@ -25,9 +28,11 @@ module Gitlab # Return if another thread is already waiting to shut Sidekiq down next unless MUTEX.try_lock - Sidekiq.logger.warn "Sidekiq worker PID-#{pid} current RSS #{current_rss}"\ - " exceeds maximum RSS #{MAX_RSS} after finishing job #{worker.class} JID-#{job['jid']}" - Sidekiq.logger.warn "Sidekiq worker PID-#{pid} will stop fetching new jobs in #{GRACE_TIME} seconds, and will be shut down #{SHUTDOWN_WAIT} seconds later" + warn("Sidekiq worker PID-#{pid} current RSS #{current_rss}"\ + " exceeds maximum RSS #{MAX_RSS} after finishing job #{worker.class} JID-#{job['jid']}") + + warn("Sidekiq worker PID-#{pid} will stop fetching new jobs"\ + " in #{GRACE_TIME} seconds, and will be shut down #{SHUTDOWN_WAIT} seconds later") # Wait `GRACE_TIME` to give the memory intensive job time to finish. # Then, tell Sidekiq to stop fetching new jobs. @@ -59,24 +64,28 @@ module Gitlab def wait_and_signal_pgroup(time, signal, explanation) return wait_and_signal(time, signal, explanation) unless Process.getpgrp == pid - Sidekiq.logger.warn "waiting #{time} seconds before sending Sidekiq worker PGRP-#{pid} #{signal} (#{explanation})" + warn("waiting #{time} seconds before sending Sidekiq worker PGRP-#{pid} #{signal} (#{explanation})", signal: signal) sleep(time) - Sidekiq.logger.warn "sending Sidekiq worker PGRP-#{pid} #{signal} (#{explanation})" + warn("sending Sidekiq worker PGRP-#{pid} #{signal} (#{explanation})", signal: signal) Process.kill(signal, 0) end def wait_and_signal(time, signal, explanation) - Sidekiq.logger.warn "waiting #{time} seconds before sending Sidekiq worker PID-#{pid} #{signal} (#{explanation})" + warn("waiting #{time} seconds before sending Sidekiq worker PID-#{pid} #{signal} (#{explanation})", signal: signal) sleep(time) - Sidekiq.logger.warn "sending Sidekiq worker PID-#{pid} #{signal} (#{explanation})" + warn("sending Sidekiq worker PID-#{pid} #{signal} (#{explanation})", signal: signal) Process.kill(signal, pid) end def pid Process.pid end + + def warn(message, signal: nil) + Sidekiq.logger.warn(class: worker.class, pid: pid, signal: signal, message: message) + end end end end diff --git a/lib/gitlab/sidekiq_middleware/metrics.rb b/lib/gitlab/sidekiq_middleware/metrics.rb new file mode 100644 index 00000000000..b06ffa9c121 --- /dev/null +++ b/lib/gitlab/sidekiq_middleware/metrics.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +module Gitlab + module SidekiqMiddleware + class Metrics + def initialize + @metrics = init_metrics + end + + def call(_worker, job, queue) + labels = create_labels(queue) + @metrics[:sidekiq_running_jobs].increment(labels, 1) + + if job['retry_count'].present? + @metrics[:sidekiq_jobs_retried_total].increment(labels, 1) + end + + realtime = Benchmark.realtime do + yield + end + + @metrics[:sidekiq_jobs_completion_seconds].observe(labels, realtime) + rescue Exception # rubocop: disable Lint/RescueException + @metrics[:sidekiq_jobs_failed_total].increment(labels, 1) + raise + ensure + @metrics[:sidekiq_running_jobs].increment(labels, -1) + end + + private + + def init_metrics + { + sidekiq_jobs_completion_seconds: ::Gitlab::Metrics.histogram(:sidekiq_jobs_completion_seconds, 'Seconds to complete sidekiq job'), + sidekiq_jobs_failed_total: ::Gitlab::Metrics.counter(:sidekiq_jobs_failed_total, 'Sidekiq jobs failed'), + sidekiq_jobs_retried_total: ::Gitlab::Metrics.counter(:sidekiq_jobs_retried_total, 'Sidekiq jobs retried'), + sidekiq_running_jobs: ::Gitlab::Metrics.gauge(:sidekiq_running_jobs, 'Number of Sidekiq jobs running', {}, :livesum) + } + end + + def create_labels(queue) + { + queue: queue + } + end + end + end +end diff --git a/lib/gitlab/submodule_links.rb b/lib/gitlab/submodule_links.rb index a6c0369d864..18fd604a3b0 100644 --- a/lib/gitlab/submodule_links.rb +++ b/lib/gitlab/submodule_links.rb @@ -9,7 +9,7 @@ module Gitlab end def for(submodule, sha) - submodule_url = submodule_url_for(sha)[submodule.path] + submodule_url = submodule_url_for(sha, submodule.path) SubmoduleHelper.submodule_links_for_url(submodule.id, submodule_url, repository) end @@ -17,10 +17,15 @@ module Gitlab attr_reader :repository - def submodule_url_for(sha) - strong_memoize(:"submodule_links_for_#{sha}") do + def submodule_urls_for(sha) + strong_memoize(:"submodule_urls_for_#{sha}") do repository.submodule_urls_for(sha) end end + + def submodule_url_for(sha, path) + urls = submodule_urls_for(sha) + urls && urls[path] + end end end diff --git a/lib/gitlab/url_blocker.rb b/lib/gitlab/url_blocker.rb index f6b2e2acf16..9c35d200dcb 100644 --- a/lib/gitlab/url_blocker.rb +++ b/lib/gitlab/url_blocker.rb @@ -45,18 +45,21 @@ module Gitlab ascii_only: ascii_only ) + normalized_hostname = uri.normalized_host hostname = uri.hostname port = get_port(uri) address_info = get_address_info(hostname, port) return [uri, nil] unless address_info - protected_uri_with_hostname = enforce_uri_hostname(address_info, uri, hostname, dns_rebind_protection) + ip_address = ip_address(address_info) + protected_uri_with_hostname = enforce_uri_hostname(ip_address, uri, hostname, dns_rebind_protection) # Allow url from the GitLab instance itself but only for the configured hostname and ports return protected_uri_with_hostname if internal?(uri) validate_local_request( + normalized_hostname: normalized_hostname, address_info: address_info, allow_localhost: allow_localhost, allow_local_network: allow_local_network @@ -83,10 +86,7 @@ module Gitlab # # The original hostname is used to validate the SSL, given in that scenario # we'll be making the request to the IP address, instead of using the hostname. - def enforce_uri_hostname(addrs_info, uri, hostname, dns_rebind_protection) - address = addrs_info.first - ip_address = address&.ip_address - + def enforce_uri_hostname(ip_address, uri, hostname, dns_rebind_protection) return [uri, nil] unless dns_rebind_protection && ip_address && ip_address != hostname uri = uri.dup @@ -94,6 +94,10 @@ module Gitlab [uri, hostname] end + def ip_address(address_info) + address_info.first&.ip_address + end + def validate_uri(uri:, schemes:, ports:, enforce_sanitization:, enforce_user:, ascii_only:) validate_html_tags(uri) if enforce_sanitization @@ -111,11 +115,30 @@ module Gitlab addr.ipv6_v4mapped? ? addr.ipv6_to_ipv4 : addr end rescue SocketError + # In the test suite we use a lot of mocked urls that are either invalid or + # don't exist. In order to avoid modifying a ton of tests and factories + # we allow invalid urls unless the environment variable RSPEC_ALLOW_INVALID_URLS + # is not true + return if Rails.env.test? && ENV['RSPEC_ALLOW_INVALID_URLS'] == 'true' + + # If the addr can't be resolved or the url is invalid (i.e http://1.1.1.1.1) + # we block the url + raise BlockedUrlError, "Host cannot be resolved or invalid" end - def validate_local_request(address_info:, allow_localhost:, allow_local_network:) + def validate_local_request( + normalized_hostname:, + address_info:, + allow_localhost:, + allow_local_network:) return if allow_local_network && allow_localhost + ip_whitelist, domain_whitelist = + Gitlab::CurrentSettings.outbound_local_requests_whitelist_arrays + + return if local_domain_whitelisted?(domain_whitelist, normalized_hostname) || + local_ip_whitelisted?(ip_whitelist, ip_address(address_info)) + unless allow_localhost validate_localhost(address_info) validate_loopback(address_info) @@ -231,6 +254,16 @@ module Gitlab (uri.port.blank? || uri.port == config.gitlab_shell.ssh_port) end + def local_ip_whitelisted?(ip_whitelist, ip_string) + ip_obj = Gitlab::Utils.string_to_ip_object(ip_string) + + ip_whitelist.any? { |ip| ip.include?(ip_obj) } + end + + def local_domain_whitelisted?(domain_whitelist, domain_string) + domain_whitelist.include?(domain_string) + end + def config Gitlab.config end diff --git a/lib/gitlab/usage_data.rb b/lib/gitlab/usage_data.rb index db1086c9cae..d5657c474c8 100644 --- a/lib/gitlab/usage_data.rb +++ b/lib/gitlab/usage_data.rb @@ -137,8 +137,11 @@ module Gitlab # @return [Array<#totals>] An array of objects that respond to `#totals` def usage_data_counters - [Gitlab::UsageDataCounters::WikiPageCounter, - Gitlab::UsageDataCounters::WebIdeCounter] + [ + Gitlab::UsageDataCounters::WikiPageCounter, + Gitlab::UsageDataCounters::WebIdeCounter, + Gitlab::UsageDataCounters::SearchCounter + ] end def components_usage_data diff --git a/lib/gitlab/usage_data_counters/search_counter.rb b/lib/gitlab/usage_data_counters/search_counter.rb new file mode 100644 index 00000000000..5f0735347e1 --- /dev/null +++ b/lib/gitlab/usage_data_counters/search_counter.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +module Gitlab + module UsageDataCounters + class SearchCounter + extend RedisCounter + + NAVBAR_SEARCHES_COUNT_KEY = 'NAVBAR_SEARCHES_COUNT' + + class << self + def increment_navbar_searches_count + increment(NAVBAR_SEARCHES_COUNT_KEY) + end + + def total_navbar_searches_count + total_count(NAVBAR_SEARCHES_COUNT_KEY) + end + + def totals + { + navbar_searches: total_navbar_searches_count + } + end + end + end + end +end diff --git a/lib/gitlab/utils.rb b/lib/gitlab/utils.rb index 16ec8a8bb28..c66ce0434a4 100644 --- a/lib/gitlab/utils.rb +++ b/lib/gitlab/utils.rb @@ -22,7 +22,7 @@ module Gitlab end def force_utf8(str) - str.force_encoding(Encoding::UTF_8) + str.dup.force_encoding(Encoding::UTF_8) end def ensure_utf8_size(str, bytes:) @@ -131,5 +131,12 @@ module Gitlab data end end + + def string_to_ip_object(str) + return unless str + + IPAddr.new(str) + rescue IPAddr::InvalidAddressError + end end end diff --git a/lib/gitlab/utils/sanitize_node_link.rb b/lib/gitlab/utils/sanitize_node_link.rb new file mode 100644 index 00000000000..620d71a7814 --- /dev/null +++ b/lib/gitlab/utils/sanitize_node_link.rb @@ -0,0 +1,61 @@ +# frozen_string_literal: true + +require_dependency 'gitlab/utils' + +module Gitlab + module Utils + module SanitizeNodeLink + UNSAFE_PROTOCOLS = %w(data javascript vbscript).freeze + ATTRS_TO_SANITIZE = %w(href src data-src).freeze + + def remove_unsafe_links(env, remove_invalid_links: true) + node = env[:node] + + sanitize_node(node: node, remove_invalid_links: remove_invalid_links) + + # HTML entities such as <video></video> have scannable attrs in + # children elements, which also need to be sanitized. + # + node.children.each do |child_node| + sanitize_node(node: child_node, remove_invalid_links: remove_invalid_links) + end + end + + # Remove all invalid scheme characters before checking against the + # list of unsafe protocols. + # + # See https://tools.ietf.org/html/rfc3986#section-3.1 + # + def safe_protocol?(scheme) + return false unless scheme + + scheme = scheme + .strip + .downcase + .gsub(/[^A-Za-z\+\.\-]+/, '') + + UNSAFE_PROTOCOLS.none?(scheme) + end + + private + + def sanitize_node(node:, remove_invalid_links: true) + ATTRS_TO_SANITIZE.each do |attr| + next unless node.has_attribute?(attr) + + begin + node[attr] = node[attr].strip + uri = Addressable::URI.parse(node[attr]) + + next unless uri.scheme + next if safe_protocol?(uri.scheme) + + node.remove_attribute(attr) + rescue Addressable::URI::InvalidURIError + node.remove_attribute(attr) if remove_invalid_links + end + end + end + end + end +end diff --git a/lib/gitlab/zoom_link_extractor.rb b/lib/gitlab/zoom_link_extractor.rb index d9994898a08..7ac14eb2d4f 100644 --- a/lib/gitlab/zoom_link_extractor.rb +++ b/lib/gitlab/zoom_link_extractor.rb @@ -17,5 +17,9 @@ module Gitlab def links @text.scan(ZOOM_REGEXP) end + + def match? + ZOOM_REGEXP.match?(@text) + end end end diff --git a/lib/peek/rblineprof/custom_controller_helpers.rb b/lib/peek/rblineprof/custom_controller_helpers.rb deleted file mode 100644 index 581cc6a37b4..00000000000 --- a/lib/peek/rblineprof/custom_controller_helpers.rb +++ /dev/null @@ -1,124 +0,0 @@ -# frozen_string_literal: true - -module Peek - module Rblineprof - module CustomControllerHelpers - extend ActiveSupport::Concern - - # This will become useless once https://github.com/peek/peek-rblineprof/pull/5 - # is merged - def pygmentize(file_name, code, lexer = nil) - if lexer.present? - Gitlab::Highlight.highlight(file_name, code) - else - "<pre>#{Rack::Utils.escape_html(code)}</pre>" - end - end - - # rubocop:disable all - def inject_rblineprof - ret = nil - profile = lineprof(rblineprof_profiler_regex) do - ret = yield - end - - if response.content_type =~ %r|text/html| - sort = params[:lineprofiler_sort] - mode = params[:lineprofiler_mode] || 'cpu' - min = (params[:lineprofiler_min] || 5).to_i * 1000 - summary = params[:lineprofiler_summary] - - # Sort each file by the longest calculated time - per_file = profile.map do |file, lines| - total, child, excl, total_cpu, child_cpu, excl_cpu = lines[0] - - wall = summary == 'exclusive' ? excl : total - cpu = summary == 'exclusive' ? excl_cpu : total_cpu - idle = summary == 'exclusive' ? (excl - excl_cpu) : (total - total_cpu) - - [ - file, lines, - wall, cpu, idle, - sort == 'idle' ? idle : sort == 'cpu' ? cpu : wall - ] - end.sort_by{ |a,b,c,d,e,f| -f } - - output = ["<div class='modal-dialog modal-xl'><div class='modal-content'>"] - output << "<div class='modal-header'>" - output << "<h4>Line profiling: #{human_description(params[:lineprofiler])}</h4>" - output << "<button class='close' type='button' data-dismiss='modal' aria-label='close'><span aria-hidden='true'>×</span></button>" - output << "</div>" - output << "<div class='modal-body'>" - - per_file.each do |file_name, lines, file_wall, file_cpu, file_idle, file_sort| - output << "<div class='peek-rblineprof-file'><div class='heading'>" - - show_src = file_sort > min - tmpl = show_src ? "<a href='#' class='js-lineprof-file'>%s</a>" : "%s" - - if mode == 'cpu' - output << sprintf("<span class='duration'>% 8.1fms + % 8.1fms</span> #{tmpl}", file_cpu / 1000.0, file_idle / 1000.0, file_name.sub(Rails.root.to_s + '/', '')) - else - output << sprintf("<span class='duration'>% 8.1fms</span> #{tmpl}", file_wall/1000.0, file_name.sub(Rails.root.to_s + '/', '')) - end - - output << "</div>" # .heading - - next unless show_src - - output << "<div class='data'>" - code = [] - times = [] - File.readlines(file_name).each_with_index do |line, i| - code << line - wall, cpu, calls = lines[i + 1] - - if calls && calls > 0 - if mode == 'cpu' - idle = wall - cpu - times << sprintf("% 8.1fms + % 8.1fms (% 5d)", cpu / 1000.0, idle / 1000.0, calls) - else - times << sprintf("% 8.1fms (% 5d)", wall / 1000.0, calls) - end - else - times << ' ' - end - end - output << "<pre class='duration'>#{times.join("\n")}</pre>" - # The following line was changed from - # https://github.com/peek/peek-rblineprof/blob/8d3b7a283a27de2f40abda45974516693d882258/lib/peek/rblineprof/controller_helpers.rb#L125 - # This will become useless once https://github.com/peek/peek-rblineprof/pull/16 - # is merged and is implemented. - output << "<pre class='code highlight white'>#{pygmentize(file_name, code.join, 'ruby')}</pre>" - output << "</div></div>" # .data then .peek-rblineprof-file - end - - output << "</div></div></div>" - - response.body += "<div class='modal' id='modal-peek-line-profile' tabindex=-1>#{output.join}</div>".html_safe - end - - ret - end - - private - - def human_description(lineprofiler_param) - case lineprofiler_param - when 'app' - 'app/ & lib/' - when 'views' - 'app/view/' - when 'gems' - 'vendor/gems' - when 'all' - 'everything in Rails.root' - when 'stdlib' - 'everything in the Ruby standard library' - else - 'app/, config/, lib/, vendor/ & plugin/' - end - end - end - end -end diff --git a/lib/peek/views/active_record.rb b/lib/peek/views/active_record.rb new file mode 100644 index 00000000000..2d78818630d --- /dev/null +++ b/lib/peek/views/active_record.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +module Peek + module Views + class ActiveRecord < DetailedView + private + + def setup_subscribers + super + + subscribe('sql.active_record') do |_, start, finish, _, data| + if Gitlab::SafeRequestStore.store[:peek_enabled] + unless data[:cached] + detail_store << { + duration: finish - start, + sql: data[:sql].strip, + backtrace: Gitlab::Profiler.clean_backtrace(caller) + } + end + end + end + end + end + end +end diff --git a/lib/peek/views/detailed_view.rb b/lib/peek/views/detailed_view.rb new file mode 100644 index 00000000000..f4ca1cb5075 --- /dev/null +++ b/lib/peek/views/detailed_view.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +module Peek + module Views + class DetailedView < View + def results + { + duration: formatted_duration, + calls: calls, + details: details + } + end + + def detail_store + ::Gitlab::SafeRequestStore["#{key}_call_details"] ||= [] + end + + private + + def duration + detail_store.map { |entry| entry[:duration] }.sum # rubocop:disable CodeReuse/ActiveRecord + end + + def calls + detail_store.count + end + + def call_details + detail_store + end + + def format_call_details(call) + call.merge(duration: (call[:duration] * 1000).round(3)) + end + + def details + call_details + .sort { |a, b| b[:duration] <=> a[:duration] } + .map(&method(:format_call_details)) + end + + def formatted_duration + ms = duration * 1000 + + if ms >= 1000 + "%.2fms" % ms + else + "%.0fms" % ms + end + end + end + end +end diff --git a/lib/peek/views/gitaly.rb b/lib/peek/views/gitaly.rb index 30f95a10024..6ad6ddfd89d 100644 --- a/lib/peek/views/gitaly.rb +++ b/lib/peek/views/gitaly.rb @@ -2,7 +2,9 @@ module Peek module Views - class Gitaly < View + class Gitaly < DetailedView + private + def duration ::Gitlab::GitalyClient.query_time end @@ -11,36 +13,14 @@ module Peek ::Gitlab::GitalyClient.get_request_count end - def results - { - duration: formatted_duration, - calls: calls, - details: details - } - end - - private - - def details + def call_details ::Gitlab::GitalyClient.list_call_details - .sort { |a, b| b[:duration] <=> a[:duration] } - .map(&method(:format_call_details)) end def format_call_details(call) pretty_request = call[:request]&.reject { |k, v| v.blank? }.to_h.pretty_inspect - call.merge(duration: (call[:duration] * 1000).round(3), - request: pretty_request || {}) - end - - def formatted_duration - ms = duration * 1000 - if ms >= 1000 - "%.2fms" % ms - else - "%.0fms" % ms - end + super.merge(request: pretty_request || {}) end def setup_subscribers diff --git a/lib/peek/views/redis_detailed.rb b/lib/peek/views/redis_detailed.rb index 12760c9b75e..b95307deddb 100644 --- a/lib/peek/views/redis_detailed.rb +++ b/lib/peek/views/redis_detailed.rb @@ -22,7 +22,7 @@ module Gitlab detail_store << { cmd: args.first, duration: duration, - backtrace: Gitlab::Profiler.clean_backtrace(caller) + backtrace: ::Gitlab::Profiler.clean_backtrace(caller) } end @@ -35,53 +35,17 @@ end module Peek module Views - class RedisDetailed < View + class RedisDetailed < DetailedView REDACTED_MARKER = "<redacted>" def key 'redis' end - def results - { - calls: calls, - duration: formatted_duration, - details: details - } - end - - def detail_store - ::Gitlab::SafeRequestStore['redis_call_details'] ||= [] - end - private - def formatted_duration - ms = duration * 1000 - if ms >= 1000 - "%.2fms" % ms - else - "%.0fms" % ms - end - end - - def duration - detail_store.map { |entry| entry[:duration] }.sum # rubocop:disable CodeReuse/ActiveRecord - end - - def calls - detail_store.count - end - - def details - detail_store - .sort { |a, b| b[:duration] <=> a[:duration] } - .map(&method(:format_call_details)) - end - def format_call_details(call) - call.merge(cmd: format_command(call[:cmd]), - duration: (call[:duration] * 1000).round(3)) + super.merge(cmd: format_command(call[:cmd])) end def format_command(cmd) diff --git a/lib/peek/views/rugged.rb b/lib/peek/views/rugged.rb new file mode 100644 index 00000000000..6b9d3e7b1a3 --- /dev/null +++ b/lib/peek/views/rugged.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +module Peek + module Views + class Rugged < DetailedView + def results + return {} unless calls > 0 + + super + end + + private + + def duration + ::Gitlab::RuggedInstrumentation.query_time + end + + def calls + ::Gitlab::RuggedInstrumentation.query_count + end + + def call_details + ::Gitlab::RuggedInstrumentation.list_call_details + end + + def format_call_details(call) + super.merge(args: format_args(call[:args])) + end + + def format_args(args) + args.map do |arg| + # Needed to avoid infinite as_json calls + if arg.is_a?(Gitlab::Git::Repository) + arg.to_s + else + arg + end + end + end + end + end +end diff --git a/lib/prometheus/pid_provider.rb b/lib/prometheus/pid_provider.rb index c92522c73c5..e0f7e7e0a9e 100644 --- a/lib/prometheus/pid_provider.rb +++ b/lib/prometheus/pid_provider.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require 'prometheus/client/support/unicorn' - module Prometheus module PidProvider extend self @@ -10,29 +8,38 @@ module Prometheus if Sidekiq.server? 'sidekiq' elsif defined?(Unicorn::Worker) - "unicorn_#{unicorn_worker_id}" + unicorn_worker_id elsif defined?(::Puma) - "puma_#{puma_worker_id}" + puma_worker_id else - "process_#{Process.pid}" + unknown_process_id end end private - # This is not fully accurate as we don't really know if the nil returned - # is actually means we're on master or not. - # Follow up issue was created to address this problem and - # to introduce more structrured approach to a current process discovery: - # https://gitlab.com/gitlab-org/gitlab-ce/issues/64740 def unicorn_worker_id - ::Prometheus::Client::Support::Unicorn.worker_id || 'master' + if matches = process_name.match(/unicorn.*worker\[([0-9]+)\]/) + "unicorn_#{matches[1]}" + elsif process_name =~ /unicorn/ + "unicorn_master" + else + unknown_process_id + end end - # See the comment for #unicorn_worker_id def puma_worker_id - match = process_name.match(/cluster worker ([0-9]+):/) - match ? match[1] : 'master' + if matches = process_name.match(/puma.*cluster worker ([0-9]+):/) + "puma_#{matches[1]}" + elsif process_name =~ /puma/ + "puma_master" + else + unknown_process_id + end + end + + def unknown_process_id + "process_#{Process.pid}" end def process_name diff --git a/lib/quality/test_level.rb b/lib/quality/test_level.rb index 24d8eac200c..60d79b52680 100644 --- a/lib/quality/test_level.rb +++ b/lib/quality/test_level.rb @@ -14,6 +14,7 @@ module Quality finders frontend graphql + haml_lint helpers initializers javascripts diff --git a/lib/support/init.d/gitlab b/lib/support/init.d/gitlab index 32df74f104a..bccb94ff0bf 100755 --- a/lib/support/init.d/gitlab +++ b/lib/support/init.d/gitlab @@ -67,6 +67,13 @@ if ! cd "$app_root" ; then echo "Failed to cd into $app_root, exiting!"; exit 1 fi +# Select the web server to use +if [ -z "$EXPERIMENTAL_PUMA" ]; then + use_web_server="unicorn" +else + use_web_server="puma" +fi + ### Init Script functions @@ -256,7 +263,7 @@ start_gitlab() { check_stale_pids if [ "$web_status" != "0" ]; then - echo "Starting GitLab web server" + echo "Starting GitLab web server ($use_web_server)" fi if [ "$sidekiq_status" != "0" ]; then echo "Starting GitLab Sidekiq" @@ -281,7 +288,7 @@ start_gitlab() { # Remove old socket if it exists rm -f "$rails_socket" 2>/dev/null # Start the web server - RAILS_ENV=$RAILS_ENV EXPERIMENTAL_PUMA=$EXPERIMENTAL_PUMA bin/web start + RAILS_ENV=$RAILS_ENV USE_WEB_SERVER=$use_web_server bin/web start fi # If sidekiq is already running, don't start it again. @@ -343,7 +350,7 @@ stop_gitlab() { if [ "$web_status" = "0" ]; then echo "Shutting down GitLab web server" - RAILS_ENV=$RAILS_ENV EXPERIMENTAL_PUMA=$EXPERIMENTAL_PUMA bin/web stop + RAILS_ENV=$RAILS_ENV USE_WEB_SERVER=$use_web_server bin/web stop fi if [ "$sidekiq_status" = "0" ]; then echo "Shutting down GitLab Sidekiq" @@ -447,7 +454,7 @@ reload_gitlab(){ exit 1 fi printf "Reloading GitLab web server configuration... " - RAILS_ENV=$RAILS_ENV EXPERIMENTAL_PUMA=$EXPERIMENTAL_PUMA bin/web reload + RAILS_ENV=$RAILS_ENV USE_WEB_SERVER=$use_web_server bin/web reload echo "Done." echo "Restarting GitLab Sidekiq since it isn't capable of reloading its config..." diff --git a/lib/tasks/gitlab/db.rake b/lib/tasks/gitlab/db.rake index 5f2ed5274e4..1961f64659c 100644 --- a/lib/tasks/gitlab/db.rake +++ b/lib/tasks/gitlab/db.rake @@ -33,7 +33,7 @@ namespace :gitlab do # Removes the entry from the array tables.delete 'schema_migrations' # Truncate schema_migrations to ensure migrations re-run - connection.execute('TRUNCATE schema_migrations') if connection.data_source_exists? 'schema_migrations' + connection.execute('TRUNCATE schema_migrations') if connection.table_exists? 'schema_migrations' # Drop tables with cascade to avoid dependent table errors # PG: http://www.postgresql.org/docs/current/static/ddl-depend.html @@ -70,5 +70,13 @@ namespace :gitlab do Gitlab::DowntimeCheck.new.check_and_print(migrations) end + + desc 'Sets up EE specific database functionality' + + if Gitlab.ee? + task setup_ee: %w[geo:db:drop geo:db:create geo:db:schema:load geo:db:migrate] + else + task :setup_ee + end end end diff --git a/lib/tasks/gitlab/setup.rake b/lib/tasks/gitlab/setup.rake index e763de682f8..5d86d6e466c 100644 --- a/lib/tasks/gitlab/setup.rake +++ b/lib/tasks/gitlab/setup.rake @@ -45,8 +45,6 @@ namespace :gitlab do # method terminates all the connections so that a subsequent DROP # will work. def self.terminate_all_connections - return false unless Gitlab::Database.postgresql? - cmd = <<~SQL SELECT pg_terminate_backend(pg_stat_activity.pid) FROM pg_stat_activity diff --git a/lib/tasks/gitlab/update_templates.rake b/lib/tasks/gitlab/update_templates.rake index e058e9fe069..8267c235a7f 100644 --- a/lib/tasks/gitlab/update_templates.rake +++ b/lib/tasks/gitlab/update_templates.rake @@ -5,25 +5,43 @@ namespace :gitlab do end desc "GitLab | Update project templates" - task :update_project_templates do - include Gitlab::ImportExport::CommandLineUtil + task :update_project_templates, [] => :environment do |_task, args| + # we need an instance method from Gitlab::ImportExport::CommandLineUtil and don't + # want to include it in the task, as this would affect subsequent tasks as well + downloader = Class.new do + extend Gitlab::ImportExport::CommandLineUtil + + def self.call(uploader, upload_path) + download_or_copy_upload(uploader, upload_path) + end + end + + template_names = args.extras.to_set if Rails.env.production? - puts "This rake task is not meant fo production instances".red - exit(1) + raise "This rake task is not meant for production instances" end admin = User.find_by(admin: true) unless admin - puts "No admin user could be found".red - exit(1) + raise "No admin user could be found" end - Gitlab::ProjectTemplate.all.each do |template| + tmp_namespace_path = "tmp-project-import-#{Time.now.to_i}" + puts "Creating temporary namespace #{tmp_namespace_path}" + tmp_namespace = Namespace.create!(owner: admin, name: tmp_namespace_path, path: tmp_namespace_path) + + templates = if template_names.empty? + Gitlab::ProjectTemplate.all + else + Gitlab::ProjectTemplate.all.select { |template| template_names.include?(template.name) } + end + + templates.each do |template| params = { import_url: template.clone_url, - namespace_id: admin.namespace.id, + namespace_id: tmp_namespace.id, path: template.name, skip_wiki: true } @@ -32,19 +50,17 @@ namespace :gitlab do project = Projects::CreateService.new(admin, params).execute unless project.persisted? - puts project.errors.messages - exit(1) + raise "Failed to create project: #{project.errors.messages}" end loop do - if project.finished? + if project.import_finished? puts "Import finished for #{template.name}" break end - if project.failed? - puts "Failed to import from #{project_params[:import_url]}".red - exit(1) + if project.import_failed? + raise "Failed to import from #{project_params[:import_url]}" end puts "Waiting for the import to finish" @@ -54,11 +70,23 @@ namespace :gitlab do end Projects::ImportExport::ExportService.new(project, admin).execute - download_or_copy_upload(project.export_file, template.archive_path) - Projects::DestroyService.new(admin, project).execute + downloader.call(project.export_file, template.archive_path) + + unless Projects::DestroyService.new(project, admin).execute + puts "Failed to destroy project #{template.name} (but namespace will be cleaned up later)" + end + puts "Exported #{template.name}".green end - puts "Done".green + + success = true + ensure + if tmp_namespace + puts "Destroying temporary namespace #{tmp_namespace_path}" + tmp_namespace.destroy + end + + puts "Done".green if success end def update(template) diff --git a/lib/tasks/spec.rake b/lib/tasks/spec.rake index c881ad4cf12..bf18332a8eb 100644 --- a/lib/tasks/spec.rake +++ b/lib/tasks/spec.rake @@ -2,8 +2,6 @@ return if Rails.env.production? -Rake::Task["spec"].clear if Rake::Task.task_defined?('spec') - namespace :spec do desc 'GitLab | RSpec | Run unit tests' RSpec::Core::RakeTask.new(:unit, :rspec_opts) do |t, args| @@ -26,63 +24,8 @@ namespace :spec do t.rspec_opts = args[:rspec_opts] end - desc '[Deprecated] Use the "bin/rspec --tag api" instead' - task :api do - cmds = [ - %w(rake gitlab:setup), - %w(rspec spec --tag @api) - ] - run_commands(cmds) - end - - desc '[Deprecated] Use the "spec:system" task instead' - task :feature do - cmds = [ - %w(rake gitlab:setup), - %w(rspec spec --tag @feature) - ] - run_commands(cmds) - end - - desc '[Deprecated] Use "bin/rspec spec/models" instead' - task :models do - cmds = [ - %w(rake gitlab:setup), - %w(rspec spec --tag @models) - ] - run_commands(cmds) - end - - desc '[Deprecated] Use "bin/rspec spec/services" instead' - task :services do - cmds = [ - %w(rake gitlab:setup), - %w(rspec spec --tag @services) - ] - run_commands(cmds) - end - - desc '[Deprecated] Use "bin/rspec spec/lib" instead' - task :lib do - cmds = [ - %w(rake gitlab:setup), - %w(rspec spec --tag @lib) - ] - run_commands(cmds) - end -end - -desc "GitLab | Run specs" -task :spec do - cmds = [ - %w(rake gitlab:setup), - %w(rspec spec) - ] - run_commands(cmds) -end - -def run_commands(cmds) - cmds.each do |cmd| - system({ 'RAILS_ENV' => 'test', 'force' => 'yes' }, *cmd) || raise("#{cmd} failed!") + desc 'Run the code examples in spec/requests/api' + RSpec::Core::RakeTask.new(:api) do |t| + t.pattern = 'spec/requests/api/**/*_spec.rb' end end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 5cd9aa7e2de..591dc2a7e39 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -95,11 +95,21 @@ msgid_plural "%d metrics" msgstr[0] "" msgstr[1] "" +msgid "%d minute" +msgid_plural "%d minutes" +msgstr[0] "" +msgstr[1] "" + msgid "%d more comment" msgid_plural "%d more comments" msgstr[0] "" msgstr[1] "" +msgid "%d second" +msgid_plural "%d seconds" +msgstr[0] "" +msgstr[1] "" + msgid "%d staged change" msgid_plural "%d staged changes" msgstr[0] "" @@ -725,6 +735,15 @@ msgstr "" msgid "AddMember|Too many users specified (limit is %{user_limit})" msgstr "" +msgid "Added" +msgstr "" + +msgid "Added %{label_references} %{label_text}." +msgstr "" + +msgid "Added a todo." +msgstr "" + msgid "Added at" msgstr "" @@ -734,6 +753,9 @@ msgstr "" msgid "Adds" msgstr "" +msgid "Adds %{labels} %{label_text}." +msgstr "" + msgid "Adds a todo." msgstr "" @@ -1070,6 +1092,9 @@ msgstr "" msgid "An error occurred while saving assignees" msgstr "" +msgid "An error occurred while triggering the job." +msgstr "" + msgid "An error occurred while validating username" msgstr "" @@ -1229,6 +1254,9 @@ msgstr "" msgid "Are you sure you want to delete this %{typeOfComment}?" msgstr "" +msgid "Are you sure you want to delete this board?" +msgstr "" + msgid "Are you sure you want to delete this device? This action cannot be undone." msgstr "" @@ -1316,6 +1344,9 @@ msgstr "" msgid "Assign" msgstr "" +msgid "Assign command failed because no user was found" +msgstr "" + msgid "Assign custom color like #FF0000" msgstr "" @@ -1337,6 +1368,9 @@ msgstr "" msgid "Assign yourself to this issue" msgstr "" +msgid "Assigned %{assignee_users_sentence}." +msgstr "" + msgid "Assigned Issues" msgstr "" @@ -1354,6 +1388,9 @@ msgstr[1] "" msgid "Assignee(s)" msgstr "" +msgid "Assigns %{assignee_users_sentence}." +msgstr "" + msgid "Attach a file" msgstr "" @@ -1626,6 +1663,12 @@ msgstr "" msgid "Blog" msgstr "" +msgid "Board name" +msgstr "" + +msgid "Board scope" +msgstr "" + msgid "BoardBlankState|Add default lists" msgstr "" @@ -1983,6 +2026,9 @@ msgstr "" msgid "ChangeTypeAction|This will create a new commit in order to revert the existing changes." msgstr "" +msgid "Changed the title to \"%{title_param}\"." +msgstr "" + msgid "Changes" msgstr "" @@ -2001,6 +2047,57 @@ msgstr "" msgid "Chat" msgstr "" +msgid "ChatMessage|%{project_link}: Pipeline %{pipeline_link} of %{ref_type} %{branch_link} by %{user_combined_name} %{humanized_status} in %{duration}" +msgstr "" + +msgid "ChatMessage|Branch" +msgstr "" + +msgid "ChatMessage|Commit" +msgstr "" + +msgid "ChatMessage|Failed job" +msgstr "" + +msgid "ChatMessage|Failed stage" +msgstr "" + +msgid "ChatMessage|Invalid CI config YAML file" +msgstr "" + +msgid "ChatMessage|Pipeline #%{pipeline_id} %{humanized_status} in %{duration}" +msgstr "" + +msgid "ChatMessage|Pipeline %{pipeline_link} of %{ref_type} %{branch_link} by %{user_combined_name} %{humanized_status}" +msgstr "" + +msgid "ChatMessage|Tag" +msgstr "" + +msgid "ChatMessage|and [%{count} more](%{pipeline_failed_jobs_url})" +msgstr "" + +msgid "ChatMessage|failed" +msgstr "" + +msgid "ChatMessage|has failed" +msgstr "" + +msgid "ChatMessage|has passed" +msgstr "" + +msgid "ChatMessage|has passed with warnings" +msgstr "" + +msgid "ChatMessage|in %{duration}" +msgstr "" + +msgid "ChatMessage|in %{project_link}" +msgstr "" + +msgid "ChatMessage|passed" +msgstr "" + msgid "Check again" msgstr "" @@ -2151,6 +2248,9 @@ msgstr "" msgid "CiVariables|Remove variable row" msgstr "" +msgid "CiVariables|Specify variable values to be used in this run. The values specified in %{linkStart}CI/CD settings%{linkEnd} will be used as default" +msgstr "" + msgid "CiVariables|State" msgstr "" @@ -2160,6 +2260,9 @@ msgstr "" msgid "CiVariables|Value" msgstr "" +msgid "CiVariables|Variables" +msgstr "" + msgid "CiVariable|* (All environments)" msgstr "" @@ -2262,9 +2365,18 @@ msgstr "" msgid "Close sidebar" msgstr "" +msgid "Close this %{quick_action_target}" +msgstr "" + msgid "Closed" msgstr "" +msgid "Closed this %{quick_action_target}." +msgstr "" + +msgid "Closes this %{quick_action_target}." +msgstr "" + msgid "ClusterIntegration| %{custom_domain_start}More information%{custom_domain_end}." msgstr "" @@ -2364,6 +2476,9 @@ msgstr "" msgid "ClusterIntegration|Certificate Authority bundle (PEM format)" msgstr "" +msgid "ClusterIntegration|Choose a prefix to be used for your namespaces. Defaults to your project path." +msgstr "" + msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster. Helm Tiller is required to install any of the following applications." msgstr "" @@ -2601,6 +2716,9 @@ msgstr "" msgid "ClusterIntegration|Project namespace (optional, unique)" msgstr "" +msgid "ClusterIntegration|Project namespace prefix (optional, unique)" +msgstr "" + msgid "ClusterIntegration|Prometheus" msgstr "" @@ -2709,6 +2827,9 @@ msgstr "" msgid "ClusterIntegration|The endpoint is in the process of being assigned. Please check your Kubernetes cluster or Quotas on Google Kubernetes Engine if it takes a long time." msgstr "" +msgid "ClusterIntegration|The namespace associated with your project. This will be used for deploy boards, pod logs, and Web terminals." +msgstr "" + msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid." msgstr "" @@ -2799,6 +2920,9 @@ msgstr "" msgid "Commands applied" msgstr "" +msgid "Commands did not apply" +msgstr "" + msgid "Comment" msgstr "" @@ -3098,6 +3222,9 @@ msgstr "" msgid "Copied" msgstr "" +msgid "Copied labels and milestone from %{source_issuable_reference}." +msgstr "" + msgid "Copy %{http_label} clone URL" msgstr "" @@ -3218,6 +3345,9 @@ msgstr "" msgid "Create a personal access token on your account to pull or push via %{protocol}." msgstr "" +msgid "Create board" +msgstr "" + msgid "Create branch" msgstr "" @@ -3257,6 +3387,9 @@ msgstr "" msgid "Create milestone" msgstr "" +msgid "Create new board" +msgstr "" + msgid "Create new branch" msgstr "" @@ -3302,6 +3435,12 @@ msgstr "" msgid "Created At" msgstr "" +msgid "Created a branch and a merge request to resolve this issue" +msgstr "" + +msgid "Created branch '%{branch_name}' and a merge request to resolve this issue" +msgstr "" + msgid "Created by me" msgstr "" @@ -3311,6 +3450,9 @@ msgstr "" msgid "Created on:" msgstr "" +msgid "Creates a branch and a merge request to resolve this issue" +msgstr "" + msgid "Creates branch '%{branch_name}' and a merge request to resolve this issue" msgstr "" @@ -3485,6 +3627,9 @@ msgstr "" msgid "Delete Snippet" msgstr "" +msgid "Delete board" +msgstr "" + msgid "Delete comment" msgstr "" @@ -3877,6 +4022,9 @@ msgstr "" msgid "Edit application" msgstr "" +msgid "Edit board" +msgstr "" + msgid "Edit comment" msgstr "" @@ -3901,6 +4049,12 @@ msgstr "" msgid "Edit public deploy key" msgstr "" +msgid "Editor|%{mdLinkStart}Markdown is supported%{mdLinkEnd}" +msgstr "" + +msgid "Editor|%{mdLinkStart}Markdown%{mdLinkEnd} and %{actionsLinkStart}quick actions%{actionsLinkEnd} are supported" +msgstr "" + msgid "Email" msgstr "" @@ -4057,6 +4211,9 @@ msgstr "" msgid "Enter at least three characters to search" msgstr "" +msgid "Enter board name" +msgstr "" + msgid "Enter in your Bitbucket Server URL and personal access token below" msgstr "" @@ -4573,6 +4730,9 @@ msgstr "" msgid "Failed to create resources" msgstr "" +msgid "Failed to delete board. Please try again." +msgstr "" + msgid "Failed to deploy to" msgstr "" @@ -4971,6 +5131,9 @@ msgstr "" msgid "Gitea Import" msgstr "" +msgid "Gitlab Pages" +msgstr "" + msgid "Given access %{time_ago}" msgstr "" @@ -5031,6 +5194,9 @@ msgstr "" msgid "Graph" msgstr "" +msgid "Gravatar" +msgstr "" + msgid "Gravatar enabled" msgstr "" @@ -5282,6 +5448,9 @@ msgstr[1] "" msgid "Hide values" msgstr "" +msgid "Highest number of requests per minute for each raw path, default to 300. To disable throttling set to 0." +msgstr "" + msgid "Highest role:" msgstr "" @@ -5363,6 +5532,9 @@ msgstr "" msgid "IDE|Review" msgstr "" +msgid "IDE|Successful commit" +msgstr "" + msgid "IP Address" msgstr "" @@ -5690,12 +5862,6 @@ msgstr "" msgid "Invocations" msgstr "" -msgid "Invoke Count" -msgstr "" - -msgid "Invoke Time" -msgstr "" - msgid "IssuableStatus|Closed (%{moved_link_start}moved%{moved_link_end})" msgstr "" @@ -5963,6 +6129,9 @@ msgstr "" msgid "Kubernetes service integration has been disabled. Fields on this page are not used by GitLab, you can configure your Kubernetes clusters using the new <a href=\"%{url}\"/>Kubernetes Clusters</a> page" msgstr "" +msgid "LDAP" +msgstr "" + msgid "LFS" msgstr "" @@ -6216,6 +6385,9 @@ msgstr "" msgid "Locked by %{fileLockUserName}" msgstr "" +msgid "Locked the discussion" +msgstr "" + msgid "Locked to current projects" msgstr "" @@ -6234,6 +6406,9 @@ msgstr "" msgid "MRDiff|Show full file" msgstr "" +msgid "Made this issue confidential" +msgstr "" + msgid "Make and review changes in the browser with the Web IDE" msgstr "" @@ -6315,6 +6490,9 @@ msgstr "" msgid "Mark as done" msgstr "" +msgid "Mark as duplicate failed because referenced issue was not found" +msgstr "" + msgid "Mark as resolved" msgstr "" @@ -6327,16 +6505,22 @@ msgstr "" msgid "Mark to do as done" msgstr "" -msgid "Markdown" -msgstr "" - msgid "Markdown Help" msgstr "" msgid "Markdown enabled" msgstr "" -msgid "Markdown is supported" +msgid "Marked this %{noun} as Work In Progress." +msgstr "" + +msgid "Marked this issue as a duplicate of %{duplicate_param}." +msgstr "" + +msgid "Marked to do as done." +msgstr "" + +msgid "Marks this %{noun} as Work In Progress." msgstr "" msgid "Marks this issue as a duplicate of %{duplicate_reference}." @@ -6384,6 +6568,9 @@ msgstr "" msgid "Merge" msgstr "" +msgid "Merge (when the pipeline succeeds)" +msgstr "" + msgid "Merge Request" msgstr "" @@ -6507,6 +6694,9 @@ msgstr "" msgid "Merged branches are being deleted. This can take some time depending on the number of branches. Please refresh the page to see changes." msgstr "" +msgid "Merges this merge request when the pipeline succeeds." +msgstr "" + msgid "Messages" msgstr "" @@ -6690,6 +6880,12 @@ msgstr "" msgid "Move issue from one column of the board to another" msgstr "" +msgid "Move this issue failed because target project doesn't exists" +msgstr "" + +msgid "Move this issue failed because you need to specify only one label." +msgstr "" + msgid "Move this issue to another project." msgstr "" @@ -6699,6 +6895,12 @@ msgstr "" msgid "MoveIssue|Cannot move issue to project it originates from!" msgstr "" +msgid "Moved issue to %{label} column in the board." +msgstr "" + +msgid "Moved this issue to %{path_to_project}." +msgstr "" + msgid "Moves issue to %{label} column in the board." msgstr "" @@ -6917,6 +7119,9 @@ msgstr "" msgid "No data found" msgstr "" +msgid "No data to display" +msgstr "" + msgid "No details available" msgstr "" @@ -7151,6 +7356,9 @@ msgstr "" msgid "OfSearchInADropdown|Filter" msgstr "" +msgid "OmniAuth" +msgstr "" + msgid "Once removed, the fork relationship cannot be restored and you will no longer be able to send merge requests to the source." msgstr "" @@ -7276,6 +7484,9 @@ msgstr "" msgid "Owner" msgstr "" +msgid "Packages" +msgstr "" + msgid "Page not found" msgstr "" @@ -7384,10 +7595,13 @@ msgstr "" msgid "PerformanceBar|Gitaly calls" msgstr "" -msgid "PerformanceBar|SQL queries" +msgid "PerformanceBar|Redis calls" +msgstr "" + +msgid "PerformanceBar|Rugged calls" msgstr "" -msgid "PerformanceBar|profile" +msgid "PerformanceBar|SQL queries" msgstr "" msgid "PerformanceBar|trace" @@ -7576,6 +7790,9 @@ msgstr "" msgid "Pipeline|Existing branch name or tag" msgstr "" +msgid "Pipeline|Key" +msgstr "" + msgid "Pipeline|Pipeline" msgstr "" @@ -7606,6 +7823,9 @@ msgstr "" msgid "Pipeline|Triggerer" msgstr "" +msgid "Pipeline|Value" +msgstr "" + msgid "Pipeline|Variables" msgstr "" @@ -8695,6 +8915,9 @@ msgstr "" msgid "Rake Tasks Help" msgstr "" +msgid "Raw blob request rate limit per minute" +msgstr "" + msgid "Read more" msgstr "" @@ -8772,9 +8995,6 @@ msgstr "" msgid "Register with two-factor app" msgstr "" -msgid "Registry" -msgstr "" - msgid "Related Deployed Jobs" msgstr "" @@ -8850,12 +9070,39 @@ msgstr "" msgid "Remove time estimate" msgstr "" +msgid "Removed %{assignee_text} %{assignee_references}." +msgstr "" + +msgid "Removed %{label_references} %{label_text}." +msgstr "" + +msgid "Removed %{milestone_reference} milestone." +msgstr "" + +msgid "Removed all labels." +msgstr "" + msgid "Removed group can not be restored!" msgstr "" msgid "Removed projects cannot be restored!" msgstr "" +msgid "Removed spent time." +msgstr "" + +msgid "Removed the due date." +msgstr "" + +msgid "Removed time estimate." +msgstr "" + +msgid "Removes %{assignee_text} %{assignee_references}." +msgstr "" + +msgid "Removes %{label_references} %{label_text}." +msgstr "" + msgid "Removes %{milestone_reference} milestone." msgstr "" @@ -8889,12 +9136,27 @@ msgstr "" msgid "Reopen milestone" msgstr "" +msgid "Reopen this %{quick_action_target}" +msgstr "" + +msgid "Reopened this %{quick_action_target}." +msgstr "" + +msgid "Reopens this %{quick_action_target}." +msgstr "" + msgid "Replace" msgstr "" msgid "Replace all label(s)" msgstr "" +msgid "Replaced all labels with %{label_references} %{label_text}." +msgstr "" + +msgid "Reply by email" +msgstr "" + msgid "Reply to comment" msgstr "" @@ -8976,6 +9238,9 @@ msgstr "" msgid "Requests Profiles" msgstr "" +msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are disabled. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The whitelist can hold a maximum of 4000 entries. Domains should use IDNA encoding. Ex: domain.com, 192.168.1.1, 127.0.0.0/28." +msgstr "" + msgid "Require all users in this group to setup Two-factor authentication" msgstr "" @@ -9227,6 +9492,9 @@ msgstr "" msgid "Scheduled" msgstr "" +msgid "Scheduled to merge this merge request when the pipeline succeeds." +msgstr "" + msgid "Schedules" msgstr "" @@ -9554,18 +9822,33 @@ msgstr "" msgid "Set requirements for a user to sign-in. Enable mandatory two-factor authentication." msgstr "" +msgid "Set target branch" +msgstr "" + +msgid "Set target branch to %{branch_name}." +msgstr "" + msgid "Set the default expiration time for each job's artifacts. 0 for unlimited. The default unit is in seconds, but you can define an alternative. For example: <code>4 mins 2 sec</code>, <code>2h42min</code>." msgstr "" +msgid "Set the due date to %{due_date}." +msgstr "" + msgid "Set the duration for which the jobs will be considered as old and expired. Once that time passes, the jobs will be archived and no longer able to be retried. Make it empty to never expire jobs. It has to be no less than 1 day, for example: <code>15 days</code>, <code>1 month</code>, <code>2 years</code>." msgstr "" msgid "Set the maximum file size for each job's artifacts" msgstr "" +msgid "Set the milestone to %{milestone_reference}." +msgstr "" + msgid "Set time estimate" msgstr "" +msgid "Set time estimate to %{time_estimate}." +msgstr "" + msgid "Set up CI/CD" msgstr "" @@ -9611,6 +9894,9 @@ msgstr "" msgid "SetStatusModal|What's your status?" msgstr "" +msgid "Sets target branch to %{branch_name}." +msgstr "" + msgid "Sets the due date to %{due_date}." msgstr "" @@ -9703,6 +9989,9 @@ msgstr "" msgid "Sign out" msgstr "" +msgid "Sign up" +msgstr "" + msgid "Sign-in restrictions" msgstr "" @@ -10189,9 +10478,18 @@ msgstr "" msgid "Subscribed" msgstr "" +msgid "Subscribed to this %{quick_action_target}." +msgstr "" + +msgid "Subscribes to this %{quick_action_target}." +msgstr "" + msgid "Subscription" msgstr "" +msgid "Subtracted" +msgstr "" + msgid "Subtracts" msgstr "" @@ -10339,6 +10637,12 @@ msgstr "" msgid "Tag this commit." msgstr "" +msgid "Tagged this commit to %{tag_name} with \"%{message}\"." +msgstr "" + +msgid "Tagged this commit to %{tag_name}." +msgstr "" + msgid "Tags" msgstr "" @@ -10926,9 +11230,6 @@ msgstr "" msgid "This issue is locked." msgstr "" -msgid "This job depends on a user to trigger its process. Often they are used to deploy code to production environments" -msgstr "" - msgid "This job depends on upstream jobs that need to succeed in order for this job to be triggered" msgstr "" @@ -10983,6 +11284,9 @@ msgstr "" msgid "This job requires a manual action" msgstr "" +msgid "This job requires manual intervention to start. Before starting this job, you can add variables below for last-minute configuration changes." +msgstr "" + msgid "This job will automatically run after its timer finishes. Often they are used for incremental roll-out deploys to production environments. When unscheduled it converts into a manual action." msgstr "" @@ -11398,6 +11702,9 @@ msgstr "" msgid "ToggleButton|Toggle Status: ON" msgstr "" +msgid "Toggled :%{name}: emoji award." +msgstr "" + msgid "Toggles :%{name}: emoji award." msgstr "" @@ -11482,9 +11789,6 @@ msgstr "" msgid "Trigger was created successfully." msgstr "" -msgid "Trigger was re-assigned." -msgstr "" - msgid "Trigger was successfully updated." msgstr "" @@ -11554,6 +11858,9 @@ msgstr "" msgid "Unable to resolve" msgstr "" +msgid "Unable to save your changes. Please try again." +msgstr "" + msgid "Unable to schedule a pipeline to run immediately" msgstr "" @@ -11605,9 +11912,18 @@ msgstr "" msgid "Unlocked" msgstr "" +msgid "Unlocked the discussion" +msgstr "" + msgid "Unlocks the discussion" msgstr "" +msgid "Unmarked this %{noun} as Work In Progress." +msgstr "" + +msgid "Unmarks this %{noun} as Work In Progress." +msgstr "" + msgid "Unresolve discussion" msgstr "" @@ -11650,6 +11966,12 @@ msgstr "" msgid "Unsubscribe from %{type}" msgstr "" +msgid "Unsubscribed from this %{quick_action_target}." +msgstr "" + +msgid "Unsubscribes from this %{quick_action_target}." +msgstr "" + msgid "Until" msgstr "" @@ -12108,6 +12430,9 @@ msgstr[1] "" msgid "When:" msgstr "" +msgid "Whitelist to allow requests to the local network from hooks and services" +msgstr "" + msgid "Who can see this group?" msgstr "" @@ -12411,6 +12736,9 @@ msgstr "" msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}." msgstr "" +msgid "You cannot access the raw file. Please wait a minute." +msgstr "" + msgid "You cannot impersonate a blocked user" msgstr "" @@ -12429,9 +12757,6 @@ msgstr "" msgid "You could not create a new trigger." msgstr "" -msgid "You could not take ownership of trigger." -msgstr "" - msgid "You do not have any subscriptions yet" msgstr "" @@ -12702,6 +13027,12 @@ msgstr "" msgid "Your request for access has been queued for review." msgstr "" +msgid "a Zoom call was added to this issue" +msgstr "" + +msgid "a Zoom call was removed from this issue" +msgstr "" + msgid "a deleted user" msgstr "" @@ -12887,6 +13218,9 @@ msgstr "" msgid "is not an email you own" msgstr "" +msgid "is too long (maximum is 1000 entries)" +msgstr "" + msgid "issue" msgstr "" @@ -13223,9 +13557,6 @@ msgstr "" msgid "project avatar" msgstr "" -msgid "quick actions" -msgstr "" - msgid "register" msgstr "" diff --git a/package.json b/package.json index 3c95091c6ef..dfa8e8fe4d7 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ "@babel/preset-env": "^7.4.4", "@gitlab/csslab": "^1.9.0", "@gitlab/svgs": "^1.67.0", - "@gitlab/ui": "^5.7.0", + "@gitlab/ui": "^5.9.0", "apollo-cache-inmemory": "^1.5.1", "apollo-client": "^2.5.1", "apollo-link": "^1.2.11", @@ -56,6 +56,7 @@ "clipboard": "^1.7.1", "codesandbox-api": "^0.0.20", "compression-webpack-plugin": "^2.0.0", + "copy-webpack-plugin": "^5.0.4", "core-js": "^3.1.3", "cropper": "^2.3.0", "css-loader": "^1.0.0", @@ -99,7 +100,7 @@ "mermaid": "^8.2.3", "monaco-editor": "^0.15.6", "monaco-editor-webpack-plugin": "^1.7.0", - "mousetrap": "^1.4.6", + "mousetrap": "1.4.6", "pdfjs-dist": "^2.0.943", "pikaday": "^1.6.1", "popper.js": "^1.14.7", @@ -314,6 +314,10 @@ module QA autoload :Login, 'qa/page/mattermost/login' end + module Search + autoload :Results, 'qa/page/search/results' + end + ## # Classes describing components that are used by several pages. # diff --git a/qa/qa/ce/knapsack/nightly_master_report.json b/qa/qa/ce/knapsack/nightly_master_report.json new file mode 100644 index 00000000000..08694f706de --- /dev/null +++ b/qa/qa/ce/knapsack/nightly_master_report.json @@ -0,0 +1,46 @@ +{ + "qa/specs/features/api/1_manage/users_spec.rb": 0.6089541912078857, + "qa/specs/features/api/3_create/repository/files_spec.rb": 5.015859127044678, + "qa/specs/features/api/3_create/repository/project_archive_compare_spec.rb": 1.0199065208435059, + "qa/specs/features/browser_ui/1_manage/group/transfer_project_spec.rb": 33.54091453552246, + "qa/specs/features/browser_ui/1_manage/login/log_in_spec.rb": 3.438166856765747, + "qa/specs/features/browser_ui/1_manage/login/login_via_oauth_spec.rb": 20.58603596687317, + "qa/specs/features/browser_ui/1_manage/login/register_spec.rb": 22.320587396621704, + "qa/specs/features/browser_ui/1_manage/project/add_project_member_spec.rb": 8.490083694458008, + "qa/specs/features/browser_ui/1_manage/project/create_project_spec.rb": 10.214765310287476, + "qa/specs/features/browser_ui/1_manage/project/import_github_repo_spec.rb": 100.28881478309631, + "qa/specs/features/browser_ui/1_manage/project/view_project_activity_spec.rb": 7.882027864456177, + "qa/specs/features/browser_ui/2_plan/issue/check_mentions_for_xss_spec.rb": 13.739388942718506, + "qa/specs/features/browser_ui/2_plan/issue/collapse_comments_in_discussions_spec.rb": 13.403101205825806, + "qa/specs/features/browser_ui/2_plan/issue/comment_issue_spec.rb": 10.989444971084595, + "qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb": 10.811973810195923, + "qa/specs/features/browser_ui/2_plan/issue/filter_issue_comments_spec.rb": 12.63524317741394, + "qa/specs/features/browser_ui/2_plan/issue/issue_suggestions_spec.rb": 11.280649185180664, + "qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_spec.rb": 41.76726770401001, + "qa/specs/features/browser_ui/3_create/merge_request/merge_merge_request_from_fork_spec.rb": 32.5517954826355, + "qa/specs/features/browser_ui/3_create/merge_request/rebase_merge_request_spec.rb": 46.54227638244629, + "qa/specs/features/browser_ui/3_create/merge_request/squash_merge_request_spec.rb": 27.943300485610962, + "qa/specs/features/browser_ui/3_create/merge_request/view_merge_request_diff_patch_spec.rb": 3.705310821533203, + "qa/specs/features/browser_ui/3_create/repository/add_file_template_spec.rb": 40.09336972236633, + "qa/specs/features/browser_ui/3_create/repository/add_list_delete_branches_spec.rb": 31.49540114402771, + "qa/specs/features/browser_ui/3_create/repository/add_ssh_key_spec.rb": 16.18057894706726, + "qa/specs/features/browser_ui/3_create/repository/clone_spec.rb": 0.7397980690002441, + "qa/specs/features/browser_ui/3_create/repository/create_edit_delete_file_via_web_spec.rb": 18.047621726989746, + "qa/specs/features/browser_ui/3_create/repository/push_http_private_token_spec.rb": 9.48607873916626, + "qa/specs/features/browser_ui/3_create/repository/push_mirroring_over_http_spec.rb": 23.710937023162842, + "qa/specs/features/browser_ui/3_create/repository/push_over_http_file_size_spec.rb": 19.459370374679565, + "qa/specs/features/browser_ui/3_create/repository/push_over_http_spec.rb": 7.730542182922363, + "qa/specs/features/browser_ui/3_create/repository/push_protected_branch_spec.rb": 29.76174831390381, + "qa/specs/features/browser_ui/3_create/repository/use_ssh_key_spec.rb": 22.800872802734375, + "qa/specs/features/browser_ui/3_create/repository/user_views_commit_diff_patch_spec.rb": 6.731764793395996, + "qa/specs/features/browser_ui/3_create/snippet/create_snippet_spec.rb": 5.812374591827393, + "qa/specs/features/browser_ui/3_create/web_ide/add_file_template_spec.rb": 25.460349321365356, + "qa/specs/features/browser_ui/3_create/wiki/create_edit_clone_push_wiki_spec.rb": 17.273863554000854, + "qa/specs/features/browser_ui/4_verify/ci_variable/add_ci_variable_spec.rb": 8.31815505027771, + "qa/specs/features/browser_ui/4_verify/runner/register_runner_spec.rb": 18.679633855819702, + "qa/specs/features/browser_ui/6_release/deploy_key/add_deploy_key_spec.rb": 15.342933893203735, + "qa/specs/features/browser_ui/6_release/deploy_key/clone_using_deploy_key_spec.rb": 92.46774697303772, + "qa/specs/features/browser_ui/6_release/deploy_token/add_deploy_token_spec.rb": 20.252174615859985, + "qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb": 8.281434059143066, + "qa/specs/features/browser_ui/non_devops/performance_bar_spec.rb": 8.810423135757446 +}
\ No newline at end of file diff --git a/qa/qa/page/admin/menu.rb b/qa/qa/page/admin/menu.rb index eea5717f5a7..61ec9854726 100644 --- a/qa/qa/page/admin/menu.rb +++ b/qa/qa/page/admin/menu.rb @@ -13,6 +13,10 @@ module QA element :admin_settings_metrics_and_profiling_item end + view 'app/views/layouts/nav/sidebar/_admin.html.haml' do + element :integration_settings_link + end + def go_to_repository_settings hover_settings do within_submenu do @@ -21,6 +25,14 @@ module QA end end + def go_to_integration_settings + hover_settings do + within_submenu do + click_element :integration_settings_link + end + end + end + def go_to_general_settings hover_settings do within_submenu do diff --git a/qa/qa/page/component/note.rb b/qa/qa/page/component/note.rb index fe324574f4d..34fde045091 100644 --- a/qa/qa/page/component/note.rb +++ b/qa/qa/page/component/note.rb @@ -20,13 +20,17 @@ module QA end base.view 'app/assets/javascripts/notes/components/discussion_actions.vue' do - element :discussion_reply + element :discussion_reply_tab end base.view 'app/assets/javascripts/notes/components/toggle_replies_widget.vue' do element :expand_replies element :collapse_replies end + + base.view 'app/assets/javascripts/diffs/components/diff_file_header.vue' do + element :toggle_comments_button + end end def start_discussion(text) @@ -36,8 +40,12 @@ module QA click_element :comment_button end + def toggle_comments + all_elements(:toggle_comments_button).last.click + end + def type_reply_to_discussion(reply_text) - all_elements(:discussion_reply).last.click + all_elements(:discussion_reply_tab).last.click fill_element :reply_input, reply_text end diff --git a/qa/qa/page/component/select2.rb b/qa/qa/page/component/select2.rb index 85d4abcde9b..d05c44d22b2 100644 --- a/qa/qa/page/component/select2.rb +++ b/qa/qa/page/component/select2.rb @@ -8,6 +8,10 @@ module QA find('.select2-result-label', text: item_text, match: :prefer_exact).click end + def current_selection + find('.select2-chosen').text + end + def clear_current_selection_if_present if has_css?('a > abbr.select2-search-choice-close', wait: 1.0) find('a > abbr.select2-search-choice-close').click diff --git a/qa/qa/page/main/menu.rb b/qa/qa/page/main/menu.rb index d86d554356e..e3039149ab4 100644 --- a/qa/qa/page/main/menu.rb +++ b/qa/qa/page/main/menu.rb @@ -27,6 +27,10 @@ module QA element :your_projects_link end + view 'app/views/layouts/_search.html.haml' do + element :search_term_field + end + def go_to_groups within_top_menu do click_element :groups_dropdown @@ -71,6 +75,10 @@ module QA click_element :snippets_link end + def search_for(term) + fill_element :search_term_field, "#{term}\n" + end + def has_personal_area?(wait: Capybara.default_max_wait_time) has_element?(:user_avatar, wait: wait) end diff --git a/qa/qa/page/project/issue/show.rb b/qa/qa/page/project/issue/show.rb index b59540d0377..507dccb52d0 100644 --- a/qa/qa/page/project/issue/show.rb +++ b/qa/qa/page/project/issue/show.rb @@ -70,7 +70,10 @@ module QA end def select_labels_and_refresh(labels) - click_element(:edit_link_labels) + Support::Retrier.retry_until do + click_element(:edit_link_labels) + has_element?(:dropdown_menu_labels, text: labels.first) + end labels.each do |label| within_element(:dropdown_menu_labels, text: label) do diff --git a/qa/qa/page/project/new.rb b/qa/qa/page/project/new.rb index 0918445d119..64aab9be056 100644 --- a/qa/qa/page/project/new.rb +++ b/qa/qa/page/project/new.rb @@ -59,7 +59,7 @@ module QA end def set_visibility(visibility) - choose visibility + choose visibility.capitalize end def click_github_link diff --git a/qa/qa/page/project/settings/ci_cd.rb b/qa/qa/page/project/settings/ci_cd.rb index b8c5c563da6..ae826fb3a32 100644 --- a/qa/qa/page/project/settings/ci_cd.rb +++ b/qa/qa/page/project/settings/ci_cd.rb @@ -8,33 +8,32 @@ module QA include Common view 'app/views/projects/settings/ci_cd/show.html.haml' do - element :autodevops_settings - element :runners_settings - element :variables_settings + element :autodevops_settings_content + element :runners_settings_content + element :variables_settings_content end view 'app/views/projects/settings/ci_cd/_autodevops_form.html.haml' do - element :enable_auto_devops_field, 'check_box :enabled' # rubocop:disable QA/ElementWithPattern - element :enable_auto_devops_button, "%strong= s_('CICD|Default to Auto DevOps pipeline')" # rubocop:disable QA/ElementWithPattern - element :save_changes_button, "submit _('Save changes')" # rubocop:disable QA/ElementWithPattern + element :enable_autodevops_checkbox + element :save_changes_button end def expand_runners_settings(&block) - expand_section(:runners_settings) do + expand_section(:runners_settings_content) do Settings::Runners.perform(&block) end end def expand_ci_variables(&block) - expand_section(:variables_settings) do + expand_section(:variables_settings_content) do Settings::CiVariables.perform(&block) end end def enable_auto_devops - expand_section(:autodevops_settings) do - check 'Default to Auto DevOps pipeline' - click_on 'Save changes' + expand_section(:autodevops_settings_content) do + check_element :enable_autodevops_checkbox + click_element :save_changes_button end end end diff --git a/qa/qa/page/project/sub_menus/project.rb b/qa/qa/page/project/sub_menus/project.rb index 5e0ee3c274a..6f1bc131f84 100644 --- a/qa/qa/page/project/sub_menus/project.rb +++ b/qa/qa/page/project/sub_menus/project.rb @@ -10,7 +10,7 @@ module QA def self.included(base) base.class_eval do view 'app/views/layouts/nav/sidebar/_project.html.haml' do - element :link_project + element :project_link end end end @@ -18,7 +18,7 @@ module QA def click_project retry_on_exception do within_sidebar do - click_element(:link_project) + click_element(:project_link) end end end diff --git a/qa/qa/page/search/results.rb b/qa/qa/page/search/results.rb new file mode 100644 index 00000000000..b9b18abf660 --- /dev/null +++ b/qa/qa/page/search/results.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +module QA::Page + module Search + class Results < QA::Page::Base + view 'app/views/search/_category.html.haml' do + element :code_tab + end + + view 'app/views/search/results/_blob_data.html.haml' do + element :result_item_content + element :file_title_content + element :file_text_content + end + + def switch_to_code + click_element(:code_tab) + end + + def has_file_in_project?(file_name, project_name) + has_element? :result_item_content, text: "#{project_name}: #{file_name}" + end + + def has_file_with_content?(file_name, file_text) + within_element_by_index :result_item_content, 0 do + false unless has_element? :file_title_content, text: file_name + + has_element? :file_text_content, text: file_text + end + end + end + end +end diff --git a/qa/qa/resource/project.rb b/qa/qa/resource/project.rb index c0a6004fe27..93a82094776 100644 --- a/qa/qa/resource/project.rb +++ b/qa/qa/resource/project.rb @@ -8,6 +8,7 @@ module QA include Events::Project attr_writer :initialize_with_readme + attr_writer :visibility attribute :id attribute :name @@ -44,6 +45,7 @@ module QA @standalone = false @description = 'My awesome project' @initialize_with_readme = false + @visibility = 'public' end def name=(raw_name) @@ -60,7 +62,7 @@ module QA page.choose_test_namespace page.choose_name(@name) page.add_description(@description) - page.set_visibility('Public') + page.set_visibility(@visibility) page.enable_initialize_with_readme if @initialize_with_readme page.create_new_project end @@ -88,7 +90,7 @@ module QA post_body = { name: name, description: description, - visibility: 'public', + visibility: @visibility, initialize_with_readme: @initialize_with_readme } diff --git a/qa/qa/specs/features/browser_ui/7_configure/mattermost/create_group_with_mattermost_team_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/group/create_group_with_mattermost_team_spec.rb index 94d20106de4..94d20106de4 100644 --- a/qa/qa/specs/features/browser_ui/7_configure/mattermost/create_group_with_mattermost_team_spec.rb +++ b/qa/qa/specs/features/browser_ui/1_manage/group/create_group_with_mattermost_team_spec.rb diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/log_into_mattermost_via_gitlab_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/log_into_mattermost_via_gitlab_spec.rb index 67610b62ed7..0a999cf00fa 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/login/log_into_mattermost_via_gitlab_spec.rb +++ b/qa/qa/specs/features/browser_ui/1_manage/login/log_into_mattermost_via_gitlab_spec.rb @@ -7,11 +7,13 @@ module QA Runtime::Browser.visit(:gitlab, Page::Main::Login) Page::Main::Login.perform(&:sign_in_using_credentials) - Runtime::Browser.visit(:mattermost, Page::Mattermost::Login) - Page::Mattermost::Login.perform(&:sign_in_using_oauth) + Support::Retrier.retry_on_exception do + Runtime::Browser.visit(:mattermost, Page::Mattermost::Login) + Page::Mattermost::Login.perform(&:sign_in_using_oauth) - Page::Mattermost::Main.perform do |page| - expect(page).to have_content(/(Welcome to: Mattermost|Logout GitLab Mattermost)/) + Page::Mattermost::Main.perform do |page| + expect(page).to have_content(/(Welcome to: Mattermost|Logout GitLab Mattermost)/) + end end end end diff --git a/qa/spec/spec_helper.rb b/qa/spec/spec_helper.rb index 21bfd2876a9..363980acc33 100644 --- a/qa/spec/spec_helper.rb +++ b/qa/spec/spec_helper.rb @@ -46,7 +46,7 @@ RSpec.configure do |config| if ENV['CI'] config.around do |example| - retry_times = example.metadata.keys.include?(:quarantine) ? 1 : 2 + retry_times = example.metadata.key?(:quarantine) ? 1 : 2 example.run_with_retry retry: retry_times end end diff --git a/scripts/insert-rspec-profiling-data b/scripts/insert-rspec-profiling-data index b34379764e0..88c9d8c12b1 100755 --- a/scripts/insert-rspec-profiling-data +++ b/scripts/insert-rspec-profiling-data @@ -14,10 +14,6 @@ module RspecProfiling Result.establish_connection(results_url) end - def prepared? - connection.data_source_exists?(table) - end - def results_url ENV['RSPEC_PROFILING_POSTGRES_URL'] end diff --git a/scripts/lint-rugged b/scripts/lint-rugged index e1605b4501b..d862571c1c5 100755 --- a/scripts/lint-rugged +++ b/scripts/lint-rugged @@ -1,6 +1,9 @@ #!/usr/bin/env ruby ALLOWED = [ + # https://gitlab.com/gitlab-org/gitaly/issues/760 + 'lib/elasticsearch/git/repository.rb', + # Needed to handle repositories that are not in any storage 'lib/gitlab/bare_repository_import/repository.rb', @@ -13,9 +16,11 @@ ALLOWED = [ 'lib/gitlab/gitaly_client/storage_settings.rb', # Needed for logging + 'config/initializers/peek.rb', 'config/initializers/lograge.rb', 'lib/gitlab/grape_logging/loggers/perf_logger.rb', - 'lib/gitlab/rugged_instrumentation.rb' + 'lib/gitlab/rugged_instrumentation.rb', + 'lib/peek/views/rugged.rb' ].freeze rugged_lines = IO.popen(%w[git grep -i -n rugged -- app config lib], &:read).lines diff --git a/scripts/review_apps/review-apps.sh b/scripts/review_apps/review-apps.sh index bc47884ee45..408a0595f9e 100755 --- a/scripts/review_apps/review-apps.sh +++ b/scripts/review_apps/review-apps.sh @@ -52,7 +52,7 @@ function delete() { function get_pod() { local app_name="${1}" local status="${2-Running}" - get_pod_cmd="kubectl get pods -n ${KUBE_NAMESPACE} --field-selector=status.phase=${status} -lapp=${app_name},release=${CI_ENVIRONMENT_SLUG} --no-headers -o=custom-columns=NAME:.metadata.name" + get_pod_cmd="kubectl get pods -n ${KUBE_NAMESPACE} --field-selector=status.phase=${status} -lapp=${app_name},release=${CI_ENVIRONMENT_SLUG} --no-headers -o=custom-columns=NAME:.metadata.name | tail -n 1" echoinfo "Waiting till '${app_name}' pod is ready" true echoinfo "Running '${get_pod_cmd}'" @@ -69,7 +69,6 @@ function get_pod() { break fi - printf "." let "elapsed_seconds+=interval" sleep ${interval} done @@ -190,18 +189,12 @@ function deploy() { gitlab_shell_image_repository="${IMAGE_REPOSITORY}/gitlab-shell" gitlab_workhorse_image_repository="${IMAGE_REPOSITORY}/gitlab-workhorse-${IMAGE_VERSION}" - # Cleanup and previous installs, as FAILED and PENDING_UPGRADE will cause errors with `upgrade` - if [ "$CI_ENVIRONMENT_SLUG" != "production" ] && previous_deploy_failed "$CI_ENVIRONMENT_SLUG" ; then - echo "Deployment in bad state, cleaning up $CI_ENVIRONMENT_SLUG" - delete - fi - create_application_secret HELM_CMD=$(cat << EOF helm upgrade --install \ - --wait \ - --timeout 600 \ + --atomic \ + --timeout 900 \ --set releaseOverride="$CI_ENVIRONMENT_SLUG" \ --set global.appConfig.enableUsagePing=false \ --set global.imagePullPolicy=Always \ @@ -360,7 +353,6 @@ function wait_for_review_app_to_be_accessible() { break fi - printf "." let "elapsed_seconds+=interval" sleep ${interval} done diff --git a/scripts/static-analysis b/scripts/static-analysis index 642c50ec0a8..6fd64fbf9da 100755 --- a/scripts/static-analysis +++ b/scripts/static-analysis @@ -1,6 +1,7 @@ #!/usr/bin/env ruby # We don't have auto-loading here +require_relative '../lib/gitlab' require_relative '../lib/gitlab/popen' require_relative '../lib/gitlab/popen/runner' @@ -36,6 +37,10 @@ tasks = [ %w[scripts/lint-rugged] ] +if Gitlab.ee? + tasks.unshift(%w[ruby -rbundler/setup scripts/ee_specific_check/ee_specific_check.rb]) +end + static_analysis = Gitlab::Popen::Runner.new static_analysis.run(tasks) do |cmd, &run| diff --git a/scripts/utils.sh b/scripts/utils.sh index 4a6567b8a62..c1bdef5b847 100644 --- a/scripts/utils.sh +++ b/scripts/utils.sh @@ -29,6 +29,134 @@ function setup_db() { if [ "$GITLAB_DATABASE" = "mysql" ]; then bundle exec rake add_limits_mysql fi + + bundle exec rake gitlab:db:setup_ee +} + +function install_api_client_dependencies_with_apk() { + apk add --update openssl curl jq +} + +function install_api_client_dependencies_with_apt() { + apt update && apt install jq -y +} + +function install_gitlab_gem() { + gem install gitlab --no-document +} + +function echoerr() { + local header="${2}" + + if [ -n "${header}" ]; then + printf "\n\033[0;31m** %s **\n\033[0m" "${1}" >&2; + else + printf "\033[0;31m%s\n\033[0m" "${1}" >&2; + fi +} + +function echoinfo() { + local header="${2}" + + if [ -n "${header}" ]; then + printf "\n\033[0;33m** %s **\n\033[0m" "${1}" >&2; + else + printf "\033[0;33m%s\n\033[0m" "${1}" >&2; + fi +} + +function get_job_id() { + local job_name="${1}" + local query_string="${2:+&${2}}" + local api_token="${API_TOKEN-${GITLAB_BOT_MULTI_PROJECT_PIPELINE_POLLING_TOKEN}}" + if [ -z "${api_token}" ]; then + echoerr "Please provide an API token with \$API_TOKEN or \$GITLAB_BOT_MULTI_PROJECT_PIPELINE_POLLING_TOKEN." + return + fi + + local max_page=3 + local page=1 + + while true; do + local url="https://gitlab.com/api/v4/projects/${CI_PROJECT_ID}/pipelines/${CI_PIPELINE_ID}/jobs?per_page=100&page=${page}${query_string}" + echoinfo "GET ${url}" + + local job_id + job_id=$(curl --silent --show-error --header "PRIVATE-TOKEN: ${api_token}" "${url}" | jq "map(select(.name == \"${job_name}\")) | map(.id) | last") + [[ "${job_id}" == "null" && "${page}" -lt "$max_page" ]] || break + + let "page++" + done + + if [[ "${job_id}" == "" ]]; then + echoerr "The '${job_name}' job ID couldn't be retrieved!" + else + echoinfo "The '${job_name}' job ID is ${job_id}" + echo "${job_id}" + fi +} + +function play_job() { + local job_name="${1}" + local job_id + job_id=$(get_job_id "${job_name}" "scope=manual"); + if [ -z "${job_id}" ]; then return; fi + + local api_token="${API_TOKEN-${GITLAB_BOT_MULTI_PROJECT_PIPELINE_POLLING_TOKEN}}" + if [ -z "${api_token}" ]; then + echoerr "Please provide an API token with \$API_TOKEN or \$GITLAB_BOT_MULTI_PROJECT_PIPELINE_POLLING_TOKEN." + return + fi + + local url="https://gitlab.com/api/v4/projects/${CI_PROJECT_ID}/jobs/${job_id}/play" + echoinfo "POST ${url}" + + local job_url + job_url=$(curl --silent --show-error --request POST --header "PRIVATE-TOKEN: ${api_token}" "${url}" | jq ".web_url") + echoinfo "Manual job '${job_name}' started at: ${job_url}" +} + +function wait_for_job_to_be_done() { + local job_name="${1}" + local query_string="${2}" + local job_id + job_id=$(get_job_id "${job_name}" "${query_string}") + if [ -z "${job_id}" ]; then return; fi + + local api_token="${API_TOKEN-${GITLAB_BOT_MULTI_PROJECT_PIPELINE_POLLING_TOKEN}}" + if [ -z "${api_token}" ]; then + echoerr "Please provide an API token with \$API_TOKEN or \$GITLAB_BOT_MULTI_PROJECT_PIPELINE_POLLING_TOKEN." + return + fi + + echoinfo "Waiting for the '${job_name}' job to finish..." + + local url="https://gitlab.com/api/v4/projects/${CI_PROJECT_ID}/jobs/${job_id}" + echoinfo "GET ${url}" + + # In case the job hasn't finished yet. Keep trying until the job times out. + local interval=30 + local elapsed_seconds=0 + while true; do + local job_status + job_status=$(curl --silent --show-error --header "PRIVATE-TOKEN: ${api_token}" "${url}" | jq ".status" | sed -e s/\"//g) + [[ "${job_status}" == "pending" || "${job_status}" == "running" ]] || break + + printf "." + let "elapsed_seconds+=interval" + sleep ${interval} + done + + local elapsed_minutes=$((elapsed_seconds / 60)) + echoinfo "Waited '${job_name}' for ${elapsed_minutes} minutes." + + if [[ "${job_status}" == "failed" ]]; then + echoerr "The '${job_name}' failed." + elif [[ "${job_status}" == "manual" ]]; then + echoinfo "The '${job_name}' is manual." + else + echoinfo "The '${job_name}' passed." + fi } function install_api_client_dependencies_with_apk() { diff --git a/spec/controllers/boards/issues_controller_spec.rb b/spec/controllers/boards/issues_controller_spec.rb index 0db58fbefc1..d54f7ad33cf 100644 --- a/spec/controllers/boards/issues_controller_spec.rb +++ b/spec/controllers/boards/issues_controller_spec.rb @@ -85,7 +85,7 @@ describe Boards::IssuesController do expect { list_issues(user: user, board: group_board, list: list3) }.not_to exceed_query_limit(control_count + (2 * 8 - 1)) end - it 'avoids N+1 database queries when adding a subgroup, project, and issue', :nested_groups do + it 'avoids N+1 database queries when adding a subgroup, project, and issue' do create(:project, group: sub_group_1) create(:labeled_issue, project: project, labels: [development]) control_count = ActiveRecord::QueryRecorder.new { list_issues(user: user, board: group_board, list: list3) }.count diff --git a/spec/controllers/concerns/group_tree_spec.rb b/spec/controllers/concerns/group_tree_spec.rb index aa3cd690e3f..835c3d9b3af 100644 --- a/spec/controllers/concerns/group_tree_spec.rb +++ b/spec/controllers/concerns/group_tree_spec.rb @@ -30,7 +30,7 @@ describe GroupTree do expect(assigns(:groups)).to contain_exactly(other_group) end - context 'for subgroups', :nested_groups do + context 'for subgroups' do it 'only renders root groups when no parent was given' do create(:group, :public, parent: group) @@ -85,7 +85,7 @@ describe GroupTree do expect(json_response.first['id']).to eq(group.id) end - context 'nested groups', :nested_groups do + context 'nested groups' do it 'expands the tree when filtering' do subgroup = create(:group, :public, parent: group, name: 'filter') diff --git a/spec/controllers/dashboard/groups_controller_spec.rb b/spec/controllers/dashboard/groups_controller_spec.rb index 48373d29412..20a0951423b 100644 --- a/spec/controllers/dashboard/groups_controller_spec.rb +++ b/spec/controllers/dashboard/groups_controller_spec.rb @@ -26,7 +26,7 @@ describe Dashboard::GroupsController do expect(assigns(:groups)).to contain_exactly(member_of_group) end - context 'when rendering an expanded hierarchy with public groups you are not a member of', :nested_groups do + context 'when rendering an expanded hierarchy with public groups you are not a member of' do let!(:top_level_result) { create(:group, name: 'chef-top') } let!(:top_level_a) { create(:group, name: 'top-a') } let!(:sub_level_result_a) { create(:group, name: 'chef-sub-a', parent: top_level_a) } diff --git a/spec/controllers/groups/children_controller_spec.rb b/spec/controllers/groups/children_controller_spec.rb index 02fb971bd9a..bced300a24c 100644 --- a/spec/controllers/groups/children_controller_spec.rb +++ b/spec/controllers/groups/children_controller_spec.rb @@ -46,7 +46,7 @@ describe Groups::ChildrenController do end end - context 'for subgroups', :nested_groups do + context 'for subgroups' do let!(:public_subgroup) { create(:group, :public, parent: group) } let!(:private_subgroup) { create(:group, :private, parent: group) } let!(:public_project) { create(:project, :public, namespace: group) } @@ -292,7 +292,7 @@ describe Groups::ChildrenController do end end - context 'with subgroups and projects', :nested_groups do + context 'with subgroups and projects' do let!(:first_page_subgroups) { create_list(:group, per_page, :public, parent: group) } let!(:other_subgroup) { create(:group, :public, parent: group) } let!(:next_page_projects) { create_list(:project, per_page, :public, namespace: group) } diff --git a/spec/controllers/groups/labels_controller_spec.rb b/spec/controllers/groups/labels_controller_spec.rb index 3cc6fc6f066..98a4c50fc49 100644 --- a/spec/controllers/groups/labels_controller_spec.rb +++ b/spec/controllers/groups/labels_controller_spec.rb @@ -24,7 +24,7 @@ describe Groups::LabelsController do expect(label_ids).to match_array([label_1.title, group_label_1.title]) end - context 'with ancestor group', :nested_groups do + context 'with ancestor group' do set(:subgroup) { create(:group, parent: group) } set(:subgroup_label_1) { create(:group_label, group: subgroup, title: 'subgroup_label_1') } @@ -32,7 +32,7 @@ describe Groups::LabelsController do subgroup.add_owner(user) end - it 'returns ancestor group labels', :nested_groups do + it 'returns ancestor group labels' do get :index, params: { group_id: subgroup, include_ancestor_groups: true, only_group_labels: true }, format: :json label_ids = json_response.map {|label| label['title']} diff --git a/spec/controllers/groups/uploads_controller_spec.rb b/spec/controllers/groups/uploads_controller_spec.rb index 0f99a957581..60342bf8e3d 100644 --- a/spec/controllers/groups/uploads_controller_spec.rb +++ b/spec/controllers/groups/uploads_controller_spec.rb @@ -10,6 +10,11 @@ describe Groups::UploadsController do { group_id: model } end + let(:other_model) { create(:group, :public) } + let(:other_params) do + { group_id: other_model } + end + it_behaves_like 'handle uploads' do let(:uploader_class) { NamespaceFileUploader } end diff --git a/spec/controllers/groups_controller_spec.rb b/spec/controllers/groups_controller_spec.rb index d2faef5b12b..404e61c5271 100644 --- a/spec/controllers/groups_controller_spec.rb +++ b/spec/controllers/groups_controller_spec.rb @@ -89,7 +89,7 @@ describe GroupsController do end describe 'GET #new' do - context 'when creating subgroups', :nested_groups do + context 'when creating subgroups' do [true, false].each do |can_create_group_status| context "and can_create_group is #{can_create_group_status}" do before do @@ -166,7 +166,7 @@ describe GroupsController do end end - context 'when creating subgroups', :nested_groups do + context 'when creating subgroups' do [true, false].each do |can_create_group_status| context "and can_create_group is #{can_create_group_status}" do context 'and logged in as Owner' do @@ -584,7 +584,7 @@ describe GroupsController do end end - describe 'PUT transfer', :postgresql do + describe 'PUT transfer' do before do sign_in(user) end diff --git a/spec/controllers/import/bitbucket_controller_spec.rb b/spec/controllers/import/bitbucket_controller_spec.rb index 64a66502732..38388c21749 100644 --- a/spec/controllers/import/bitbucket_controller_spec.rb +++ b/spec/controllers/import/bitbucket_controller_spec.rb @@ -231,7 +231,7 @@ describe Import::BitbucketController do end end - context 'user has chosen an existing nested namespace and name for the project', :postgresql do + context 'user has chosen an existing nested namespace and name for the project' do let(:parent_namespace) { create(:group, name: 'foo') } let(:nested_namespace) { create(:group, name: 'bar', parent: parent_namespace) } let(:test_name) { 'test_name' } @@ -250,7 +250,7 @@ describe Import::BitbucketController do end end - context 'user has chosen a non-existent nested namespaces and name for the project', :postgresql do + context 'user has chosen a non-existent nested namespaces and name for the project' do let(:test_name) { 'test_name' } it 'takes the selected namespace and name' do @@ -281,7 +281,7 @@ describe Import::BitbucketController do end end - context 'user has chosen existent and non-existent nested namespaces and name for the project', :postgresql do + context 'user has chosen existent and non-existent nested namespaces and name for the project' do let(:test_name) { 'test_name' } let!(:parent_namespace) { create(:group, name: 'foo') } diff --git a/spec/controllers/import/github_controller_spec.rb b/spec/controllers/import/github_controller_spec.rb index 059354870b5..5675798ac33 100644 --- a/spec/controllers/import/github_controller_spec.rb +++ b/spec/controllers/import/github_controller_spec.rb @@ -33,6 +33,16 @@ describe Import::GithubController do expect(response).to have_http_status(200) end + + context 'when importing a CI/CD project' do + it 'always prompts for an access token' do + allow(controller).to receive(:github_import_configured?).and_return(true) + + get :new, params: { ci_cd_only: true } + + expect(response).to render_template(:new) + end + end end describe "GET callback" do diff --git a/spec/controllers/import/gitlab_controller_spec.rb b/spec/controllers/import/gitlab_controller_spec.rb index 5af7572e74e..e465eca6c71 100644 --- a/spec/controllers/import/gitlab_controller_spec.rb +++ b/spec/controllers/import/gitlab_controller_spec.rb @@ -197,7 +197,7 @@ describe Import::GitlabController do end end - context 'user has chosen an existing nested namespace for the project', :postgresql do + context 'user has chosen an existing nested namespace for the project' do let(:parent_namespace) { create(:group, name: 'foo') } let(:nested_namespace) { create(:group, name: 'bar', parent: parent_namespace) } @@ -215,7 +215,7 @@ describe Import::GitlabController do end end - context 'user has chosen a non-existent nested namespaces for the project', :postgresql do + context 'user has chosen a non-existent nested namespaces for the project' do let(:test_name) { 'test_name' } it 'takes the selected namespace and name' do @@ -246,7 +246,7 @@ describe Import::GitlabController do end end - context 'user has chosen existent and non-existent nested namespaces and name for the project', :postgresql do + context 'user has chosen existent and non-existent nested namespaces and name for the project' do let(:test_name) { 'test_name' } let!(:parent_namespace) { create(:group, name: 'foo') } diff --git a/spec/controllers/projects/badges_controller_spec.rb b/spec/controllers/projects/badges_controller_spec.rb index 5ec8d8d41d7..4ae29ba7f54 100644 --- a/spec/controllers/projects/badges_controller_spec.rb +++ b/spec/controllers/projects/badges_controller_spec.rb @@ -7,51 +7,115 @@ describe Projects::BadgesController do let!(:pipeline) { create(:ci_empty_pipeline) } let(:user) { create(:user) } - before do - project.add_maintainer(user) - sign_in(user) - end + shared_examples 'a badge resource' do |badge_type| + context 'when pipelines are public' do + before do + project.update!(public_builds: true) + end + + context 'when project is public' do + before do + project.update!(visibility_level: Gitlab::VisibilityLevel::PUBLIC) + end + + it "returns the #{badge_type} badge to unauthenticated users" do + get_badge(badge_type) + + expect(response).to have_gitlab_http_status(:ok) + end + end + + context 'when project is restricted' do + before do + project.update!(visibility_level: Gitlab::VisibilityLevel::INTERNAL) + project.add_guest(user) + sign_in(user) + end + + it "returns the #{badge_type} badge to guest users" do + get_badge(badge_type) + + expect(response).to have_gitlab_http_status(:ok) + end + end + end - it 'requests the pipeline badge successfully' do - get_badge(:pipeline) + context 'format' do + before do + project.add_maintainer(user) + sign_in(user) + end - expect(response).to have_gitlab_http_status(:ok) - end + it 'renders the `flat` badge layout by default' do + get_badge(badge_type) - it 'requests the coverage badge successfully' do - get_badge(:coverage) + expect(response).to render_template('projects/badges/badge') + end - expect(response).to have_gitlab_http_status(:ok) - end + context 'when style param is set to `flat`' do + it 'renders the `flat` badge layout' do + get_badge(badge_type, 'flat') - it 'renders the `flat` badge layout by default' do - get_badge(:coverage) + expect(response).to render_template('projects/badges/badge') + end + end - expect(response).to render_template('projects/badges/badge') - end + context 'when style param is set to an invalid type' do + it 'renders the `flat` (default) badge layout' do + get_badge(badge_type, 'xxx') + + expect(response).to render_template('projects/badges/badge') + end + end - context 'when style param is set to `flat`' do - it 'renders the `flat` badge layout' do - get_badge(:coverage, 'flat') + context 'when style param is set to `flat-square`' do + it 'renders the `flat-square` badge layout' do + get_badge(badge_type, 'flat-square') - expect(response).to render_template('projects/badges/badge') + expect(response).to render_template('projects/badges/badge_flat-square') + end + end end - end - context 'when style param is set to an invalid type' do - it 'renders the `flat` (default) badge layout' do - get_badge(:coverage, 'xxx') + context 'when pipelines are not public' do + before do + project.update!(public_builds: false) + end - expect(response).to render_template('projects/badges/badge') + context 'when project is public' do + before do + project.update!(visibility_level: Gitlab::VisibilityLevel::PUBLIC) + end + + it 'returns 404 to unauthenticated users' do + get_badge(badge_type) + + expect(response).to have_gitlab_http_status(:not_found) + end + end + + context 'when project is restricted to the user' do + before do + project.update!(visibility_level: Gitlab::VisibilityLevel::INTERNAL) + project.add_guest(user) + sign_in(user) + end + + it 'defaults to project permissions' do + get_badge(:coverage) + + expect(response).to have_gitlab_http_status(:not_found) + end + end end end - context 'when style param is set to `flat-square`' do - it 'renders the `flat-square` badge layout' do - get_badge(:coverage, 'flat-square') + describe '#pipeline' do + it_behaves_like 'a badge resource', :pipeline + end - expect(response).to render_template('projects/badges/badge_flat-square') - end + describe '#coverage' do + it_behaves_like 'a badge resource', :coverage end def get_badge(badge, style = nil) diff --git a/spec/controllers/projects/environments_controller_spec.rb b/spec/controllers/projects/environments_controller_spec.rb index ebbbebf1bc0..8872e8d38e7 100644 --- a/spec/controllers/projects/environments_controller_spec.rb +++ b/spec/controllers/projects/environments_controller_spec.rb @@ -551,7 +551,7 @@ describe Projects::EnvironmentsController do end context 'when the specified dashboard is the default dashboard' do - let(:dashboard_path) { Gitlab::Metrics::Dashboard::SystemDashboardService::SYSTEM_DASHBOARD_PATH } + let(:dashboard_path) { ::Metrics::Dashboard::SystemDashboardService::SYSTEM_DASHBOARD_PATH } it_behaves_like 'the default dashboard' end diff --git a/spec/controllers/projects/jobs_controller_spec.rb b/spec/controllers/projects/jobs_controller_spec.rb index 901402aa5fd..39ebf02dcf5 100644 --- a/spec/controllers/projects/jobs_controller_spec.rb +++ b/spec/controllers/projects/jobs_controller_spec.rb @@ -158,7 +158,7 @@ describe Projects::JobsController, :clean_gitlab_redis_shared_state do get_show_json json_response.dig('pipeline', 'details', 'stages').tap do |stages| - expect(stages.map(&:keys).flatten) + expect(stages.flat_map(&:keys)) .to eq %w[name title status path dropdown_path] end end @@ -676,6 +676,8 @@ describe Projects::JobsController, :clean_gitlab_redis_shared_state do end describe 'POST play' do + let(:variable_attributes) { [] } + before do project.add_developer(user) @@ -698,6 +700,14 @@ describe Projects::JobsController, :clean_gitlab_redis_shared_state do it 'transits to pending' do expect(job.reload).to be_pending end + + context 'when job variables are specified' do + let(:variable_attributes) { [{ key: 'first', secret_value: 'first' }] } + + it 'assigns the job variables' do + expect(job.reload.job_variables.map(&:key)).to contain_exactly('first') + end + end end context 'when job is not playable' do @@ -712,7 +722,8 @@ describe Projects::JobsController, :clean_gitlab_redis_shared_state do post :play, params: { namespace_id: project.namespace, project_id: project, - id: job.id + id: job.id, + job_variables_attributes: variable_attributes } end end diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb index f11880122b1..57a432de3f5 100644 --- a/spec/controllers/projects/merge_requests_controller_spec.rb +++ b/spec/controllers/projects/merge_requests_controller_spec.rb @@ -621,10 +621,100 @@ describe Projects::MergeRequestsController do format: :json end - it 'responds with serialized pipelines' do - expect(json_response['pipelines']).not_to be_empty - expect(json_response['count']['all']).to eq 1 - expect(response).to include_pagination_headers + context 'with "enabled" builds on a public project' do + let(:project) { create(:project, :repository, :public) } + + context 'for a project owner' do + it 'responds with serialized pipelines' do + expect(json_response['pipelines']).to be_present + expect(json_response['count']['all']).to eq(1) + expect(response).to include_pagination_headers + end + end + + context 'for an unassociated user' do + let(:user) { create :user } + + it 'responds with no pipelines' do + expect(json_response['pipelines']).to be_present + expect(json_response['count']['all']).to eq(1) + expect(response).to include_pagination_headers + end + end + end + + context 'with private builds on a public project' do + let(:project) { create(:project, :repository, :public, :builds_private) } + + context 'for a project owner' do + it 'responds with serialized pipelines' do + expect(json_response['pipelines']).to be_present + expect(json_response['count']['all']).to eq(1) + expect(response).to include_pagination_headers + end + end + + context 'for an unassociated user' do + let(:user) { create :user } + + it 'responds with no pipelines' do + expect(json_response['pipelines']).to be_empty + expect(json_response['count']['all']).to eq(0) + expect(response).to include_pagination_headers + end + end + + context 'from a project fork' do + let(:fork_user) { create :user } + let(:forked_project) { fork_project(project, fork_user, repository: true) } # Forked project carries over :builds_private + let(:merge_request) { create(:merge_request_with_diffs, target_project: project, source_project: forked_project) } + + context 'with private builds' do + context 'for the target project member' do + it 'does not respond with serialized pipelines' do + expect(json_response['pipelines']).to be_empty + expect(json_response['count']['all']).to eq(0) + expect(response).to include_pagination_headers + end + end + + context 'for the source project member' do + let(:user) { fork_user } + + it 'responds with serialized pipelines' do + expect(json_response['pipelines']).to be_present + expect(json_response['count']['all']).to eq(1) + expect(response).to include_pagination_headers + end + end + end + + context 'with public builds' do + let(:forked_project) do + fork_project(project, fork_user, repository: true).tap do |new_project| + new_project.project_feature.update(builds_access_level: ProjectFeature::ENABLED) + end + end + + context 'for the target project member' do + it 'does not respond with serialized pipelines' do + expect(json_response['pipelines']).to be_present + expect(json_response['count']['all']).to eq(1) + expect(response).to include_pagination_headers + end + end + + context 'for the source project member' do + let(:user) { fork_user } + + it 'responds with serialized pipelines' do + expect(json_response['pipelines']).to be_present + expect(json_response['count']['all']).to eq(1) + expect(response).to include_pagination_headers + end + end + end + end end end @@ -885,10 +975,9 @@ describe Projects::MergeRequestsController do environment2 = create(:environment, project: forked) create(:deployment, :succeed, environment: environment2, sha: sha, ref: 'master', deployable: build) - # TODO address the last 11 queries + # TODO address the last 5 queries # See https://gitlab.com/gitlab-org/gitlab-ce/issues/63952 (5 queries) - # And https://gitlab.com/gitlab-org/gitlab-ce/issues/64105 (6 queries) - leeway = 11 + leeway = 5 expect { get_ci_environments_status }.not_to exceed_all_query_limit(control_count + leeway) end end diff --git a/spec/controllers/projects/milestones_controller_spec.rb b/spec/controllers/projects/milestones_controller_spec.rb index 767cee7d54a..9b2025b836c 100644 --- a/spec/controllers/projects/milestones_controller_spec.rb +++ b/spec/controllers/projects/milestones_controller_spec.rb @@ -115,7 +115,7 @@ describe Projects::MilestonesController do end end - context 'with nested groups', :nested_groups do + context 'with nested groups' do let!(:subgroup) { create(:group, :public, parent: group) } let!(:subgroup_milestone) { create(:milestone, group: subgroup) } diff --git a/spec/controllers/projects/raw_controller_spec.rb b/spec/controllers/projects/raw_controller_spec.rb index 97acd47b4da..8ee3168273f 100644 --- a/spec/controllers/projects/raw_controller_spec.rb +++ b/spec/controllers/projects/raw_controller_spec.rb @@ -3,6 +3,8 @@ require 'spec_helper' describe Projects::RawController do + include RepoHelpers + let(:project) { create(:project, :public, :repository) } describe 'GET #show' do @@ -46,5 +48,98 @@ describe Projects::RawController do let(:filename) { 'lfs_object.iso' } let(:filepath) { "be93687/files/lfs/#{filename}" } end + + context 'when the endpoint receives requests above the limit', :clean_gitlab_redis_cache do + let(:file_path) { 'master/README.md' } + + before do + stub_application_setting(raw_blob_request_limit: 5) + end + + it 'prevents from accessing the raw file' do + execute_raw_requests(requests: 6, project: project, file_path: file_path) + + expect(flash[:alert]).to eq('You cannot access the raw file. Please wait a minute.') + expect(response).to redirect_to(project_blob_path(project, file_path)) + end + + it 'logs the event on auth.log' do + attributes = { + message: 'Action_Rate_Limiter_Request', + env: :raw_blob_request_limit, + ip: '0.0.0.0', + request_method: 'GET', + fullpath: "/#{project.full_path}/raw/#{file_path}" + } + + expect(Gitlab::AuthLogger).to receive(:error).with(attributes).once + + execute_raw_requests(requests: 6, project: project, file_path: file_path) + end + + context 'when the request uses a different version of a commit' do + it 'prevents from accessing the raw file' do + # 3 times with the normal sha + commit_sha = project.repository.commit.sha + file_path = "#{commit_sha}/README.md" + + execute_raw_requests(requests: 3, project: project, file_path: file_path) + + # 3 times with the modified version + modified_sha = commit_sha.gsub(commit_sha[0..5], commit_sha[0..5].upcase) + modified_path = "#{modified_sha}/README.md" + + execute_raw_requests(requests: 3, project: project, file_path: modified_path) + + expect(flash[:alert]).to eq('You cannot access the raw file. Please wait a minute.') + expect(response).to redirect_to(project_blob_path(project, modified_path)) + end + end + + context 'when the throttling has been disabled' do + before do + stub_application_setting(raw_blob_request_limit: 0) + end + + it 'does not prevent from accessing the raw file' do + execute_raw_requests(requests: 10, project: project, file_path: file_path) + + expect(response).to have_gitlab_http_status(200) + end + end + + context 'with case-sensitive files' do + it 'prevents from accessing the specific file' do + create_file_in_repo(project, 'master', 'master', 'readme.md', 'Add readme.md') + create_file_in_repo(project, 'master', 'master', 'README.md', 'Add README.md') + + commit_sha = project.repository.commit.sha + file_path = "#{commit_sha}/readme.md" + + # Accessing downcase version of readme + execute_raw_requests(requests: 6, project: project, file_path: file_path) + + expect(flash[:alert]).to eq('You cannot access the raw file. Please wait a minute.') + expect(response).to redirect_to(project_blob_path(project, file_path)) + + # Accessing upcase version of readme + file_path = "#{commit_sha}/README.md" + + execute_raw_requests(requests: 1, project: project, file_path: file_path) + + expect(response).to have_gitlab_http_status(200) + end + end + end + end + + def execute_raw_requests(requests:, project:, file_path:) + requests.times do + get :show, params: { + namespace_id: project.namespace, + project_id: project, + id: file_path + } + end end end diff --git a/spec/controllers/projects/repositories_controller_spec.rb b/spec/controllers/projects/repositories_controller_spec.rb index 8fca9e680dd..fcab4d73dca 100644 --- a/spec/controllers/projects/repositories_controller_spec.rb +++ b/spec/controllers/projects/repositories_controller_spec.rb @@ -77,6 +77,53 @@ describe Projects::RepositoriesController do expect(response).to have_gitlab_http_status(404) end end + + describe 'caching' do + it 'sets appropriate caching headers' do + get_archive + + expect(response).to have_gitlab_http_status(200) + expect(response.header['ETag']).to be_present + expect(response.header['Cache-Control']).to include('max-age=60, private') + end + + context 'when project is public' do + let(:project) { create(:project, :repository, :public) } + + it 'sets appropriate caching headers' do + get_archive + + expect(response).to have_gitlab_http_status(200) + expect(response.header['ETag']).to be_present + expect(response.header['Cache-Control']).to include('max-age=60, public') + end + end + + context 'when ref is a commit SHA' do + it 'max-age is set to 3600 in Cache-Control header' do + get_archive('ddd0f15ae83993f5cb66a927a28673882e99100b') + + expect(response).to have_gitlab_http_status(200) + expect(response.header['Cache-Control']).to include('max-age=3600') + end + end + + context 'when If-None-Modified header is set' do + it 'returns a 304 status' do + # Get the archive cached first + get_archive + + request.headers['If-None-Match'] = response.headers['ETag'] + get_archive + + expect(response).to have_gitlab_http_status(304) + end + end + + def get_archive(id = 'feature') + get :archive, params: { namespace_id: project.namespace, project_id: project, id: id }, format: 'zip' + end + end end end end diff --git a/spec/controllers/projects/uploads_controller_spec.rb b/spec/controllers/projects/uploads_controller_spec.rb index 776c1270977..661ed9840b1 100644 --- a/spec/controllers/projects/uploads_controller_spec.rb +++ b/spec/controllers/projects/uploads_controller_spec.rb @@ -10,6 +10,11 @@ describe Projects::UploadsController do { namespace_id: model.namespace.to_param, project_id: model } end + let(:other_model) { create(:project, :public) } + let(:other_params) do + { namespace_id: other_model.namespace.to_param, project_id: other_model } + end + it_behaves_like 'handle uploads' context 'when the URL the old style, without /-/system' do diff --git a/spec/controllers/user_callouts_controller_spec.rb b/spec/controllers/user_callouts_controller_spec.rb index babc93a83e5..07eaff2da09 100644 --- a/spec/controllers/user_callouts_controller_spec.rb +++ b/spec/controllers/user_callouts_controller_spec.rb @@ -13,7 +13,7 @@ describe UserCalloutsController do subject { post :create, params: { feature_name: feature_name }, format: :json } context 'with valid feature name' do - let(:feature_name) { UserCallout.feature_names.keys.first } + let(:feature_name) { UserCallout.feature_names.first.first } context 'when callout entry does not exist' do it 'creates a callout entry with dismissed state' do @@ -28,7 +28,7 @@ describe UserCalloutsController do end context 'when callout entry already exists' do - let!(:callout) { create(:user_callout, feature_name: UserCallout.feature_names.keys.first, user: user) } + let!(:callout) { create(:user_callout, feature_name: UserCallout.feature_names.first.first, user: user) } it 'returns success' do subject diff --git a/spec/db/schema_spec.rb b/spec/db/schema_spec.rb index 6cfec5f4017..13fad1b6dc9 100644 --- a/spec/db/schema_spec.rb +++ b/spec/db/schema_spec.rb @@ -1,12 +1,14 @@ # frozen_string_literal: true require 'spec_helper' +require Rails.root.join('ee', 'spec', 'db', 'schema_support') if Gitlab.ee? describe 'Database schema' do let(:connection) { ActiveRecord::Base.connection } let(:tables) { connection.tables } # Use if you are certain that this column should not have a foreign key + # EE: edit the ee/spec/db/schema_support.rb IGNORED_FK_COLUMNS = { abuse_reports: %w[reporter_id user_id], application_settings: %w[performance_bar_allowed_group_id slack_app_id snowplow_site_id], diff --git a/spec/factories/abuse_reports.rb b/spec/factories/abuse_reports.rb index 021971ac421..578af9ed895 100644 --- a/spec/factories/abuse_reports.rb +++ b/spec/factories/abuse_reports.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :abuse_report do reporter factory: :user diff --git a/spec/factories/appearances.rb b/spec/factories/appearances.rb index dd5129229d4..bdd5964fb93 100644 --- a/spec/factories/appearances.rb +++ b/spec/factories/appearances.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Read about factories at https://github.com/thoughtbot/factory_bot FactoryBot.define do diff --git a/spec/factories/application_settings.rb b/spec/factories/application_settings.rb index 00c063c49f8..90b6b9e648a 100644 --- a/spec/factories/application_settings.rb +++ b/spec/factories/application_settings.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :application_setting do default_projects_limit 42 diff --git a/spec/factories/award_emoji.rb b/spec/factories/award_emoji.rb index 43753fa650c..a8bb806381e 100644 --- a/spec/factories/award_emoji.rb +++ b/spec/factories/award_emoji.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :award_emoji do name "thumbsup" diff --git a/spec/factories/badge.rb b/spec/factories/badge.rb index b87ece946cb..1d4e29014cc 100644 --- a/spec/factories/badge.rb +++ b/spec/factories/badge.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do trait :base_badge do link_url { generate(:url) } diff --git a/spec/factories/boards.rb b/spec/factories/boards.rb index 6524bb4830c..a5aff5c7504 100644 --- a/spec/factories/boards.rb +++ b/spec/factories/boards.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :board do transient do diff --git a/spec/factories/broadcast_messages.rb b/spec/factories/broadcast_messages.rb index 1a2be5e9552..2a30e2034b1 100644 --- a/spec/factories/broadcast_messages.rb +++ b/spec/factories/broadcast_messages.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :broadcast_message do message "MyText" diff --git a/spec/factories/chat_names.rb b/spec/factories/chat_names.rb index 56993e5da18..07bf990162f 100644 --- a/spec/factories/chat_names.rb +++ b/spec/factories/chat_names.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :chat_name, class: ChatName do user factory: :user diff --git a/spec/factories/chat_teams.rb b/spec/factories/chat_teams.rb index d048c46d6b6..52628e6d53d 100644 --- a/spec/factories/chat_teams.rb +++ b/spec/factories/chat_teams.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :chat_team, class: ChatTeam do sequence(:team_id) { |n| "abcdefghijklm#{n}" } diff --git a/spec/factories/ci/bridge.rb b/spec/factories/ci/bridge.rb index 7cb5900f2b7..6491b9dca19 100644 --- a/spec/factories/ci/bridge.rb +++ b/spec/factories/ci/bridge.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :ci_bridge, class: Ci::Bridge do name 'bridge' diff --git a/spec/factories/ci/build_trace_chunks.rb b/spec/factories/ci/build_trace_chunks.rb index 3e8e2736423..492dc47f083 100644 --- a/spec/factories/ci/build_trace_chunks.rb +++ b/spec/factories/ci/build_trace_chunks.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :ci_build_trace_chunk, class: Ci::BuildTraceChunk do build factory: :ci_build diff --git a/spec/factories/ci/build_trace_section_names.rb b/spec/factories/ci/build_trace_section_names.rb index ce07e716dde..e52694ef3dc 100644 --- a/spec/factories/ci/build_trace_section_names.rb +++ b/spec/factories/ci/build_trace_section_names.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :ci_build_trace_section_name, class: Ci::BuildTraceSectionName do sequence(:name) { |n| "section_#{n}" } diff --git a/spec/factories/ci/builds.rb b/spec/factories/ci/builds.rb index 5f7c75a3a92..e3b7c64176a 100644 --- a/spec/factories/ci/builds.rb +++ b/spec/factories/ci/builds.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + include ActionDispatch::TestProcess FactoryBot.define do diff --git a/spec/factories/ci/group_variables.rb b/spec/factories/ci/group_variables.rb index 9bf520a2c0a..13c2b78e61b 100644 --- a/spec/factories/ci/group_variables.rb +++ b/spec/factories/ci/group_variables.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :ci_group_variable, class: Ci::GroupVariable do sequence(:key) { |n| "VARIABLE_#{n}" } diff --git a/spec/factories/ci/job_artifacts.rb b/spec/factories/ci/job_artifacts.rb index 542fa9775cd..2d68a8e9fe3 100644 --- a/spec/factories/ci/job_artifacts.rb +++ b/spec/factories/ci/job_artifacts.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + include ActionDispatch::TestProcess FactoryBot.define do diff --git a/spec/factories/ci/job_variables.rb b/spec/factories/ci/job_variables.rb new file mode 100644 index 00000000000..d664b763abd --- /dev/null +++ b/spec/factories/ci/job_variables.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :ci_job_variable, class: Ci::JobVariable do + sequence(:key) { |n| "VARIABLE_#{n}" } + value 'VARIABLE_VALUE' + + job factory: :ci_build + end +end diff --git a/spec/factories/ci/pipeline_schedule.rb b/spec/factories/ci/pipeline_schedule.rb index 4b83ba2ac1b..8fae6986869 100644 --- a/spec/factories/ci/pipeline_schedule.rb +++ b/spec/factories/ci/pipeline_schedule.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :ci_pipeline_schedule, class: Ci::PipelineSchedule do cron '0 1 * * *' diff --git a/spec/factories/ci/pipeline_schedule_variables.rb b/spec/factories/ci/pipeline_schedule_variables.rb index c85b97fbfc7..fd7cfada65b 100644 --- a/spec/factories/ci/pipeline_schedule_variables.rb +++ b/spec/factories/ci/pipeline_schedule_variables.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :ci_pipeline_schedule_variable, class: Ci::PipelineScheduleVariable do sequence(:key) { |n| "VARIABLE_#{n}" } diff --git a/spec/factories/ci/pipeline_variables.rb b/spec/factories/ci/pipeline_variables.rb index b18055d7b3a..af0982124d7 100644 --- a/spec/factories/ci/pipeline_variables.rb +++ b/spec/factories/ci/pipeline_variables.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :ci_pipeline_variable, class: Ci::PipelineVariable do sequence(:key) { |n| "VARIABLE_#{n}" } diff --git a/spec/factories/ci/pipelines.rb b/spec/factories/ci/pipelines.rb index aa5ccbda6cd..9652b0000a9 100644 --- a/spec/factories/ci/pipelines.rb +++ b/spec/factories/ci/pipelines.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :ci_empty_pipeline, class: Ci::Pipeline do source :push diff --git a/spec/factories/ci/runner_projects.rb b/spec/factories/ci/runner_projects.rb index ec15972c423..bc28544a839 100644 --- a/spec/factories/ci/runner_projects.rb +++ b/spec/factories/ci/runner_projects.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :ci_runner_project, class: Ci::RunnerProject do runner factory: [:ci_runner, :project] diff --git a/spec/factories/ci/runners.rb b/spec/factories/ci/runners.rb index 24e70913b87..1e4344b814d 100644 --- a/spec/factories/ci/runners.rb +++ b/spec/factories/ci/runners.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :ci_runner, class: Ci::Runner do sequence(:description) { |n| "My runner#{n}" } diff --git a/spec/factories/ci/stages.rb b/spec/factories/ci/stages.rb index ce61e6bf759..88ff8d7dc53 100644 --- a/spec/factories/ci/stages.rb +++ b/spec/factories/ci/stages.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :ci_stage, class: Ci::LegacyStage do skip_create diff --git a/spec/factories/ci/trigger_requests.rb b/spec/factories/ci/trigger_requests.rb index 0e9fc3d0014..d63bf9868c9 100644 --- a/spec/factories/ci/trigger_requests.rb +++ b/spec/factories/ci/trigger_requests.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :ci_trigger_request, class: Ci::TriggerRequest do trigger factory: :ci_trigger diff --git a/spec/factories/ci/triggers.rb b/spec/factories/ci/triggers.rb index 742d9efba2d..6f628ed5435 100644 --- a/spec/factories/ci/triggers.rb +++ b/spec/factories/ci/triggers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :ci_trigger_without_token, class: Ci::Trigger do owner diff --git a/spec/factories/ci/variables.rb b/spec/factories/ci/variables.rb index 97a7c9ba252..55d11085040 100644 --- a/spec/factories/ci/variables.rb +++ b/spec/factories/ci/variables.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :ci_variable, class: Ci::Variable do sequence(:key) { |n| "VARIABLE_#{n}" } diff --git a/spec/factories/clusters/applications/helm.rb b/spec/factories/clusters/applications/helm.rb index d78f01828d7..7fe9ea6801a 100644 --- a/spec/factories/clusters/applications/helm.rb +++ b/spec/factories/clusters/applications/helm.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :clusters_applications_helm, class: Clusters::Applications::Helm do cluster factory: %i(cluster provided_by_gcp) diff --git a/spec/factories/clusters/clusters.rb b/spec/factories/clusters/clusters.rb index 171f5256d2b..b0d14b672f4 100644 --- a/spec/factories/clusters/clusters.rb +++ b/spec/factories/clusters/clusters.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :cluster, class: Clusters::Cluster do user diff --git a/spec/factories/clusters/platforms/kubernetes.rb b/spec/factories/clusters/platforms/kubernetes.rb index bf30a9c3a61..d5dc288fddb 100644 --- a/spec/factories/clusters/platforms/kubernetes.rb +++ b/spec/factories/clusters/platforms/kubernetes.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :cluster_platform_kubernetes, class: Clusters::Platforms::Kubernetes do cluster diff --git a/spec/factories/clusters/providers/gcp.rb b/spec/factories/clusters/providers/gcp.rb index 186c7c8027c..22462651b6a 100644 --- a/spec/factories/clusters/providers/gcp.rb +++ b/spec/factories/clusters/providers/gcp.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :cluster_provider_gcp, class: Clusters::Providers::Gcp do cluster diff --git a/spec/factories/commit_statuses.rb b/spec/factories/commit_statuses.rb index 848a31e96c1..a76da30217e 100644 --- a/spec/factories/commit_statuses.rb +++ b/spec/factories/commit_statuses.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :commit_status, class: CommitStatus do name 'default' diff --git a/spec/factories/commits.rb b/spec/factories/commits.rb index 2bcc4b6cf52..d1554426a76 100644 --- a/spec/factories/commits.rb +++ b/spec/factories/commits.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative '../support/helpers/repo_helpers' FactoryBot.define do diff --git a/spec/factories/container_repositories.rb b/spec/factories/container_repositories.rb index 00fad7975c9..a9771200d6e 100644 --- a/spec/factories/container_repositories.rb +++ b/spec/factories/container_repositories.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :container_repository do name 'test_image' diff --git a/spec/factories/conversational_development_index_metrics.rb b/spec/factories/conversational_development_index_metrics.rb index abf37fb861e..ea5816684c6 100644 --- a/spec/factories/conversational_development_index_metrics.rb +++ b/spec/factories/conversational_development_index_metrics.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :conversational_development_index_metric, class: ConversationalDevelopmentIndex::Metric do leader_issues 9.256 diff --git a/spec/factories/deploy_keys_projects.rb b/spec/factories/deploy_keys_projects.rb index 4350652fb79..7f82902dee7 100644 --- a/spec/factories/deploy_keys_projects.rb +++ b/spec/factories/deploy_keys_projects.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :deploy_keys_project do deploy_key diff --git a/spec/factories/deploy_tokens.rb b/spec/factories/deploy_tokens.rb index 017e866e69c..a96258f5cbe 100644 --- a/spec/factories/deploy_tokens.rb +++ b/spec/factories/deploy_tokens.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :deploy_token do token { SecureRandom.hex(50) } diff --git a/spec/factories/deployments.rb b/spec/factories/deployments.rb index 1c7787bc1a6..89ff1c527df 100644 --- a/spec/factories/deployments.rb +++ b/spec/factories/deployments.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :deployment, class: Deployment do sha 'b83d6e391c22777fca1ed3012fce84f633d7fed0' diff --git a/spec/factories/emails.rb b/spec/factories/emails.rb index feacd5ccf15..284ba631c37 100644 --- a/spec/factories/emails.rb +++ b/spec/factories/emails.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :email do user diff --git a/spec/factories/environments.rb b/spec/factories/environments.rb index 9d9e3d693b8..b5c8f0ca4f0 100644 --- a/spec/factories/environments.rb +++ b/spec/factories/environments.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :environment, class: Environment do sequence(:name) { |n| "environment#{n}" } diff --git a/spec/factories/events.rb b/spec/factories/events.rb index bf8411b1894..b15eb1592fc 100644 --- a/spec/factories/events.rb +++ b/spec/factories/events.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :event do project diff --git a/spec/factories/file_uploaders.rb b/spec/factories/file_uploaders.rb index 8404985bfea..ec8f5c9af2d 100644 --- a/spec/factories/file_uploaders.rb +++ b/spec/factories/file_uploaders.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :file_uploader do skip_create diff --git a/spec/factories/fork_network_members.rb b/spec/factories/fork_network_members.rb index 850e3f158f1..d34de72ab60 100644 --- a/spec/factories/fork_network_members.rb +++ b/spec/factories/fork_network_members.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :fork_network_member do association :project diff --git a/spec/factories/fork_networks.rb b/spec/factories/fork_networks.rb index 813b1943eb2..12ea688bbce 100644 --- a/spec/factories/fork_networks.rb +++ b/spec/factories/fork_networks.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :fork_network do association :root_project, factory: :project diff --git a/spec/factories/gitaly/commit.rb b/spec/factories/gitaly/commit.rb index 5034c3d0e48..954b5338846 100644 --- a/spec/factories/gitaly/commit.rb +++ b/spec/factories/gitaly/commit.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do sequence(:gitaly_commit_id) { Digest::SHA1.hexdigest(Time.now.to_f.to_s) } diff --git a/spec/factories/gitaly/commit_author.rb b/spec/factories/gitaly/commit_author.rb index aaf634ce08b..51dcd8a623b 100644 --- a/spec/factories/gitaly/commit_author.rb +++ b/spec/factories/gitaly/commit_author.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :gitaly_commit_author, class: Gitaly::CommitAuthor do skip_create diff --git a/spec/factories/gitaly/tag.rb b/spec/factories/gitaly/tag.rb index e99776d524a..a7a84753090 100644 --- a/spec/factories/gitaly/tag.rb +++ b/spec/factories/gitaly/tag.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :gitaly_tag, class: Gitaly::Tag do skip_create diff --git a/spec/factories/gpg_key_subkeys.rb b/spec/factories/gpg_key_subkeys.rb index 6c7db5379a9..9daf26d930d 100644 --- a/spec/factories/gpg_key_subkeys.rb +++ b/spec/factories/gpg_key_subkeys.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :gpg_key_subkey do gpg_key diff --git a/spec/factories/gpg_keys.rb b/spec/factories/gpg_keys.rb index 3c0f43cc1b6..9f321643174 100644 --- a/spec/factories/gpg_keys.rb +++ b/spec/factories/gpg_keys.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative '../support/helpers/gpg_helpers' FactoryBot.define do diff --git a/spec/factories/gpg_signature.rb b/spec/factories/gpg_signature.rb index b89e6ffc4b3..a0fc1740d77 100644 --- a/spec/factories/gpg_signature.rb +++ b/spec/factories/gpg_signature.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :gpg_signature do commit_sha { Digest::SHA1.hexdigest(SecureRandom.hex) } diff --git a/spec/factories/group_custom_attributes.rb b/spec/factories/group_custom_attributes.rb index d2f45d5d3ce..895bc42c84b 100644 --- a/spec/factories/group_custom_attributes.rb +++ b/spec/factories/group_custom_attributes.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :group_custom_attribute do group diff --git a/spec/factories/group_members.rb b/spec/factories/group_members.rb index 077c6ddc5ae..3bf9cdef253 100644 --- a/spec/factories/group_members.rb +++ b/spec/factories/group_members.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :group_member do access_level { GroupMember::OWNER } diff --git a/spec/factories/groups.rb b/spec/factories/groups.rb index b67ab955ffc..334c0f369cd 100644 --- a/spec/factories/groups.rb +++ b/spec/factories/groups.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :group, class: Group, parent: :namespace do sequence(:name) { |n| "group#{n}" } diff --git a/spec/factories/identities.rb b/spec/factories/identities.rb index 122d0d42938..21cfe7fe623 100644 --- a/spec/factories/identities.rb +++ b/spec/factories/identities.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :identity do provider 'ldapmain' diff --git a/spec/factories/import_export_uploads.rb b/spec/factories/import_export_uploads.rb index 7750d49b1d0..8521411e0e8 100644 --- a/spec/factories/import_export_uploads.rb +++ b/spec/factories/import_export_uploads.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :import_export_upload do project { create(:project) } diff --git a/spec/factories/import_states.rb b/spec/factories/import_states.rb index d6de26dccbc..8e778200389 100644 --- a/spec/factories/import_states.rb +++ b/spec/factories/import_states.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :import_state, class: ProjectImportState do status :none diff --git a/spec/factories/instance_configuration.rb b/spec/factories/instance_configuration.rb index 31866a9c221..daa0be3f404 100644 --- a/spec/factories/instance_configuration.rb +++ b/spec/factories/instance_configuration.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :instance_configuration do skip_create diff --git a/spec/factories/internal_ids.rb b/spec/factories/internal_ids.rb index fbde07a391a..df5c5beeb42 100644 --- a/spec/factories/internal_ids.rb +++ b/spec/factories/internal_ids.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :internal_id do project diff --git a/spec/factories/issues.rb b/spec/factories/issues.rb index ab27fee33dc..434225f7022 100644 --- a/spec/factories/issues.rb +++ b/spec/factories/issues.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :issue do title { generate(:title) } diff --git a/spec/factories/keys.rb b/spec/factories/keys.rb index 3f0c60f32b7..087d2521836 100644 --- a/spec/factories/keys.rb +++ b/spec/factories/keys.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative '../support/helpers/key_generator_helper' FactoryBot.define do diff --git a/spec/factories/label_links.rb b/spec/factories/label_links.rb index 007847d9cf4..9b7c0a158bd 100644 --- a/spec/factories/label_links.rb +++ b/spec/factories/label_links.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :label_link do label diff --git a/spec/factories/label_priorities.rb b/spec/factories/label_priorities.rb index c4824faad53..2f9f2ddfa89 100644 --- a/spec/factories/label_priorities.rb +++ b/spec/factories/label_priorities.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :label_priority do project diff --git a/spec/factories/labels.rb b/spec/factories/labels.rb index f759b6d499d..3eed750be03 100644 --- a/spec/factories/labels.rb +++ b/spec/factories/labels.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do trait :base_label do title { generate(:label_title) } diff --git a/spec/factories/lfs_file_locks.rb b/spec/factories/lfs_file_locks.rb index b9d24f82b65..73675d076ab 100644 --- a/spec/factories/lfs_file_locks.rb +++ b/spec/factories/lfs_file_locks.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :lfs_file_lock do user diff --git a/spec/factories/lfs_objects.rb b/spec/factories/lfs_objects.rb index c909471bb55..631d87cfb12 100644 --- a/spec/factories/lfs_objects.rb +++ b/spec/factories/lfs_objects.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + include ActionDispatch::TestProcess FactoryBot.define do @@ -14,6 +16,7 @@ FactoryBot.define do # objects, so the test needs to decide which (if any) object gets it trait :correct_oid do oid 'b804383982bb89b00e828e3f44c038cc991d3d1768009fc39ba8e2c081b9fb75' + size 1062 end trait :object_storage do diff --git a/spec/factories/lfs_objects_projects.rb b/spec/factories/lfs_objects_projects.rb index 4804d0bb884..7b55cc57f75 100644 --- a/spec/factories/lfs_objects_projects.rb +++ b/spec/factories/lfs_objects_projects.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :lfs_objects_project do lfs_object diff --git a/spec/factories/lists.rb b/spec/factories/lists.rb index 210c58b21e9..e68611ec518 100644 --- a/spec/factories/lists.rb +++ b/spec/factories/lists.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :list do board diff --git a/spec/factories/merge_requests.rb b/spec/factories/merge_requests.rb index 0b6a43b13a9..3d12ff98257 100644 --- a/spec/factories/merge_requests.rb +++ b/spec/factories/merge_requests.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :merge_request do title { generate(:title) } diff --git a/spec/factories/merge_requests_closing_issues.rb b/spec/factories/merge_requests_closing_issues.rb index ee0606a72b6..94f8b27358c 100644 --- a/spec/factories/merge_requests_closing_issues.rb +++ b/spec/factories/merge_requests_closing_issues.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :merge_requests_closing_issues do issue diff --git a/spec/factories/milestones.rb b/spec/factories/milestones.rb index 027349b2f8e..7d623000fc9 100644 --- a/spec/factories/milestones.rb +++ b/spec/factories/milestones.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :milestone do title diff --git a/spec/factories/namespaces.rb b/spec/factories/namespaces.rb index 0cfc6e3aa46..09dbe16ef9e 100644 --- a/spec/factories/namespaces.rb +++ b/spec/factories/namespaces.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :namespace do sequence(:name) { |n| "namespace#{n}" } diff --git a/spec/factories/notes.rb b/spec/factories/notes.rb index c51f2f958f9..5b9a7e6f864 100644 --- a/spec/factories/notes.rb +++ b/spec/factories/notes.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative '../support/helpers/repo_helpers' include ActionDispatch::TestProcess diff --git a/spec/factories/notification_settings.rb b/spec/factories/notification_settings.rb index 5116ef33f5d..c16b0e456ba 100644 --- a/spec/factories/notification_settings.rb +++ b/spec/factories/notification_settings.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :notification_setting do source factory: :project diff --git a/spec/factories/oauth_access_grants.rb b/spec/factories/oauth_access_grants.rb index 02c51cd9899..7a46ae6d71d 100644 --- a/spec/factories/oauth_access_grants.rb +++ b/spec/factories/oauth_access_grants.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :oauth_access_grant do resource_owner_id { create(:user).id } diff --git a/spec/factories/oauth_access_tokens.rb b/spec/factories/oauth_access_tokens.rb index eabfd6cd830..8d1075dacbb 100644 --- a/spec/factories/oauth_access_tokens.rb +++ b/spec/factories/oauth_access_tokens.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :oauth_access_token do resource_owner diff --git a/spec/factories/oauth_applications.rb b/spec/factories/oauth_applications.rb index 4427da1d6c7..4748b320298 100644 --- a/spec/factories/oauth_applications.rb +++ b/spec/factories/oauth_applications.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :oauth_application, class: 'Doorkeeper::Application', aliases: [:application] do sequence(:name) { |n| "OAuth App #{n}" } diff --git a/spec/factories/pages_domains.rb b/spec/factories/pages_domains.rb index e441dfcf229..ee5be82cd19 100644 --- a/spec/factories/pages_domains.rb +++ b/spec/factories/pages_domains.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :pages_domain, class: 'PagesDomain' do sequence(:domain) { |n| "my#{n}.domain.com" } diff --git a/spec/factories/personal_access_tokens.rb b/spec/factories/personal_access_tokens.rb index e7fd22a96b2..cc9b2328705 100644 --- a/spec/factories/personal_access_tokens.rb +++ b/spec/factories/personal_access_tokens.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :personal_access_token do user diff --git a/spec/factories/pool_repositories.rb b/spec/factories/pool_repositories.rb index 8cac666069c..7a8946d47b0 100644 --- a/spec/factories/pool_repositories.rb +++ b/spec/factories/pool_repositories.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :pool_repository do shard { Shard.by_name("default") } diff --git a/spec/factories/programming_languages.rb b/spec/factories/programming_languages.rb index d3511d42b6c..ee8e7765ec9 100644 --- a/spec/factories/programming_languages.rb +++ b/spec/factories/programming_languages.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :programming_language do name 'Ruby' diff --git a/spec/factories/project_auto_devops.rb b/spec/factories/project_auto_devops.rb index 1de42512402..4cc59c7095c 100644 --- a/spec/factories/project_auto_devops.rb +++ b/spec/factories/project_auto_devops.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :project_auto_devops do project diff --git a/spec/factories/project_custom_attributes.rb b/spec/factories/project_custom_attributes.rb index 099d2d7ff19..c9ed86cc0ac 100644 --- a/spec/factories/project_custom_attributes.rb +++ b/spec/factories/project_custom_attributes.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :project_custom_attribute do project diff --git a/spec/factories/project_deploy_tokens.rb b/spec/factories/project_deploy_tokens.rb index 4866cb58d88..fbf5454b0fe 100644 --- a/spec/factories/project_deploy_tokens.rb +++ b/spec/factories/project_deploy_tokens.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :project_deploy_token do project diff --git a/spec/factories/project_group_links.rb b/spec/factories/project_group_links.rb index 59c77627ee5..b02d167a950 100644 --- a/spec/factories/project_group_links.rb +++ b/spec/factories/project_group_links.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :project_group_link do project diff --git a/spec/factories/project_hooks.rb b/spec/factories/project_hooks.rb index a448d565e4b..96c9742c7d0 100644 --- a/spec/factories/project_hooks.rb +++ b/spec/factories/project_hooks.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :project_hook do url { generate(:url) } diff --git a/spec/factories/project_members.rb b/spec/factories/project_members.rb index c72e0487895..6dcac0400ca 100644 --- a/spec/factories/project_members.rb +++ b/spec/factories/project_members.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :project_member do user diff --git a/spec/factories/project_statistics.rb b/spec/factories/project_statistics.rb index 3d4174eb852..f084d9d5cbf 100644 --- a/spec/factories/project_statistics.rb +++ b/spec/factories/project_statistics.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :project_statistics do project diff --git a/spec/factories/project_wikis.rb b/spec/factories/project_wikis.rb index 4d21ed47f39..401402614f4 100644 --- a/spec/factories/project_wikis.rb +++ b/spec/factories/project_wikis.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :project_wiki do skip_create diff --git a/spec/factories/projects.rb b/spec/factories/projects.rb index 0e8810b73a1..afe27aaf1fb 100644 --- a/spec/factories/projects.rb +++ b/spec/factories/projects.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative '../support/helpers/test_env' FactoryBot.define do diff --git a/spec/factories/protected_branches.rb b/spec/factories/protected_branches.rb index 5457c0d2a8f..741615bc0d3 100644 --- a/spec/factories/protected_branches.rb +++ b/spec/factories/protected_branches.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :protected_branch do name diff --git a/spec/factories/protected_tags.rb b/spec/factories/protected_tags.rb index 2b81d089549..6ff2a245b58 100644 --- a/spec/factories/protected_tags.rb +++ b/spec/factories/protected_tags.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :protected_tag do name diff --git a/spec/factories/redirect_routes.rb b/spec/factories/redirect_routes.rb index 774232d0b34..8fa0aec007c 100644 --- a/spec/factories/redirect_routes.rb +++ b/spec/factories/redirect_routes.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :redirect_route do sequence(:path) { |n| "redirect#{n}" } diff --git a/spec/factories/releases.rb b/spec/factories/releases.rb index 4cacc77c182..34794f57284 100644 --- a/spec/factories/releases.rb +++ b/spec/factories/releases.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :release do tag "v1.1.0" diff --git a/spec/factories/remote_mirrors.rb b/spec/factories/remote_mirrors.rb index adc7da27522..ff1d751c86c 100644 --- a/spec/factories/remote_mirrors.rb +++ b/spec/factories/remote_mirrors.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :remote_mirror, class: 'RemoteMirror' do association :project, :repository diff --git a/spec/factories/repository_languages.rb b/spec/factories/repository_languages.rb index 1757ba6766c..b2b17ebbce2 100644 --- a/spec/factories/repository_languages.rb +++ b/spec/factories/repository_languages.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :repository_language do project diff --git a/spec/factories/sent_notifications.rb b/spec/factories/sent_notifications.rb index b0174dd06b7..11116af7dbb 100644 --- a/spec/factories/sent_notifications.rb +++ b/spec/factories/sent_notifications.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :sent_notification do project diff --git a/spec/factories/sequences.rb b/spec/factories/sequences.rb index f2b6e7a11f9..b6f2d6d8389 100644 --- a/spec/factories/sequences.rb +++ b/spec/factories/sequences.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do sequence(:username) { |n| "user#{n}" } sequence(:name) { |n| "John Doe#{n}" } diff --git a/spec/factories/service_hooks.rb b/spec/factories/service_hooks.rb index c907862b4f6..ff819f4f8d0 100644 --- a/spec/factories/service_hooks.rb +++ b/spec/factories/service_hooks.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :service_hook do url { generate(:url) } diff --git a/spec/factories/services.rb b/spec/factories/services.rb index daf842e3075..5ef39b3e818 100644 --- a/spec/factories/services.rb +++ b/spec/factories/services.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :service do project diff --git a/spec/factories/shards.rb b/spec/factories/shards.rb index c095fa5f0a0..c30a38180e8 100644 --- a/spec/factories/shards.rb +++ b/spec/factories/shards.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :shard do name "default" diff --git a/spec/factories/snippets.rb b/spec/factories/snippets.rb index dc12b562108..9c3a0fbe9b3 100644 --- a/spec/factories/snippets.rb +++ b/spec/factories/snippets.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :snippet do author diff --git a/spec/factories/spam_logs.rb b/spec/factories/spam_logs.rb index a467f850a80..42a856832e7 100644 --- a/spec/factories/spam_logs.rb +++ b/spec/factories/spam_logs.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :spam_log do user diff --git a/spec/factories/subscriptions.rb b/spec/factories/subscriptions.rb index 8f7ab74ec70..2b652cd57bf 100644 --- a/spec/factories/subscriptions.rb +++ b/spec/factories/subscriptions.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :subscription do project diff --git a/spec/factories/system_hooks.rb b/spec/factories/system_hooks.rb index 9e00eeb6ef1..a2d163a060f 100644 --- a/spec/factories/system_hooks.rb +++ b/spec/factories/system_hooks.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :system_hook do url { generate(:url) } diff --git a/spec/factories/system_note_metadata.rb b/spec/factories/system_note_metadata.rb index e913068da40..8cd4b77799c 100644 --- a/spec/factories/system_note_metadata.rb +++ b/spec/factories/system_note_metadata.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :system_note_metadata do note diff --git a/spec/factories/term_agreements.rb b/spec/factories/term_agreements.rb index 3c4eebd0196..b7e259bd44b 100644 --- a/spec/factories/term_agreements.rb +++ b/spec/factories/term_agreements.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :term_agreement do term diff --git a/spec/factories/terms.rb b/spec/factories/terms.rb index 5ffca365a5f..b890261d293 100644 --- a/spec/factories/terms.rb +++ b/spec/factories/terms.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :term, class: ApplicationSetting::Term do terms "Lorem ipsum dolor sit amet, consectetur adipiscing elit." diff --git a/spec/factories/timelogs.rb b/spec/factories/timelogs.rb index b45f06b9a0a..056a8833c46 100644 --- a/spec/factories/timelogs.rb +++ b/spec/factories/timelogs.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Read about factories at https://github.com/thoughtbot/factory_bot FactoryBot.define do diff --git a/spec/factories/todos.rb b/spec/factories/todos.rb index ed3d87eb76b..2ff024112a4 100644 --- a/spec/factories/todos.rb +++ b/spec/factories/todos.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :todo do project diff --git a/spec/factories/trending_project.rb b/spec/factories/trending_project.rb index f7c634fd21f..354b8c1e002 100644 --- a/spec/factories/trending_project.rb +++ b/spec/factories/trending_project.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do # TrendingProject factory :trending_project, class: 'TrendingProject' do diff --git a/spec/factories/u2f_registrations.rb b/spec/factories/u2f_registrations.rb index 26090b08966..c968468834b 100644 --- a/spec/factories/u2f_registrations.rb +++ b/spec/factories/u2f_registrations.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :u2f_registration do certificate { FFaker::BaconIpsum.characters(728) } diff --git a/spec/factories/uploads.rb b/spec/factories/uploads.rb index 426abdc2a6c..2ede92c8af0 100644 --- a/spec/factories/uploads.rb +++ b/spec/factories/uploads.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :upload do model { build(:project) } diff --git a/spec/factories/user_agent_details.rb b/spec/factories/user_agent_details.rb index 7183a8e1140..055aea50585 100644 --- a/spec/factories/user_agent_details.rb +++ b/spec/factories/user_agent_details.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :user_agent_detail do ip_address '127.0.0.1' diff --git a/spec/factories/user_callouts.rb b/spec/factories/user_callouts.rb index 528e442c14b..c4a217fd357 100644 --- a/spec/factories/user_callouts.rb +++ b/spec/factories/user_callouts.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :user_callout do feature_name :gke_cluster_integration diff --git a/spec/factories/user_custom_attributes.rb b/spec/factories/user_custom_attributes.rb index a184a2e0f17..7bd5c06f4ef 100644 --- a/spec/factories/user_custom_attributes.rb +++ b/spec/factories/user_custom_attributes.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :user_custom_attribute do user diff --git a/spec/factories/users.rb b/spec/factories/users.rb index 4f3392cdcbf..b2c8bdab013 100644 --- a/spec/factories/users.rb +++ b/spec/factories/users.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :user, aliases: [:author, :assignee, :recipient, :owner, :resource_owner] do email { generate(:email) } diff --git a/spec/factories/users_star_projects.rb b/spec/factories/users_star_projects.rb index 6afd08a2084..a1299024fe4 100644 --- a/spec/factories/users_star_projects.rb +++ b/spec/factories/users_star_projects.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :users_star_project do project diff --git a/spec/factories/web_hook_log.rb b/spec/factories/web_hook_log.rb index 17837260a4b..5750af85662 100644 --- a/spec/factories/web_hook_log.rb +++ b/spec/factories/web_hook_log.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :web_hook_log do web_hook factory: :project_hook diff --git a/spec/factories/wiki_directories.rb b/spec/factories/wiki_directories.rb index b105c82b19d..de23cf110b5 100644 --- a/spec/factories/wiki_directories.rb +++ b/spec/factories/wiki_directories.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :wiki_directory do skip_create diff --git a/spec/factories/wiki_pages.rb b/spec/factories/wiki_pages.rb index ae257d769e8..761ba58edb2 100644 --- a/spec/factories/wiki_pages.rb +++ b/spec/factories/wiki_pages.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'ostruct' FactoryBot.define do diff --git a/spec/features/abuse_report_spec.rb b/spec/features/abuse_report_spec.rb index eb12eebe8e6..b1573bfb270 100644 --- a/spec/features/abuse_report_spec.rb +++ b/spec/features/abuse_report_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Abuse reports' do diff --git a/spec/features/admin/admin_abuse_reports_spec.rb b/spec/features/admin/admin_abuse_reports_spec.rb index 3ff1a66b0b2..48fff9e57d3 100644 --- a/spec/features/admin/admin_abuse_reports_spec.rb +++ b/spec/features/admin/admin_abuse_reports_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe "Admin::AbuseReports", :js do diff --git a/spec/features/admin/admin_broadcast_messages_spec.rb b/spec/features/admin/admin_broadcast_messages_spec.rb index f6dc499df29..dfc7c89840a 100644 --- a/spec/features/admin/admin_broadcast_messages_spec.rb +++ b/spec/features/admin/admin_broadcast_messages_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Admin Broadcast Messages' do diff --git a/spec/features/admin/admin_browse_spam_logs_spec.rb b/spec/features/admin/admin_browse_spam_logs_spec.rb index 4645fde7522..c79524a7fb3 100644 --- a/spec/features/admin/admin_browse_spam_logs_spec.rb +++ b/spec/features/admin/admin_browse_spam_logs_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Admin browse spam logs' do diff --git a/spec/features/admin/admin_browses_logs_spec.rb b/spec/features/admin/admin_browses_logs_spec.rb index 1f83d04d9aa..5a2df89aeb7 100644 --- a/spec/features/admin/admin_browses_logs_spec.rb +++ b/spec/features/admin/admin_browses_logs_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Admin browses logs' do diff --git a/spec/features/admin/admin_builds_spec.rb b/spec/features/admin/admin_builds_spec.rb index 51b42d1b43b..afdf8eb0cca 100644 --- a/spec/features/admin/admin_builds_spec.rb +++ b/spec/features/admin/admin_builds_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Admin Builds' do diff --git a/spec/features/admin/admin_deploy_keys_spec.rb b/spec/features/admin/admin_deploy_keys_spec.rb index cb96830cb7c..2039a6ff1ee 100644 --- a/spec/features/admin/admin_deploy_keys_spec.rb +++ b/spec/features/admin/admin_deploy_keys_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' RSpec.describe 'admin deploy keys' do diff --git a/spec/features/admin/admin_disables_git_access_protocol_spec.rb b/spec/features/admin/admin_disables_git_access_protocol_spec.rb index f066b088800..ca8874a24f9 100644 --- a/spec/features/admin/admin_disables_git_access_protocol_spec.rb +++ b/spec/features/admin/admin_disables_git_access_protocol_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Admin disables Git access protocol', :js do diff --git a/spec/features/admin/admin_disables_two_factor_spec.rb b/spec/features/admin/admin_disables_two_factor_spec.rb index e41835b4f24..6e6a4964541 100644 --- a/spec/features/admin/admin_disables_two_factor_spec.rb +++ b/spec/features/admin/admin_disables_two_factor_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Admin disables 2FA for a user' do diff --git a/spec/features/admin/admin_groups_spec.rb b/spec/features/admin/admin_groups_spec.rb index a08902c30be..34356a2ee90 100644 --- a/spec/features/admin/admin_groups_spec.rb +++ b/spec/features/admin/admin_groups_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Admin Groups' do diff --git a/spec/features/admin/admin_health_check_spec.rb b/spec/features/admin/admin_health_check_spec.rb index 790051dd933..97c34d55d73 100644 --- a/spec/features/admin/admin_health_check_spec.rb +++ b/spec/features/admin/admin_health_check_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe "Admin Health Check", :feature do diff --git a/spec/features/admin/admin_hook_logs_spec.rb b/spec/features/admin/admin_hook_logs_spec.rb index 928f97b6d29..98900142353 100644 --- a/spec/features/admin/admin_hook_logs_spec.rb +++ b/spec/features/admin/admin_hook_logs_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Admin::HookLogs' do diff --git a/spec/features/admin/admin_hooks_spec.rb b/spec/features/admin/admin_hooks_spec.rb index ce780789f5a..0fd748af3ce 100644 --- a/spec/features/admin/admin_hooks_spec.rb +++ b/spec/features/admin/admin_hooks_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Admin::Hooks' do diff --git a/spec/features/admin/admin_labels_spec.rb b/spec/features/admin/admin_labels_spec.rb index 238ea2a25bd..35638e0829b 100644 --- a/spec/features/admin/admin_labels_spec.rb +++ b/spec/features/admin/admin_labels_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' RSpec.describe 'admin issues labels' do diff --git a/spec/features/admin/admin_manage_applications_spec.rb b/spec/features/admin/admin_manage_applications_spec.rb index a4904272706..dd4d4b1a426 100644 --- a/spec/features/admin/admin_manage_applications_spec.rb +++ b/spec/features/admin/admin_manage_applications_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' RSpec.describe 'admin manage applications' do diff --git a/spec/features/admin/admin_projects_spec.rb b/spec/features/admin/admin_projects_spec.rb index 1c1ca41f633..058e548208f 100644 --- a/spec/features/admin/admin_projects_spec.rb +++ b/spec/features/admin/admin_projects_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe "Admin::Projects" do diff --git a/spec/features/admin/admin_requests_profiles_spec.rb b/spec/features/admin/admin_requests_profiles_spec.rb index e8764d0a79c..0400b89dbfd 100644 --- a/spec/features/admin/admin_requests_profiles_spec.rb +++ b/spec/features/admin/admin_requests_profiles_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Admin::RequestsProfilesController' do diff --git a/spec/features/admin/admin_runners_spec.rb b/spec/features/admin/admin_runners_spec.rb index 97b432a6751..4ad90c96558 100644 --- a/spec/features/admin/admin_runners_spec.rb +++ b/spec/features/admin/admin_runners_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe "Admin Runners" do diff --git a/spec/features/admin/admin_settings_spec.rb b/spec/features/admin/admin_settings_spec.rb index 518b3625348..a074bbcff0a 100644 --- a/spec/features/admin/admin_settings_spec.rb +++ b/spec/features/admin/admin_settings_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Admin updates settings' do diff --git a/spec/features/admin/admin_system_info_spec.rb b/spec/features/admin/admin_system_info_spec.rb index 5a989319d5b..3dacf63e25a 100644 --- a/spec/features/admin/admin_system_info_spec.rb +++ b/spec/features/admin/admin_system_info_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Admin System Info' do diff --git a/spec/features/admin/admin_users_impersonation_tokens_spec.rb b/spec/features/admin/admin_users_impersonation_tokens_spec.rb index c7860bebb06..27f2436108c 100644 --- a/spec/features/admin/admin_users_impersonation_tokens_spec.rb +++ b/spec/features/admin/admin_users_impersonation_tokens_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Admin > Users > Impersonation Tokens', :js do diff --git a/spec/features/admin/admin_users_spec.rb b/spec/features/admin/admin_users_spec.rb index dafec29dfcc..ebf71d8c9da 100644 --- a/spec/features/admin/admin_users_spec.rb +++ b/spec/features/admin/admin_users_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe "Admin::Users" do diff --git a/spec/features/admin/admin_uses_repository_checks_spec.rb b/spec/features/admin/admin_uses_repository_checks_spec.rb index d04bb9acd9e..8c1ec183286 100644 --- a/spec/features/admin/admin_uses_repository_checks_spec.rb +++ b/spec/features/admin/admin_uses_repository_checks_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Admin uses repository checks' do diff --git a/spec/features/admin/dashboard_spec.rb b/spec/features/admin/dashboard_spec.rb index a6ca0803469..e204e0a515d 100644 --- a/spec/features/admin/dashboard_spec.rb +++ b/spec/features/admin/dashboard_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'admin visits dashboard' do @@ -15,10 +17,8 @@ describe 'admin visits dashboard' do # Make sure the fork_networks & fork_networks reltuples have been updated # to get a correct count on postgresql - if Gitlab::Database.postgresql? - ActiveRecord::Base.connection.execute('ANALYZE fork_networks') - ActiveRecord::Base.connection.execute('ANALYZE fork_network_members') - end + ActiveRecord::Base.connection.execute('ANALYZE fork_networks') + ActiveRecord::Base.connection.execute('ANALYZE fork_network_members') visit admin_root_path diff --git a/spec/features/admin/services/admin_activates_prometheus_spec.rb b/spec/features/admin/services/admin_activates_prometheus_spec.rb index 904fe5b406b..64c57cd425b 100644 --- a/spec/features/admin/services/admin_activates_prometheus_spec.rb +++ b/spec/features/admin/services/admin_activates_prometheus_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Admin activates Prometheus' do diff --git a/spec/features/atom/dashboard_spec.rb b/spec/features/atom/dashboard_spec.rb index 947587220a9..7df0e47cd14 100644 --- a/spec/features/atom/dashboard_spec.rb +++ b/spec/features/atom/dashboard_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe "Dashboard Feed" do diff --git a/spec/features/atom/issues_spec.rb b/spec/features/atom/issues_spec.rb index 714a9885caa..c0413f0f352 100644 --- a/spec/features/atom/issues_spec.rb +++ b/spec/features/atom/issues_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Issues Feed' do diff --git a/spec/features/atom/users_spec.rb b/spec/features/atom/users_spec.rb index 7de8bea5049..6f013e13ae4 100644 --- a/spec/features/atom/users_spec.rb +++ b/spec/features/atom/users_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe "User Feed" do diff --git a/spec/features/boards/add_issues_modal_spec.rb b/spec/features/boards/add_issues_modal_spec.rb index 030993462b5..6e477a93293 100644 --- a/spec/features/boards/add_issues_modal_spec.rb +++ b/spec/features/boards/add_issues_modal_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Issue Boards add issue modal', :js do diff --git a/spec/features/boards/boards_spec.rb b/spec/features/boards/boards_spec.rb index 4c6175f5590..4e7b25115d7 100644 --- a/spec/features/boards/boards_spec.rb +++ b/spec/features/boards/boards_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Issue Boards', :js do diff --git a/spec/features/boards/issue_ordering_spec.rb b/spec/features/boards/issue_ordering_spec.rb index 21779336559..c8ea202169c 100644 --- a/spec/features/boards/issue_ordering_spec.rb +++ b/spec/features/boards/issue_ordering_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Issue Boards', :js do diff --git a/spec/features/boards/keyboard_shortcut_spec.rb b/spec/features/boards/keyboard_shortcut_spec.rb index d820a59aa16..5f3a2c409ed 100644 --- a/spec/features/boards/keyboard_shortcut_spec.rb +++ b/spec/features/boards/keyboard_shortcut_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Issue Boards shortcut', :js do diff --git a/spec/features/boards/modal_filter_spec.rb b/spec/features/boards/modal_filter_spec.rb index e42d18b457e..93de2750466 100644 --- a/spec/features/boards/modal_filter_spec.rb +++ b/spec/features/boards/modal_filter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Issue Boards add issue modal filtering', :js do diff --git a/spec/features/boards/new_issue_spec.rb b/spec/features/boards/new_issue_spec.rb index d0c4534e317..abbec0ea810 100644 --- a/spec/features/boards/new_issue_spec.rb +++ b/spec/features/boards/new_issue_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Issue Boards new issue', :js do diff --git a/spec/features/boards/reload_boards_on_browser_back_spec.rb b/spec/features/boards/reload_boards_on_browser_back_spec.rb index 4b4bd705a77..752c8c1052d 100644 --- a/spec/features/boards/reload_boards_on_browser_back_spec.rb +++ b/spec/features/boards/reload_boards_on_browser_back_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Ensure Boards do not show stale data on browser back', :js do diff --git a/spec/features/boards/sidebar_spec.rb b/spec/features/boards/sidebar_spec.rb index 6c9ae343e01..7ee3a839293 100644 --- a/spec/features/boards/sidebar_spec.rb +++ b/spec/features/boards/sidebar_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Issue Boards', :js do diff --git a/spec/features/boards/sub_group_project_spec.rb b/spec/features/boards/sub_group_project_spec.rb index de2cb4c335e..264e5e85505 100644 --- a/spec/features/boards/sub_group_project_spec.rb +++ b/spec/features/boards/sub_group_project_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Sub-group project issue boards', :js do diff --git a/spec/features/calendar_spec.rb b/spec/features/calendar_spec.rb index 8cb9b57a049..235b6d0fd40 100644 --- a/spec/features/calendar_spec.rb +++ b/spec/features/calendar_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Contributions Calendar', :js do diff --git a/spec/features/commits_spec.rb b/spec/features/commits_spec.rb index a2dd34e7f7c..96d8da845cb 100644 --- a/spec/features/commits_spec.rb +++ b/spec/features/commits_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Commits' do diff --git a/spec/features/container_registry_spec.rb b/spec/features/container_registry_spec.rb index 1b5943bd5d8..89dece97a35 100644 --- a/spec/features/container_registry_spec.rb +++ b/spec/features/container_registry_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe "Container Registry", :js do diff --git a/spec/features/contextual_sidebar_spec.rb b/spec/features/contextual_sidebar_spec.rb index 88da1b7966b..e250e8cc90a 100644 --- a/spec/features/contextual_sidebar_spec.rb +++ b/spec/features/contextual_sidebar_spec.rb @@ -16,21 +16,21 @@ describe 'Contextual sidebar', :js do it 'shows flyout navs when collapsed or expanded apart from on the active item when expanded' do expect(page).not_to have_selector('.js-sidebar-collapsed') - find('.qa-link-pipelines').hover + find('.rspec-link-pipelines').hover expect(page).to have_selector('.is-showing-fly-out') - find('.qa-link-project').hover + find('.rspec-project-link').hover expect(page).not_to have_selector('.is-showing-fly-out') - find('.qa-toggle-sidebar').click + find('.rspec-toggle-sidebar').click - find('.qa-link-pipelines').hover + find('.rspec-link-pipelines').hover expect(page).to have_selector('.is-showing-fly-out') - find('.qa-link-project').hover + find('.rspec-project-link').hover expect(page).to have_selector('.is-showing-fly-out') end diff --git a/spec/features/cycle_analytics_spec.rb b/spec/features/cycle_analytics_spec.rb index 4108a0f370d..07f0864fb3b 100644 --- a/spec/features/cycle_analytics_spec.rb +++ b/spec/features/cycle_analytics_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Cycle Analytics', :js do diff --git a/spec/features/dashboard/active_tab_spec.rb b/spec/features/dashboard/active_tab_spec.rb index f4d0f82d248..92d0c0c9260 100644 --- a/spec/features/dashboard/active_tab_spec.rb +++ b/spec/features/dashboard/active_tab_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' RSpec.describe 'Dashboard Active Tab', :js do diff --git a/spec/features/dashboard/activity_spec.rb b/spec/features/dashboard/activity_spec.rb index c55dc4523f7..0a3b550c0c4 100644 --- a/spec/features/dashboard/activity_spec.rb +++ b/spec/features/dashboard/activity_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Dashboard > Activity' do diff --git a/spec/features/dashboard/archived_projects_spec.rb b/spec/features/dashboard/archived_projects_spec.rb index d31df322d10..9965229a539 100644 --- a/spec/features/dashboard/archived_projects_spec.rb +++ b/spec/features/dashboard/archived_projects_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' RSpec.describe 'Dashboard Archived Project' do diff --git a/spec/features/dashboard/datetime_on_tooltips_spec.rb b/spec/features/dashboard/datetime_on_tooltips_spec.rb index f44bd55ecf6..56b47b74626 100644 --- a/spec/features/dashboard/datetime_on_tooltips_spec.rb +++ b/spec/features/dashboard/datetime_on_tooltips_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Tooltips on .timeago dates', :js do diff --git a/spec/features/dashboard/group_dashboard_with_external_authorization_service_spec.rb b/spec/features/dashboard/group_dashboard_with_external_authorization_service_spec.rb index 4098dd02141..aebc2eb1916 100644 --- a/spec/features/dashboard/group_dashboard_with_external_authorization_service_spec.rb +++ b/spec/features/dashboard/group_dashboard_with_external_authorization_service_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'The group dashboard' do diff --git a/spec/features/dashboard/group_spec.rb b/spec/features/dashboard/group_spec.rb index 259f220c68b..653a16bbbcc 100644 --- a/spec/features/dashboard/group_spec.rb +++ b/spec/features/dashboard/group_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' RSpec.describe 'Dashboard Group' do diff --git a/spec/features/dashboard/groups_list_spec.rb b/spec/features/dashboard/groups_list_spec.rb index fb76e2b0014..76785534ec7 100644 --- a/spec/features/dashboard/groups_list_spec.rb +++ b/spec/features/dashboard/groups_list_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Dashboard Groups page', :js do @@ -27,7 +29,7 @@ describe 'Dashboard Groups page', :js do expect(page).not_to have_content(another_group.name) end - it 'shows subgroups the user is member of', :nested_groups do + it 'shows subgroups the user is member of' do group.add_owner(user) nested_group.add_owner(user) @@ -40,7 +42,7 @@ describe 'Dashboard Groups page', :js do expect(page).to have_content(nested_group.name) end - context 'when filtering groups', :nested_groups do + context 'when filtering groups' do before do group.add_owner(user) nested_group.add_owner(user) @@ -79,7 +81,7 @@ describe 'Dashboard Groups page', :js do end end - context 'with subgroups', :nested_groups do + context 'with subgroups' do let!(:subgroup) { create(:group, :public, parent: group) } before do diff --git a/spec/features/dashboard/help_spec.rb b/spec/features/dashboard/help_spec.rb index 467a503a62d..3f425001447 100644 --- a/spec/features/dashboard/help_spec.rb +++ b/spec/features/dashboard/help_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' RSpec.describe 'Dashboard Help' do diff --git a/spec/features/dashboard/issuables_counter_spec.rb b/spec/features/dashboard/issuables_counter_spec.rb index 50b71368e13..eca78749171 100644 --- a/spec/features/dashboard/issuables_counter_spec.rb +++ b/spec/features/dashboard/issuables_counter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Navigation bar counter', :use_clean_rails_memory_store_caching do diff --git a/spec/features/dashboard/issues_filter_spec.rb b/spec/features/dashboard/issues_filter_spec.rb index c0434f767bb..1352e1bd8fc 100644 --- a/spec/features/dashboard/issues_filter_spec.rb +++ b/spec/features/dashboard/issues_filter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Dashboard Issues filtering', :js do diff --git a/spec/features/dashboard/issues_spec.rb b/spec/features/dashboard/issues_spec.rb index 9957bec0f0b..cb055ff8416 100644 --- a/spec/features/dashboard/issues_spec.rb +++ b/spec/features/dashboard/issues_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' RSpec.describe 'Dashboard Issues' do diff --git a/spec/features/dashboard/label_filter_spec.rb b/spec/features/dashboard/label_filter_spec.rb index 2d4659d380f..630b2b636b4 100644 --- a/spec/features/dashboard/label_filter_spec.rb +++ b/spec/features/dashboard/label_filter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Dashboard > label filter', :js do diff --git a/spec/features/dashboard/merge_requests_spec.rb b/spec/features/dashboard/merge_requests_spec.rb index 0c6713f623c..0c1e1d5910b 100644 --- a/spec/features/dashboard/merge_requests_spec.rb +++ b/spec/features/dashboard/merge_requests_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Dashboard Merge Requests' do diff --git a/spec/features/dashboard/milestone_tabs_spec.rb b/spec/features/dashboard/milestone_tabs_spec.rb index 21de7c2f06f..a83e4c1f7c9 100644 --- a/spec/features/dashboard/milestone_tabs_spec.rb +++ b/spec/features/dashboard/milestone_tabs_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Dashboard milestone tabs', :js do diff --git a/spec/features/dashboard/milestones_spec.rb b/spec/features/dashboard/milestones_spec.rb index c3310a4a132..c21bc922de7 100644 --- a/spec/features/dashboard/milestones_spec.rb +++ b/spec/features/dashboard/milestones_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Dashboard > Milestones' do diff --git a/spec/features/dashboard/project_member_activity_index_spec.rb b/spec/features/dashboard/project_member_activity_index_spec.rb index 16919fe63ad..8e7a0b2a611 100644 --- a/spec/features/dashboard/project_member_activity_index_spec.rb +++ b/spec/features/dashboard/project_member_activity_index_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Project member activity', :js do diff --git a/spec/features/dashboard/projects_spec.rb b/spec/features/dashboard/projects_spec.rb index d1ed64cce7f..e2100c8562b 100644 --- a/spec/features/dashboard/projects_spec.rb +++ b/spec/features/dashboard/projects_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Dashboard Projects' do diff --git a/spec/features/dashboard/shortcuts_spec.rb b/spec/features/dashboard/shortcuts_spec.rb index 254bb12573c..659bec177ab 100644 --- a/spec/features/dashboard/shortcuts_spec.rb +++ b/spec/features/dashboard/shortcuts_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Dashboard shortcuts', :js do diff --git a/spec/features/dashboard/snippets_spec.rb b/spec/features/dashboard/snippets_spec.rb index 0e248c8732d..4fb01995cb0 100644 --- a/spec/features/dashboard/snippets_spec.rb +++ b/spec/features/dashboard/snippets_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Dashboard snippets' do diff --git a/spec/features/dashboard/todos/target_state_spec.rb b/spec/features/dashboard/todos/target_state_spec.rb index d55c32b3082..931fc16a5eb 100644 --- a/spec/features/dashboard/todos/target_state_spec.rb +++ b/spec/features/dashboard/todos/target_state_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Dashboard > Todo target states' do diff --git a/spec/features/dashboard/todos/todos_filtering_spec.rb b/spec/features/dashboard/todos/todos_filtering_spec.rb index 85f865321cf..f273e416597 100644 --- a/spec/features/dashboard/todos/todos_filtering_spec.rb +++ b/spec/features/dashboard/todos/todos_filtering_spec.rb @@ -1,26 +1,41 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Dashboard > User filters todos', :js do let(:user_1) { create(:user, username: 'user_1', name: 'user_1') } let(:user_2) { create(:user, username: 'user_2', name: 'user_2') } - let(:project_1) { create(:project, name: 'project_1') } - let(:project_2) { create(:project, name: 'project_2') } + let(:group1) { create(:group) } + let(:group2) { create(:group) } + + let(:project_1) { create(:project, name: 'project_1', namespace: group1) } + let(:project_2) { create(:project, name: 'project_2', namespace: group1) } + let(:project_3) { create(:project, name: 'project_3', namespace: group2) } - let(:issue) { create(:issue, title: 'issue', project: project_1) } + let(:issue1) { create(:issue, title: 'issue', project: project_1) } + let(:issue2) { create(:issue, title: 'issue', project: project_3) } let!(:merge_request) { create(:merge_request, source_project: project_2, title: 'merge_request') } before do - create(:todo, user: user_1, author: user_2, project: project_1, target: issue, action: 1) + create(:todo, user: user_1, author: user_2, project: project_1, target: issue1, action: 1) + create(:todo, user: user_1, author: user_2, project: project_3, target: issue2, action: 1) create(:todo, user: user_1, author: user_1, project: project_2, target: merge_request, action: 2) project_1.add_developer(user_1) project_2.add_developer(user_1) + project_3.add_developer(user_1) sign_in(user_1) visit dashboard_todos_path end + it 'displays all todos without a filter' do + expect(page).to have_content issue1.to_reference(full: true) + expect(page).to have_content merge_request.to_reference(full: true) + expect(page).to have_content issue2.to_reference(full: true) + end + it 'filters by project' do click_button 'Project' within '.dropdown-menu-project' do @@ -34,6 +49,20 @@ describe 'Dashboard > User filters todos', :js do expect(page).not_to have_content project_2.full_name end + it 'filters by group' do + click_button 'Group' + within '.dropdown-menu-group' do + fill_in 'Search groups', with: group1.full_name + click_link group1.full_name + end + + wait_for_requests + + expect(page).to have_content issue1.to_reference(full: true) + expect(page).to have_content merge_request.to_reference(full: true) + expect(page).not_to have_content issue2.to_reference(full: true) + end + context 'Author filter' do it 'filters by author' do click_button 'Author' @@ -63,7 +92,7 @@ describe 'Dashboard > User filters todos', :js do it 'shows only authors of existing done todos' do user_3 = create :user user_4 = create :user - create(:todo, user: user_1, author: user_3, project: project_1, target: issue, action: 1, state: :done) + create(:todo, user: user_1, author: user_3, project: project_1, target: issue1, action: 1, state: :done) create(:todo, user: user_1, author: user_4, project: project_2, target: merge_request, action: 2, state: :done) project_1.add_developer(user_3) @@ -92,14 +121,15 @@ describe 'Dashboard > User filters todos', :js do wait_for_requests - expect(find('.todos-list')).to have_content issue.to_reference + expect(find('.todos-list')).to have_content issue1.to_reference + expect(find('.todos-list')).to have_content issue2.to_reference expect(find('.todos-list')).not_to have_content merge_request.to_reference end describe 'filter by action' do before do create(:todo, :build_failed, user: user_1, author: user_2, project: project_1) - create(:todo, :marked, user: user_1, author: user_2, project: project_1, target: issue) + create(:todo, :marked, user: user_1, author: user_2, project: project_1, target: issue1) end it 'filters by Assigned' do diff --git a/spec/features/dashboard/todos/todos_sorting_spec.rb b/spec/features/dashboard/todos/todos_sorting_spec.rb index b87caaa1c07..3870c661784 100644 --- a/spec/features/dashboard/todos/todos_sorting_spec.rb +++ b/spec/features/dashboard/todos/todos_sorting_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Dashboard > User sorts todos' do diff --git a/spec/features/dashboard/todos/todos_spec.rb b/spec/features/dashboard/todos/todos_spec.rb index c48229fc0a0..b98a04b0bda 100644 --- a/spec/features/dashboard/todos/todos_spec.rb +++ b/spec/features/dashboard/todos/todos_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Dashboard Todos' do diff --git a/spec/features/dashboard/user_filters_projects_spec.rb b/spec/features/dashboard/user_filters_projects_spec.rb index 4410c8f887f..c4e4eb8affe 100644 --- a/spec/features/dashboard/user_filters_projects_spec.rb +++ b/spec/features/dashboard/user_filters_projects_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Dashboard > User filters projects' do diff --git a/spec/features/discussion_comments/commit_spec.rb b/spec/features/discussion_comments/commit_spec.rb index b3f1731ec95..0362ddbae82 100644 --- a/spec/features/discussion_comments/commit_spec.rb +++ b/spec/features/discussion_comments/commit_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Thread Comments Commit', :js do diff --git a/spec/features/discussion_comments/issue_spec.rb b/spec/features/discussion_comments/issue_spec.rb index d71a1ee4731..fbceb2a51ae 100644 --- a/spec/features/discussion_comments/issue_spec.rb +++ b/spec/features/discussion_comments/issue_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Thread Comments Issue', :js do diff --git a/spec/features/discussion_comments/merge_request_spec.rb b/spec/features/discussion_comments/merge_request_spec.rb index 86e3507a3ee..96184593655 100644 --- a/spec/features/discussion_comments/merge_request_spec.rb +++ b/spec/features/discussion_comments/merge_request_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Thread Comments Merge Request', :js do diff --git a/spec/features/discussion_comments/snippets_spec.rb b/spec/features/discussion_comments/snippets_spec.rb index 29aa3e4366c..082f35050c0 100644 --- a/spec/features/discussion_comments/snippets_spec.rb +++ b/spec/features/discussion_comments/snippets_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Thread Comments Snippet', :js do diff --git a/spec/features/error_pages_spec.rb b/spec/features/error_pages_spec.rb index cd7bcf29cc9..562277388bb 100644 --- a/spec/features/error_pages_spec.rb +++ b/spec/features/error_pages_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Error Pages' do diff --git a/spec/features/expand_collapse_diffs_spec.rb b/spec/features/expand_collapse_diffs_spec.rb index b2b3382666a..4bd2a305dfa 100644 --- a/spec/features/expand_collapse_diffs_spec.rb +++ b/spec/features/expand_collapse_diffs_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Expand and collapse diffs', :js do diff --git a/spec/features/explore/groups_list_spec.rb b/spec/features/explore/groups_list_spec.rb index 56f6b1f7eaf..9686eee18fc 100644 --- a/spec/features/explore/groups_list_spec.rb +++ b/spec/features/explore/groups_list_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Explore Groups page', :js do diff --git a/spec/features/explore/groups_spec.rb b/spec/features/explore/groups_spec.rb index e4ef47d88dd..81c77a29ecd 100644 --- a/spec/features/explore/groups_spec.rb +++ b/spec/features/explore/groups_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Explore Groups', :js do diff --git a/spec/features/explore/user_explores_projects_spec.rb b/spec/features/explore/user_explores_projects_spec.rb index c724c3d17f8..9c3686dba2d 100644 --- a/spec/features/explore/user_explores_projects_spec.rb +++ b/spec/features/explore/user_explores_projects_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User explores projects' do diff --git a/spec/features/global_search_spec.rb b/spec/features/global_search_spec.rb index f2ab5373d3d..a7ccc6f7d7b 100644 --- a/spec/features/global_search_spec.rb +++ b/spec/features/global_search_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Global search' do @@ -7,6 +9,15 @@ describe 'Global search' do before do project.add_maintainer(user) sign_in(user) + + visit dashboard_projects_path + end + + it 'increases usage ping searches counter' do + expect(Gitlab::UsageDataCounters::SearchCounter).to receive(:increment_navbar_searches_count) + + fill_in "search", with: "foobar" + click_button "Go" end describe 'I search through the issues and I see pagination' do @@ -16,8 +27,6 @@ describe 'Global search' do end it "has a pagination" do - visit dashboard_projects_path - fill_in "search", with: "initial" click_button "Go" @@ -27,8 +36,6 @@ describe 'Global search' do end it 'closes the dropdown on blur', :js do - visit dashboard_projects_path - fill_in 'search', with: "a" dropdown = find('.js-dashboard-search-options') diff --git a/spec/features/group_variables_spec.rb b/spec/features/group_variables_spec.rb index fc5777e8c7c..2b8d37bd629 100644 --- a/spec/features/group_variables_spec.rb +++ b/spec/features/group_variables_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Group variables', :js do diff --git a/spec/features/groups/activity_spec.rb b/spec/features/groups/activity_spec.rb index 88fc12ae1e4..c102e19d477 100644 --- a/spec/features/groups/activity_spec.rb +++ b/spec/features/groups/activity_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Group activity page' do diff --git a/spec/features/groups/board_spec.rb b/spec/features/groups/board_spec.rb index 86a4a016f3d..ca33dbb7a33 100644 --- a/spec/features/groups/board_spec.rb +++ b/spec/features/groups/board_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Group Boards' do diff --git a/spec/features/groups/empty_states_spec.rb b/spec/features/groups/empty_states_spec.rb index e4eb0d355d1..bbc80b7eec4 100644 --- a/spec/features/groups/empty_states_spec.rb +++ b/spec/features/groups/empty_states_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Group empty states' do @@ -110,7 +112,7 @@ describe 'Group empty states' do end context 'group without a project' do - context 'group has a subgroup', :nested_groups do + context 'group has a subgroup' do let(:subgroup) { create(:group, parent: group) } let(:subgroup_project) { create(:project, namespace: subgroup) } diff --git a/spec/features/groups/group_settings_spec.rb b/spec/features/groups/group_settings_spec.rb index 676769c25fe..41ecd21a386 100644 --- a/spec/features/groups/group_settings_spec.rb +++ b/spec/features/groups/group_settings_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Edit group settings' do @@ -121,7 +123,7 @@ describe 'Edit group settings' do expect(find(:css, '.group-root-path').text).to eq(root_url) end - it 'has a parent group URL label for a subgroup group', :postgresql do + it 'has a parent group URL label for a subgroup group' do subgroup = create(:group, parent: group) visit edit_group_path(subgroup) diff --git a/spec/features/groups/issues_spec.rb b/spec/features/groups/issues_spec.rb index 0ada530781c..0cb24ef856b 100644 --- a/spec/features/groups/issues_spec.rb +++ b/spec/features/groups/issues_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Group issues page' do @@ -50,7 +52,7 @@ describe 'Group issues page' do end end - context 'issues list', :nested_groups do + context 'issues list' do let(:subgroup) { create(:group, parent: group) } let(:subgroup_project) { create(:project, :public, group: subgroup)} let(:user_in_group) { create(:group_member, :maintainer, user: create(:user), group: group ).user } diff --git a/spec/features/groups/labels/edit_spec.rb b/spec/features/groups/labels/edit_spec.rb index 7cfc27a8905..43f067b89d6 100644 --- a/spec/features/groups/labels/edit_spec.rb +++ b/spec/features/groups/labels/edit_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Edit group label' do diff --git a/spec/features/groups/labels/subscription_spec.rb b/spec/features/groups/labels/subscription_spec.rb index 22b51b297a6..cbccf4f3880 100644 --- a/spec/features/groups/labels/subscription_spec.rb +++ b/spec/features/groups/labels/subscription_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Labels subscription' do diff --git a/spec/features/groups/labels/user_sees_links_to_issuables.rb b/spec/features/groups/labels/user_sees_links_to_issuables.rb index 1fdba78fa6c..e636f625b31 100644 --- a/spec/features/groups/labels/user_sees_links_to_issuables.rb +++ b/spec/features/groups/labels/user_sees_links_to_issuables.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Groups > Labels > User sees links to issuables' do diff --git a/spec/features/groups/members/filter_members_spec.rb b/spec/features/groups/members/filter_members_spec.rb index 386d81546d7..7aad66ec08f 100644 --- a/spec/features/groups/members/filter_members_spec.rb +++ b/spec/features/groups/members/filter_members_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Groups > Members > Filter members' do diff --git a/spec/features/groups/members/leave_group_spec.rb b/spec/features/groups/members/leave_group_spec.rb index 439803f9255..df15f995be4 100644 --- a/spec/features/groups/members/leave_group_spec.rb +++ b/spec/features/groups/members/leave_group_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Groups > Members > Leave group' do diff --git a/spec/features/groups/members/list_members_spec.rb b/spec/features/groups/members/list_members_spec.rb index 4ba7161601e..8df807186be 100644 --- a/spec/features/groups/members/list_members_spec.rb +++ b/spec/features/groups/members/list_members_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Groups > Members > List members' do @@ -13,7 +15,7 @@ describe 'Groups > Members > List members' do sign_in(user1) end - it 'show members from current group and parent', :nested_groups do + it 'show members from current group and parent' do group.add_developer(user1) nested_group.add_developer(user2) @@ -23,7 +25,7 @@ describe 'Groups > Members > List members' do expect(second_row.text).to include(user2.name) end - it 'show user once if member of both current group and parent', :nested_groups do + it 'show user once if member of both current group and parent' do group.add_developer(user1) nested_group.add_developer(user1) diff --git a/spec/features/groups/members/manage_members_spec.rb b/spec/features/groups/members/manage_members_spec.rb index e2b4a491a13..779fa74501a 100644 --- a/spec/features/groups/members/manage_members_spec.rb +++ b/spec/features/groups/members/manage_members_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Groups > Members > Manage members' do diff --git a/spec/features/groups/members/master_manages_access_requests_spec.rb b/spec/features/groups/members/master_manages_access_requests_spec.rb index bd615c99412..454da126c81 100644 --- a/spec/features/groups/members/master_manages_access_requests_spec.rb +++ b/spec/features/groups/members/master_manages_access_requests_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Groups > Members > Maintainer manages access requests' do diff --git a/spec/features/groups/members/request_access_spec.rb b/spec/features/groups/members/request_access_spec.rb index 94510f917a3..0d5321709ae 100644 --- a/spec/features/groups/members/request_access_spec.rb +++ b/spec/features/groups/members/request_access_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Groups > Members > Request access' do diff --git a/spec/features/groups/members/search_members_spec.rb b/spec/features/groups/members/search_members_spec.rb index e7efdf7dfef..d2d084c9174 100644 --- a/spec/features/groups/members/search_members_spec.rb +++ b/spec/features/groups/members/search_members_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Search group member' do diff --git a/spec/features/groups/members/sort_members_spec.rb b/spec/features/groups/members/sort_members_spec.rb index ee32f6d77fe..11770e6ac2a 100644 --- a/spec/features/groups/members/sort_members_spec.rb +++ b/spec/features/groups/members/sort_members_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Groups > Members > Sort members' do diff --git a/spec/features/groups/milestone_spec.rb b/spec/features/groups/milestone_spec.rb index d57eb87ca77..7f0155b63e0 100644 --- a/spec/features/groups/milestone_spec.rb +++ b/spec/features/groups/milestone_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Group milestones' do diff --git a/spec/features/groups/milestones_sorting_spec.rb b/spec/features/groups/milestones_sorting_spec.rb index 7bc015ea28f..d27511be0b0 100644 --- a/spec/features/groups/milestones_sorting_spec.rb +++ b/spec/features/groups/milestones_sorting_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Milestones sorting', :js do diff --git a/spec/features/groups/settings/group_badges_spec.rb b/spec/features/groups/settings/group_badges_spec.rb index a5c8dbf18d0..9236a50cce5 100644 --- a/spec/features/groups/settings/group_badges_spec.rb +++ b/spec/features/groups/settings/group_badges_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Group Badges' do diff --git a/spec/features/groups/share_lock_spec.rb b/spec/features/groups/share_lock_spec.rb index 704d9f12888..777f5d98720 100644 --- a/spec/features/groups/share_lock_spec.rb +++ b/spec/features/groups/share_lock_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Group share with group lock' do @@ -9,7 +11,7 @@ describe 'Group share with group lock' do sign_in(root_owner) end - context 'with a subgroup', :nested_groups do + context 'with a subgroup' do let!(:subgroup) { create(:group, parent: root_group) } context 'when enabling the parent group share with group lock' do diff --git a/spec/features/groups/show_spec.rb b/spec/features/groups/show_spec.rb index bed998a0859..942a9889488 100644 --- a/spec/features/groups/show_spec.rb +++ b/spec/features/groups/show_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Group show page' do @@ -75,11 +77,7 @@ describe 'Group show page' do sign_in(owner) end - context 'when subgroups are supported', :nested_groups do - before do - allow(Group).to receive(:supports_nested_objects?) { true } - end - + context 'when subgroups are supported' do it 'allows creating subgroups' do visit path @@ -87,19 +85,6 @@ describe 'Group show page' do .to have_css("li[data-text='New subgroup']", visible: false) end end - - context 'when subgroups are not supported' do - before do - allow(Group).to receive(:supports_nested_objects?) { false } - end - - it 'does not allow creating subgroups' do - visit path - - expect(page) - .not_to have_selector("li[data-text='New subgroup']", visible: false) - end - end end context 'for maintainers' do @@ -107,11 +92,7 @@ describe 'Group show page' do sign_in(maintainer) end - context 'when subgroups are supported', :nested_groups do - before do - allow(Group).to receive(:supports_nested_objects?) { true } - end - + context 'when subgroups are supported' do context 'when subgroup_creation_level is set to maintainers' do before do relaxed_group.add_maintainer(maintainer) @@ -141,19 +122,6 @@ describe 'Group show page' do end end end - - context 'when subgroups are not supported' do - before do - allow(Group).to receive(:supports_nested_objects?) { false } - end - - it 'does not allow creating subgroups' do - visit path - - expect(page) - .not_to have_selector("li[data-text='New subgroup']", visible: false) - end - end end end diff --git a/spec/features/groups/user_browse_projects_group_page_spec.rb b/spec/features/groups/user_browse_projects_group_page_spec.rb index 916363c41dd..075bc1128ca 100644 --- a/spec/features/groups/user_browse_projects_group_page_spec.rb +++ b/spec/features/groups/user_browse_projects_group_page_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'User browse group projects page' do diff --git a/spec/features/groups/user_sees_users_dropdowns_in_issuables_list_spec.rb b/spec/features/groups/user_sees_users_dropdowns_in_issuables_list_spec.rb index 6d6f206d761..742021ae4a1 100644 --- a/spec/features/groups/user_sees_users_dropdowns_in_issuables_list_spec.rb +++ b/spec/features/groups/user_sees_users_dropdowns_in_issuables_list_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Groups > User sees users dropdowns in issuables list' do diff --git a/spec/features/groups_spec.rb b/spec/features/groups_spec.rb index 8e7f78cab81..ca994c95df8 100644 --- a/spec/features/groups_spec.rb +++ b/spec/features/groups_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Group' do @@ -105,7 +107,7 @@ describe 'Group' do end end - describe 'create a nested group', :nested_groups, :js do + describe 'create a nested group', :js do let(:group) { create(:group, path: 'foo') } context 'as admin' do @@ -231,7 +233,7 @@ describe 'Group' do end end - describe 'group page with nested groups', :nested_groups, :js do + describe 'group page with nested groups', :js do let!(:group) { create(:group) } let!(:nested_group) { create(:group, parent: group) } let!(:project) { create(:project, namespace: group) } diff --git a/spec/features/ics/dashboard_issues_spec.rb b/spec/features/ics/dashboard_issues_spec.rb index b74bbf848ac..bde5488f375 100644 --- a/spec/features/ics/dashboard_issues_spec.rb +++ b/spec/features/ics/dashboard_issues_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Dashboard Issues Calendar Feed' do @@ -91,7 +93,7 @@ describe 'Dashboard Issues Calendar Feed' do expect(body).to have_text("SUMMARY:test title (in #{project.full_path})") # line length for ics is 75 chars - expected_description = "DESCRIPTION:Find out more at #{issue_url(issue)}".insert(75, ' ') + expected_description = (+"DESCRIPTION:Find out more at #{issue_url(issue)}").insert(75, ' ') expect(body).to have_text(expected_description) expect(body).to have_text("DTSTART;VALUE=DATE:#{Date.tomorrow.strftime('%Y%m%d')}") expect(body).to have_text("URL:#{issue_url(issue)}") diff --git a/spec/features/ics/group_issues_spec.rb b/spec/features/ics/group_issues_spec.rb index 86da720c8be..0b317095678 100644 --- a/spec/features/ics/group_issues_spec.rb +++ b/spec/features/ics/group_issues_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Group Issues Calendar Feed' do @@ -66,7 +68,7 @@ describe 'Group Issues Calendar Feed' do expect(body).to have_text("SUMMARY:test title (in #{project.full_path})") # line length for ics is 75 chars - expected_description = "DESCRIPTION:Find out more at #{issue_url(issue)}".insert(75, ' ') + expected_description = (+"DESCRIPTION:Find out more at #{issue_url(issue)}").insert(75, ' ') expect(body).to have_text(expected_description) expect(body).to have_text("DTSTART;VALUE=DATE:#{Date.tomorrow.strftime('%Y%m%d')}") expect(body).to have_text("URL:#{issue_url(issue)}") diff --git a/spec/features/ics/project_issues_spec.rb b/spec/features/ics/project_issues_spec.rb index 37b90c666bc..3c940149670 100644 --- a/spec/features/ics/project_issues_spec.rb +++ b/spec/features/ics/project_issues_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Project Issues Calendar Feed' do @@ -65,7 +67,7 @@ describe 'Project Issues Calendar Feed' do expect(body).to have_text("SUMMARY:test title (in #{project.full_path})") # line length for ics is 75 chars - expected_description = "DESCRIPTION:Find out more at #{issue_url(issue)}".insert(75, ' ') + expected_description = (+"DESCRIPTION:Find out more at #{issue_url(issue)}").insert(75, ' ') expect(body).to have_text(expected_description) expect(body).to have_text("DTSTART;VALUE=DATE:#{Date.tomorrow.strftime('%Y%m%d')}") expect(body).to have_text("URL:#{issue_url(issue)}") diff --git a/spec/features/ide/user_opens_merge_request_spec.rb b/spec/features/ide/user_opens_merge_request_spec.rb index 185349219a7..03318287db9 100644 --- a/spec/features/ide/user_opens_merge_request_spec.rb +++ b/spec/features/ide/user_opens_merge_request_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'IDE merge request', :js do diff --git a/spec/features/ide_spec.rb b/spec/features/ide_spec.rb index 6eb59ef72c2..73f6180d944 100644 --- a/spec/features/ide_spec.rb +++ b/spec/features/ide_spec.rb @@ -1,7 +1,9 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'IDE', :js do - describe 'sub-groups', :nested_groups do + describe 'sub-groups' do let(:user) { create(:user) } let(:group) { create(:group) } let(:subgroup) { create(:group, parent: group) } diff --git a/spec/features/import/manifest_import_spec.rb b/spec/features/import/manifest_import_spec.rb index a90cdd8d920..e9471257544 100644 --- a/spec/features/import/manifest_import_spec.rb +++ b/spec/features/import/manifest_import_spec.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + require 'spec_helper' -describe 'Import multiple repositories by uploading a manifest file', :js, :postgresql do +describe 'Import multiple repositories by uploading a manifest file', :js do include Select2Helper let(:user) { create(:admin) } diff --git a/spec/features/instance_statistics/cohorts_spec.rb b/spec/features/instance_statistics/cohorts_spec.rb index 40e65515ceb..61294ec9af2 100644 --- a/spec/features/instance_statistics/cohorts_spec.rb +++ b/spec/features/instance_statistics/cohorts_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Cohorts page' do diff --git a/spec/features/instance_statistics/instance_statistics.rb b/spec/features/instance_statistics/instance_statistics.rb index d03e6e68075..40d0f1db207 100644 --- a/spec/features/instance_statistics/instance_statistics.rb +++ b/spec/features/instance_statistics/instance_statistics.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Cohorts page', :js do diff --git a/spec/features/invites_spec.rb b/spec/features/invites_spec.rb index 9e1a12a9c2a..855cf22642e 100644 --- a/spec/features/invites_spec.rb +++ b/spec/features/invites_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Invites' do diff --git a/spec/features/issuables/close_reopen_report_toggle_spec.rb b/spec/features/issuables/close_reopen_report_toggle_spec.rb index 26c44baeb21..8805018902f 100644 --- a/spec/features/issuables/close_reopen_report_toggle_spec.rb +++ b/spec/features/issuables/close_reopen_report_toggle_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Issuables Close/Reopen/Report toggle' do diff --git a/spec/features/issuables/discussion_lock_spec.rb b/spec/features/issuables/discussion_lock_spec.rb index 7ea29ff252b..0cd2c077081 100644 --- a/spec/features/issuables/discussion_lock_spec.rb +++ b/spec/features/issuables/discussion_lock_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Discussion Lock', :js do diff --git a/spec/features/issuables/issuable_list_spec.rb b/spec/features/issuables/issuable_list_spec.rb index 225b858742d..dc68e633e27 100644 --- a/spec/features/issuables/issuable_list_spec.rb +++ b/spec/features/issuables/issuable_list_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'issuable list' do diff --git a/spec/features/issuables/markdown_references/internal_references_spec.rb b/spec/features/issuables/markdown_references/internal_references_spec.rb index 870e92b8de8..e84629dc17f 100644 --- a/spec/features/issuables/markdown_references/internal_references_spec.rb +++ b/spec/features/issuables/markdown_references/internal_references_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" describe "Internal references", :js do diff --git a/spec/features/issuables/markdown_references/jira_spec.rb b/spec/features/issuables/markdown_references/jira_spec.rb index 8eaccfc0949..aecdeffe4a4 100644 --- a/spec/features/issuables/markdown_references/jira_spec.rb +++ b/spec/features/issuables/markdown_references/jira_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" describe "Jira", :js do diff --git a/spec/features/issuables/shortcuts_issuable_spec.rb b/spec/features/issuables/shortcuts_issuable_spec.rb index a19101366a0..da8a0dd7b0f 100644 --- a/spec/features/issuables/shortcuts_issuable_spec.rb +++ b/spec/features/issuables/shortcuts_issuable_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Blob shortcuts', :js do diff --git a/spec/features/issuables/sorting_list_spec.rb b/spec/features/issuables/sorting_list_spec.rb index 3a46a4e0167..b4531f5da4e 100644 --- a/spec/features/issuables/sorting_list_spec.rb +++ b/spec/features/issuables/sorting_list_spec.rb @@ -102,7 +102,7 @@ describe 'Sort Issuable List' do expect(first_merge_request).to include(last_updated_issuable.title) expect(last_merge_request).to include(first_updated_issuable.title) - find('.issues-other-filters .filter-dropdown-container .qa-reverse-sort').click + find('.issues-other-filters .filter-dropdown-container .rspec-reverse-sort').click expect(first_merge_request).to include(first_updated_issuable.title) expect(last_merge_request).to include(last_updated_issuable.title) @@ -204,7 +204,7 @@ describe 'Sort Issuable List' do expect(first_issue).to include(last_updated_issuable.title) expect(last_issue).to include(first_updated_issuable.title) - find('.issues-other-filters .filter-dropdown-container .qa-reverse-sort').click + find('.issues-other-filters .filter-dropdown-container .rspec-reverse-sort').click expect(first_issue).to include(first_updated_issuable.title) expect(last_issue).to include(last_updated_issuable.title) diff --git a/spec/features/issuables/user_sees_sidebar_spec.rb b/spec/features/issuables/user_sees_sidebar_spec.rb index c6c2e58ecea..d1e10c70414 100644 --- a/spec/features/issuables/user_sees_sidebar_spec.rb +++ b/spec/features/issuables/user_sees_sidebar_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Issue Sidebar on Mobile' do diff --git a/spec/features/issues/bulk_assignment_labels_spec.rb b/spec/features/issues/bulk_assignment_labels_spec.rb index 7be5961af09..e8b828bd264 100644 --- a/spec/features/issues/bulk_assignment_labels_spec.rb +++ b/spec/features/issues/bulk_assignment_labels_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Issues > Labels bulk assignment' do diff --git a/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb b/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb index f6dccb5e98a..f2e482faf5f 100644 --- a/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb +++ b/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Resolving all open threads in a merge request from an issue', :js do diff --git a/spec/features/issues/create_issue_for_single_discussion_in_merge_request_spec.rb b/spec/features/issues/create_issue_for_single_discussion_in_merge_request_spec.rb index 1b1a31d0723..08c98358544 100644 --- a/spec/features/issues/create_issue_for_single_discussion_in_merge_request_spec.rb +++ b/spec/features/issues/create_issue_for_single_discussion_in_merge_request_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Resolve an open thread in a merge request by creating an issue', :js do diff --git a/spec/features/issues/filtered_search/dropdown_assignee_spec.rb b/spec/features/issues/filtered_search/dropdown_assignee_spec.rb index 75313442b65..2ca551cec77 100644 --- a/spec/features/issues/filtered_search/dropdown_assignee_spec.rb +++ b/spec/features/issues/filtered_search/dropdown_assignee_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Dropdown assignee', :js do diff --git a/spec/features/issues/filtered_search/dropdown_author_spec.rb b/spec/features/issues/filtered_search/dropdown_author_spec.rb index bc8d9bc8450..b2905fc1dde 100644 --- a/spec/features/issues/filtered_search/dropdown_author_spec.rb +++ b/spec/features/issues/filtered_search/dropdown_author_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Dropdown author', :js do diff --git a/spec/features/issues/filtered_search/dropdown_emoji_spec.rb b/spec/features/issues/filtered_search/dropdown_emoji_spec.rb index a5c3ab7e7d0..45344aeb8f5 100644 --- a/spec/features/issues/filtered_search/dropdown_emoji_spec.rb +++ b/spec/features/issues/filtered_search/dropdown_emoji_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Dropdown emoji', :js do diff --git a/spec/features/issues/filtered_search/dropdown_hint_spec.rb b/spec/features/issues/filtered_search/dropdown_hint_spec.rb index 1f4e9e79179..34313553b34 100644 --- a/spec/features/issues/filtered_search/dropdown_hint_spec.rb +++ b/spec/features/issues/filtered_search/dropdown_hint_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Dropdown hint', :js do diff --git a/spec/features/issues/filtered_search/dropdown_label_spec.rb b/spec/features/issues/filtered_search/dropdown_label_spec.rb index f502061dfce..f7f9f0de4db 100644 --- a/spec/features/issues/filtered_search/dropdown_label_spec.rb +++ b/spec/features/issues/filtered_search/dropdown_label_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Dropdown label', :js do diff --git a/spec/features/issues/filtered_search/dropdown_milestone_spec.rb b/spec/features/issues/filtered_search/dropdown_milestone_spec.rb index 7a6f76cb382..8429fe44c43 100644 --- a/spec/features/issues/filtered_search/dropdown_milestone_spec.rb +++ b/spec/features/issues/filtered_search/dropdown_milestone_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Dropdown milestone', :js do diff --git a/spec/features/issues/filtered_search/filter_issues_spec.rb b/spec/features/issues/filtered_search/filter_issues_spec.rb index fa8e5cb0ca9..8b5e7934ec1 100644 --- a/spec/features/issues/filtered_search/filter_issues_spec.rb +++ b/spec/features/issues/filtered_search/filter_issues_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Filter issues', :js do diff --git a/spec/features/issues/filtered_search/recent_searches_spec.rb b/spec/features/issues/filtered_search/recent_searches_spec.rb index 41b9ada988a..c038281d825 100644 --- a/spec/features/issues/filtered_search/recent_searches_spec.rb +++ b/spec/features/issues/filtered_search/recent_searches_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Recent searches', :js do diff --git a/spec/features/issues/filtered_search/search_bar_spec.rb b/spec/features/issues/filtered_search/search_bar_spec.rb index da23aea1fc9..0fe03160e7a 100644 --- a/spec/features/issues/filtered_search/search_bar_spec.rb +++ b/spec/features/issues/filtered_search/search_bar_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Search bar', :js do diff --git a/spec/features/issues/filtered_search/visual_tokens_spec.rb b/spec/features/issues/filtered_search/visual_tokens_spec.rb index 9fd661d80ae..b20add1ea33 100644 --- a/spec/features/issues/filtered_search/visual_tokens_spec.rb +++ b/spec/features/issues/filtered_search/visual_tokens_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Visual tokens', :js do diff --git a/spec/features/issues/form_spec.rb b/spec/features/issues/form_spec.rb index 597af566f9c..e840ac79916 100644 --- a/spec/features/issues/form_spec.rb +++ b/spec/features/issues/form_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'New/edit issue', :js do diff --git a/spec/features/issues/gfm_autocomplete_spec.rb b/spec/features/issues/gfm_autocomplete_spec.rb index 40845ec48f9..566441dc6f6 100644 --- a/spec/features/issues/gfm_autocomplete_spec.rb +++ b/spec/features/issues/gfm_autocomplete_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'GFM autocomplete', :js do diff --git a/spec/features/issues/group_label_sidebar_spec.rb b/spec/features/issues/group_label_sidebar_spec.rb index 9c10f78f67a..746c55b6a26 100644 --- a/spec/features/issues/group_label_sidebar_spec.rb +++ b/spec/features/issues/group_label_sidebar_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Group label on issue' do diff --git a/spec/features/issues/issue_detail_spec.rb b/spec/features/issues/issue_detail_spec.rb index 791bd003597..8f2e5b237ea 100644 --- a/spec/features/issues/issue_detail_spec.rb +++ b/spec/features/issues/issue_detail_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Issue Detail', :js do diff --git a/spec/features/issues/issue_sidebar_spec.rb b/spec/features/issues/issue_sidebar_spec.rb index 321da8f44d7..b88d1bbeae5 100644 --- a/spec/features/issues/issue_sidebar_spec.rb +++ b/spec/features/issues/issue_sidebar_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Issue Sidebar' do diff --git a/spec/features/issues/keyboard_shortcut_spec.rb b/spec/features/issues/keyboard_shortcut_spec.rb index 961de9d3d25..e1325e63e6b 100644 --- a/spec/features/issues/keyboard_shortcut_spec.rb +++ b/spec/features/issues/keyboard_shortcut_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Issues shortcut', :js do diff --git a/spec/features/issues/markdown_toolbar_spec.rb b/spec/features/issues/markdown_toolbar_spec.rb index 94bd7c53bb5..b80b47a4c99 100644 --- a/spec/features/issues/markdown_toolbar_spec.rb +++ b/spec/features/issues/markdown_toolbar_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Issue markdown toolbar', :js do diff --git a/spec/features/issues/move_spec.rb b/spec/features/issues/move_spec.rb index 2abc50b04e4..9e0be7d8935 100644 --- a/spec/features/issues/move_spec.rb +++ b/spec/features/issues/move_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'issue move to another project' do diff --git a/spec/features/issues/note_polling_spec.rb b/spec/features/issues/note_polling_spec.rb index 3cd7ce6dada..04ad012d57e 100644 --- a/spec/features/issues/note_polling_spec.rb +++ b/spec/features/issues/note_polling_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Issue notes polling', :js do diff --git a/spec/features/issues/notes_on_issues_spec.rb b/spec/features/issues/notes_on_issues_spec.rb index fed77453cbb..5247baa58a1 100644 --- a/spec/features/issues/notes_on_issues_spec.rb +++ b/spec/features/issues/notes_on_issues_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Create notes on issues', :js do diff --git a/spec/features/issues/rss_spec.rb b/spec/features/issues/rss_spec.rb index 0e1383cd607..d6a406f4f44 100644 --- a/spec/features/issues/rss_spec.rb +++ b/spec/features/issues/rss_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Project Issues RSS' do diff --git a/spec/features/issues/spam_issues_spec.rb b/spec/features/issues/spam_issues_spec.rb index 7cce45ff206..85c72c42f45 100644 --- a/spec/features/issues/spam_issues_spec.rb +++ b/spec/features/issues/spam_issues_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'New issue', :js do diff --git a/spec/features/issues/todo_spec.rb b/spec/features/issues/todo_spec.rb index 07ae159eef4..9282c31751a 100644 --- a/spec/features/issues/todo_spec.rb +++ b/spec/features/issues/todo_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Manually create a todo item from issue', :js do diff --git a/spec/features/issues/update_issues_spec.rb b/spec/features/issues/update_issues_spec.rb index fd8629ae504..0e27d0231d0 100644 --- a/spec/features/issues/update_issues_spec.rb +++ b/spec/features/issues/update_issues_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Multiple issue updating from issues#index', :js do diff --git a/spec/features/issues/user_comments_on_issue_spec.rb b/spec/features/issues/user_comments_on_issue_spec.rb index 4b29f6ee42a..bdaaea5bf7f 100644 --- a/spec/features/issues/user_comments_on_issue_spec.rb +++ b/spec/features/issues/user_comments_on_issue_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "spec_helper" describe "User comments on issue", :js do diff --git a/spec/features/issues/user_creates_branch_and_merge_request_spec.rb b/spec/features/issues/user_creates_branch_and_merge_request_spec.rb index f9103d83ba0..878a73718d7 100644 --- a/spec/features/issues/user_creates_branch_and_merge_request_spec.rb +++ b/spec/features/issues/user_creates_branch_and_merge_request_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'User creates branch and merge request on issue page', :js do diff --git a/spec/features/issues/user_creates_confidential_merge_request_spec.rb b/spec/features/issues/user_creates_confidential_merge_request_spec.rb index 7ae4af4667b..4a32b7e2b73 100644 --- a/spec/features/issues/user_creates_confidential_merge_request_spec.rb +++ b/spec/features/issues/user_creates_confidential_merge_request_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'User creates confidential merge request on issue page', :js do diff --git a/spec/features/issues/user_creates_issue_spec.rb b/spec/features/issues/user_creates_issue_spec.rb index 2789d574156..a71395c0e47 100644 --- a/spec/features/issues/user_creates_issue_spec.rb +++ b/spec/features/issues/user_creates_issue_spec.rb @@ -28,7 +28,7 @@ describe "User creates issue" do fill_in("Title", with: issue_title) first('.js-md').click - first('.qa-issuable-form-description').native.send_keys('Description') + first('.rspec-issuable-form-description').native.send_keys('Description') click_button("Submit issue") diff --git a/spec/features/issues/user_edits_issue_spec.rb b/spec/features/issues/user_edits_issue_spec.rb index 60b88ef4bdf..0afc19d9519 100644 --- a/spec/features/issues/user_edits_issue_spec.rb +++ b/spec/features/issues/user_edits_issue_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "spec_helper" describe "User edits issue", :js do diff --git a/spec/features/issues/user_interacts_with_awards_spec.rb b/spec/features/issues/user_interacts_with_awards_spec.rb index d117620a2b1..eab18b72c86 100644 --- a/spec/features/issues/user_interacts_with_awards_spec.rb +++ b/spec/features/issues/user_interacts_with_awards_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User interacts with awards' do diff --git a/spec/features/issues/user_sees_breadcrumb_links_spec.rb b/spec/features/issues/user_sees_breadcrumb_links_spec.rb index 43369f7609f..db8d3c5dd53 100644 --- a/spec/features/issues/user_sees_breadcrumb_links_spec.rb +++ b/spec/features/issues/user_sees_breadcrumb_links_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'New issue breadcrumb' do diff --git a/spec/features/issues/user_sorts_issues_spec.rb b/spec/features/issues/user_sorts_issues_spec.rb index eebd2d57cca..79938785633 100644 --- a/spec/features/issues/user_sorts_issues_spec.rb +++ b/spec/features/issues/user_sorts_issues_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "spec_helper" describe "User sorts issues" do diff --git a/spec/features/issues/user_toggles_subscription_spec.rb b/spec/features/issues/user_toggles_subscription_spec.rb index c2b2a193682..7a721adc8dd 100644 --- a/spec/features/issues/user_toggles_subscription_spec.rb +++ b/spec/features/issues/user_toggles_subscription_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "spec_helper" describe "User toggles subscription", :js do diff --git a/spec/features/issues/user_views_issue_spec.rb b/spec/features/issues/user_views_issue_spec.rb index 330b6f0e77a..dd04ac94105 100644 --- a/spec/features/issues/user_views_issue_spec.rb +++ b/spec/features/issues/user_views_issue_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "spec_helper" describe "User views issue" do diff --git a/spec/features/issues/user_views_issues_spec.rb b/spec/features/issues/user_views_issues_spec.rb index 58afb4efb86..b986991f38f 100644 --- a/spec/features/issues/user_views_issues_spec.rb +++ b/spec/features/issues/user_views_issues_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "spec_helper" describe "User views issues" do diff --git a/spec/features/labels_hierarchy_spec.rb b/spec/features/labels_hierarchy_spec.rb index 489651fea15..b7a45905845 100644 --- a/spec/features/labels_hierarchy_spec.rb +++ b/spec/features/labels_hierarchy_spec.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + require 'spec_helper' -describe 'Labels Hierarchy', :js, :nested_groups do +describe 'Labels Hierarchy', :js do include FilteredSearchHelpers let!(:user) { create(:user) } diff --git a/spec/features/markdown/copy_as_gfm_spec.rb b/spec/features/markdown/copy_as_gfm_spec.rb index c30ac9c4ae2..c098a1b3e3a 100644 --- a/spec/features/markdown/copy_as_gfm_spec.rb +++ b/spec/features/markdown/copy_as_gfm_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Copy as GFM', :js do @@ -416,8 +418,8 @@ describe 'Copy as GFM', :js do html = <<~HTML <div class="md-suggestion"> - <div class="md-suggestion-header border-bottom-0 mt-2 qa-suggestion-diff-header"> - <div class="qa-suggestion-diff-header font-weight-bold"> + <div class="md-suggestion-header border-bottom-0 mt-2 qa-suggestion-diff-header js-suggestion-diff-header"> + <div class="qa-suggestion-diff-header js-suggestion-diff-header font-weight-bold"> Suggested change <a href="/gitlab/help/user/discussions/index.md#suggest-changes" aria-label="Help" class="js-help-btn"> <svg aria-hidden="true" class="s16 ic-question-o link-highlight"> @@ -426,7 +428,7 @@ describe 'Copy as GFM', :js do </a> </div> <!----> - <button type="button" class="btn qa-apply-btn">Apply suggestion</button> + <button type="button" class="btn qa-apply-btn js-apply-btn">Apply suggestion</button> </div> <table class="mb-3 md-suggestion-diff js-syntax-highlight code white"> <tbody> @@ -796,7 +798,7 @@ describe 'Copy as GFM', :js do context 'selecting one word of text' do it 'copies as inline code' do verify( - '.line[id="LC27"] .s2', + '.line[id="LC27"] .nl', '`"bio"`' ) diff --git a/spec/features/markdown/gitlab_flavored_markdown_spec.rb b/spec/features/markdown/gitlab_flavored_markdown_spec.rb index 8fda3c7193e..f34af268630 100644 --- a/spec/features/markdown/gitlab_flavored_markdown_spec.rb +++ b/spec/features/markdown/gitlab_flavored_markdown_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe "GitLab Flavored Markdown" do diff --git a/spec/features/markdown/markdown_spec.rb b/spec/features/markdown/markdown_spec.rb index 8815643ca96..0efeffe3232 100644 --- a/spec/features/markdown/markdown_spec.rb +++ b/spec/features/markdown/markdown_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' require 'erb' diff --git a/spec/features/markdown/math_spec.rb b/spec/features/markdown/math_spec.rb index 16ad0d456be..68d99b4241a 100644 --- a/spec/features/markdown/math_spec.rb +++ b/spec/features/markdown/math_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Math rendering', :js do diff --git a/spec/features/markdown/mermaid_spec.rb b/spec/features/markdown/mermaid_spec.rb index e3bcaca737e..aaaceebc216 100644 --- a/spec/features/markdown/mermaid_spec.rb +++ b/spec/features/markdown/mermaid_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Mermaid rendering', :js do diff --git a/spec/features/markdown/metrics_spec.rb b/spec/features/markdown/metrics_spec.rb new file mode 100644 index 00000000000..aa53ac50c78 --- /dev/null +++ b/spec/features/markdown/metrics_spec.rb @@ -0,0 +1,60 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'Metrics rendering', :js, :use_clean_rails_memory_store_caching do + include PrometheusHelpers + + let(:user) { create(:user) } + let(:project) { create(:prometheus_project) } + let(:environment) { create(:environment, project: project) } + let(:issue) { create(:issue, project: project, description: description) } + let(:description) { "See [metrics dashboard](#{metrics_url}) for info." } + let(:metrics_url) { metrics_project_environment_url(project, environment) } + + before do + configure_host + import_common_metrics + stub_any_prometheus_request_with_response + + project.add_developer(user) + + sign_in(user) + end + + after do + restore_host + end + + context 'with deployments and related deployable present' do + it 'shows embedded metrics' do + visit project_issue_path(project, issue) + + expect(page).to have_css('div.prometheus-graph') + expect(page).to have_text('Memory Usage (Total)') + expect(page).to have_text('Core Usage (Total)') + end + end + + def import_common_metrics + ::Gitlab::DatabaseImporters::CommonMetrics::Importer.new.execute + end + + def configure_host + @original_default_host = default_url_options[:host] + @original_gitlab_url = Gitlab.config.gitlab[:url] + + # Ensure we create a metrics url with the right host. + # Configure host for route helpers in specs (also updates root_url): + default_url_options[:host] = Capybara.server_host + + # Ensure we identify urls with the appropriate host. + # Configure host to include port in app: + Gitlab.config.gitlab[:url] = root_url.chomp('/') + end + + def restore_host + default_url_options[:host] = @original_default_host + Gitlab.config.gitlab[:url] = @original_gitlab_url + end +end diff --git a/spec/features/merge_request/maintainer_edits_fork_spec.rb b/spec/features/merge_request/maintainer_edits_fork_spec.rb index b35f985126c..030638cba71 100644 --- a/spec/features/merge_request/maintainer_edits_fork_spec.rb +++ b/spec/features/merge_request/maintainer_edits_fork_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'a maintainer edits files on a source-branch of an MR from a fork', :js do diff --git a/spec/features/merge_request/user_accepts_merge_request_spec.rb b/spec/features/merge_request/user_accepts_merge_request_spec.rb index 3d029ccec1a..4d305d43351 100644 --- a/spec/features/merge_request/user_accepts_merge_request_spec.rb +++ b/spec/features/merge_request/user_accepts_merge_request_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User accepts a merge request', :js do diff --git a/spec/features/merge_request/user_allows_commits_from_memebers_who_can_merge_spec.rb b/spec/features/merge_request/user_allows_commits_from_memebers_who_can_merge_spec.rb index b8c4a78e24f..be403abcc4d 100644 --- a/spec/features/merge_request/user_allows_commits_from_memebers_who_can_merge_spec.rb +++ b/spec/features/merge_request/user_allows_commits_from_memebers_who_can_merge_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'create a merge request, allowing commits from members who can merge to the target branch', :js do diff --git a/spec/features/merge_request/user_assigns_themselves_spec.rb b/spec/features/merge_request/user_assigns_themselves_spec.rb index 41cc7cef777..d7918a9e9d7 100644 --- a/spec/features/merge_request/user_assigns_themselves_spec.rb +++ b/spec/features/merge_request/user_assigns_themselves_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Merge request > User assigns themselves' do diff --git a/spec/features/merge_request/user_awards_emoji_spec.rb b/spec/features/merge_request/user_awards_emoji_spec.rb index 93376bc8ce0..5e9b232760b 100644 --- a/spec/features/merge_request/user_awards_emoji_spec.rb +++ b/spec/features/merge_request/user_awards_emoji_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Merge request > User awards emoji', :js do diff --git a/spec/features/merge_request/user_closes_merge_request_spec.rb b/spec/features/merge_request/user_closes_merge_request_spec.rb index 2d12d690151..c5125c38ed7 100644 --- a/spec/features/merge_request/user_closes_merge_request_spec.rb +++ b/spec/features/merge_request/user_closes_merge_request_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User closes a merge requests', :js do diff --git a/spec/features/merge_request/user_comments_on_commit_spec.rb b/spec/features/merge_request/user_comments_on_commit_spec.rb index 8ea358bcc70..6b869d93e4c 100644 --- a/spec/features/merge_request/user_comments_on_commit_spec.rb +++ b/spec/features/merge_request/user_comments_on_commit_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User comments on a commit', :js do diff --git a/spec/features/merge_request/user_comments_on_diff_spec.rb b/spec/features/merge_request/user_comments_on_diff_spec.rb index eb4b2cf5bd0..19b8a7f74b7 100644 --- a/spec/features/merge_request/user_comments_on_diff_spec.rb +++ b/spec/features/merge_request/user_comments_on_diff_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User comments on a diff', :js do diff --git a/spec/features/merge_request/user_comments_on_merge_request_spec.rb b/spec/features/merge_request/user_comments_on_merge_request_spec.rb index e6bc3780b5c..c7845b4cce4 100644 --- a/spec/features/merge_request/user_comments_on_merge_request_spec.rb +++ b/spec/features/merge_request/user_comments_on_merge_request_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User comments on a merge request', :js do diff --git a/spec/features/merge_request/user_creates_image_diff_notes_spec.rb b/spec/features/merge_request/user_creates_image_diff_notes_spec.rb index 3a9a06a6bc3..e0724a04ea3 100644 --- a/spec/features/merge_request/user_creates_image_diff_notes_spec.rb +++ b/spec/features/merge_request/user_creates_image_diff_notes_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Merge request > User creates image diff notes', :js do diff --git a/spec/features/merge_request/user_creates_merge_request_spec.rb b/spec/features/merge_request/user_creates_merge_request_spec.rb index 2a70cbb2a72..f92791cc810 100644 --- a/spec/features/merge_request/user_creates_merge_request_spec.rb +++ b/spec/features/merge_request/user_creates_merge_request_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "spec_helper" describe "User creates a merge request", :js do diff --git a/spec/features/merge_request/user_creates_mr_spec.rb b/spec/features/merge_request/user_creates_mr_spec.rb index c9dedab048a..267097bd466 100644 --- a/spec/features/merge_request/user_creates_mr_spec.rb +++ b/spec/features/merge_request/user_creates_mr_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Merge request > User creates MR' do diff --git a/spec/features/merge_request/user_customizes_merge_commit_message_spec.rb b/spec/features/merge_request/user_customizes_merge_commit_message_spec.rb index c6b11fce388..3213efcb60b 100644 --- a/spec/features/merge_request/user_customizes_merge_commit_message_spec.rb +++ b/spec/features/merge_request/user_customizes_merge_commit_message_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Merge request < User customizes merge commit message', :js do diff --git a/spec/features/merge_request/user_edits_merge_request_spec.rb b/spec/features/merge_request/user_edits_merge_request_spec.rb index 7de0f9daac6..81c56855961 100644 --- a/spec/features/merge_request/user_edits_merge_request_spec.rb +++ b/spec/features/merge_request/user_edits_merge_request_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User edits a merge request', :js do diff --git a/spec/features/merge_request/user_edits_mr_spec.rb b/spec/features/merge_request/user_edits_mr_spec.rb index 25979513ead..e6b847c5e7f 100644 --- a/spec/features/merge_request/user_edits_mr_spec.rb +++ b/spec/features/merge_request/user_edits_mr_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Merge request > User edits MR' do diff --git a/spec/features/merge_request/user_expands_diff_spec.rb b/spec/features/merge_request/user_expands_diff_spec.rb index 3560b8d90bb..f7317ec5ca7 100644 --- a/spec/features/merge_request/user_expands_diff_spec.rb +++ b/spec/features/merge_request/user_expands_diff_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User expands diff', :js do diff --git a/spec/features/merge_request/user_locks_discussion_spec.rb b/spec/features/merge_request/user_locks_discussion_spec.rb index 76c759ab8d3..365e9b60d90 100644 --- a/spec/features/merge_request/user_locks_discussion_spec.rb +++ b/spec/features/merge_request/user_locks_discussion_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Merge request > User locks discussion', :js do diff --git a/spec/features/merge_request/user_manages_subscription_spec.rb b/spec/features/merge_request/user_manages_subscription_spec.rb index 68a835e7f77..5c6072c57ff 100644 --- a/spec/features/merge_request/user_manages_subscription_spec.rb +++ b/spec/features/merge_request/user_manages_subscription_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User manages subscription', :js do diff --git a/spec/features/merge_request/user_merges_immediately_spec.rb b/spec/features/merge_request/user_merges_immediately_spec.rb index 84636ae355c..2f01971c2e9 100644 --- a/spec/features/merge_request/user_merges_immediately_spec.rb +++ b/spec/features/merge_request/user_merges_immediately_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Merge requests > User merges immediately', :js do diff --git a/spec/features/merge_request/user_merges_only_if_pipeline_succeeds_spec.rb b/spec/features/merge_request/user_merges_only_if_pipeline_succeeds_spec.rb index 8372b61f872..3f9c27bbf9d 100644 --- a/spec/features/merge_request/user_merges_only_if_pipeline_succeeds_spec.rb +++ b/spec/features/merge_request/user_merges_only_if_pipeline_succeeds_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Merge request > User merges only if pipeline succeeds', :js do diff --git a/spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb b/spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb index 85c4d778fd0..93938ac221a 100644 --- a/spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb +++ b/spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Merge request > User merges when pipeline succeeds', :js do 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 19edce1b562..ead564aea28 100644 --- a/spec/features/merge_request/user_posts_diff_notes_spec.rb +++ b/spec/features/merge_request/user_posts_diff_notes_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Merge request > User posts diff notes', :js do diff --git a/spec/features/merge_request/user_posts_notes_spec.rb b/spec/features/merge_request/user_posts_notes_spec.rb index 8ff24449b39..1fad9eac1bd 100644 --- a/spec/features/merge_request/user_posts_notes_spec.rb +++ b/spec/features/merge_request/user_posts_notes_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Merge request > User posts notes', :js do diff --git a/spec/features/merge_request/user_rebases_merge_request_spec.rb b/spec/features/merge_request/user_rebases_merge_request_spec.rb index 92e1c9942b1..34f009000dc 100644 --- a/spec/features/merge_request/user_rebases_merge_request_spec.rb +++ b/spec/features/merge_request/user_rebases_merge_request_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "spec_helper" describe "User rebases a merge request", :js do diff --git a/spec/features/merge_request/user_reopens_merge_request_spec.rb b/spec/features/merge_request/user_reopens_merge_request_spec.rb index 745b4537e72..6dee5770d0c 100644 --- a/spec/features/merge_request/user_reopens_merge_request_spec.rb +++ b/spec/features/merge_request/user_reopens_merge_request_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User reopens a merge requests', :js do diff --git a/spec/features/merge_request/user_resolves_conflicts_spec.rb b/spec/features/merge_request/user_resolves_conflicts_spec.rb index 8fd44b87e5a..fb089a9ffcb 100644 --- a/spec/features/merge_request/user_resolves_conflicts_spec.rb +++ b/spec/features/merge_request/user_resolves_conflicts_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Merge request > User resolves conflicts', :js do diff --git a/spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb b/spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb index 3e72b2ce71f..b8e4852a748 100644 --- a/spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb +++ b/spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Merge request > User resolves diff notes and threads', :js do diff --git a/spec/features/merge_request/user_resolves_outdated_diff_discussions_spec.rb b/spec/features/merge_request/user_resolves_outdated_diff_discussions_spec.rb index 777464ef841..b40c11f0d47 100644 --- a/spec/features/merge_request/user_resolves_outdated_diff_discussions_spec.rb +++ b/spec/features/merge_request/user_resolves_outdated_diff_discussions_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Merge request > User resolves outdated diff discussions', :js do diff --git a/spec/features/merge_request/user_reverts_merge_request_spec.rb b/spec/features/merge_request/user_reverts_merge_request_spec.rb index 67b6aefb2d8..71270b13c14 100644 --- a/spec/features/merge_request/user_reverts_merge_request_spec.rb +++ b/spec/features/merge_request/user_reverts_merge_request_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User reverts a merge request', :js do diff --git a/spec/features/merge_request/user_scrolls_to_note_on_load_spec.rb b/spec/features/merge_request/user_scrolls_to_note_on_load_spec.rb index 2f7d359575e..23b37c218e1 100644 --- a/spec/features/merge_request/user_scrolls_to_note_on_load_spec.rb +++ b/spec/features/merge_request/user_scrolls_to_note_on_load_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Merge request > User scrolls to note on load', :js do diff --git a/spec/features/merge_request/user_sees_avatar_on_diff_notes_spec.rb b/spec/features/merge_request/user_sees_avatar_on_diff_notes_spec.rb index b58c433bbfe..fae81758086 100644 --- a/spec/features/merge_request/user_sees_avatar_on_diff_notes_spec.rb +++ b/spec/features/merge_request/user_sees_avatar_on_diff_notes_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Merge request > User sees avatars on diff notes', :js do diff --git a/spec/features/merge_request/user_sees_breadcrumb_links_spec.rb b/spec/features/merge_request/user_sees_breadcrumb_links_spec.rb index 18d204da17a..e1f0ddc4c6a 100644 --- a/spec/features/merge_request/user_sees_breadcrumb_links_spec.rb +++ b/spec/features/merge_request/user_sees_breadcrumb_links_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'New merge request breadcrumb' do diff --git a/spec/features/merge_request/user_sees_check_out_branch_modal_spec.rb b/spec/features/merge_request/user_sees_check_out_branch_modal_spec.rb index 86086a58f18..93ae408a173 100644 --- a/spec/features/merge_request/user_sees_check_out_branch_modal_spec.rb +++ b/spec/features/merge_request/user_sees_check_out_branch_modal_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Merge request > User sees check out branch modal', :js do diff --git a/spec/features/merge_request/user_sees_cherry_pick_modal_spec.rb b/spec/features/merge_request/user_sees_cherry_pick_modal_spec.rb index aa499493dbe..8a2614c53af 100644 --- a/spec/features/merge_request/user_sees_cherry_pick_modal_spec.rb +++ b/spec/features/merge_request/user_sees_cherry_pick_modal_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Merge request > User cherry-picks', :js do diff --git a/spec/features/merge_request/user_sees_closing_issues_message_spec.rb b/spec/features/merge_request/user_sees_closing_issues_message_spec.rb index d7c784b14c5..52163571175 100644 --- a/spec/features/merge_request/user_sees_closing_issues_message_spec.rb +++ b/spec/features/merge_request/user_sees_closing_issues_message_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Merge request > User sees closing issues message', :js do diff --git a/spec/features/merge_request/user_sees_deleted_target_branch_spec.rb b/spec/features/merge_request/user_sees_deleted_target_branch_spec.rb index 46c21a2b155..f46921af1cd 100644 --- a/spec/features/merge_request/user_sees_deleted_target_branch_spec.rb +++ b/spec/features/merge_request/user_sees_deleted_target_branch_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Merge request > User sees deleted target branch', :js do diff --git a/spec/features/merge_request/user_sees_deployment_widget_spec.rb b/spec/features/merge_request/user_sees_deployment_widget_spec.rb index fe8e0b07d39..14fbfc2fd3f 100644 --- a/spec/features/merge_request/user_sees_deployment_widget_spec.rb +++ b/spec/features/merge_request/user_sees_deployment_widget_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Merge request > User sees deployment widget', :js do diff --git a/spec/features/merge_request/user_sees_diff_spec.rb b/spec/features/merge_request/user_sees_diff_spec.rb index 8dc5912b8be..32429bac5f9 100644 --- a/spec/features/merge_request/user_sees_diff_spec.rb +++ b/spec/features/merge_request/user_sees_diff_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Merge request > User sees diff', :js do diff --git a/spec/features/merge_request/user_sees_discussions_spec.rb b/spec/features/merge_request/user_sees_discussions_spec.rb index 39258b48295..a11baf1dca3 100644 --- a/spec/features/merge_request/user_sees_discussions_spec.rb +++ b/spec/features/merge_request/user_sees_discussions_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Merge request > User sees threads', :js do diff --git a/spec/features/merge_request/user_sees_empty_state_spec.rb b/spec/features/merge_request/user_sees_empty_state_spec.rb index 012bfd6e458..f1ad5c2dffc 100644 --- a/spec/features/merge_request/user_sees_empty_state_spec.rb +++ b/spec/features/merge_request/user_sees_empty_state_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Merge request > User sees empty state' do diff --git a/spec/features/merge_request/user_sees_merge_button_depending_on_unresolved_discussions_spec.rb b/spec/features/merge_request/user_sees_merge_button_depending_on_unresolved_discussions_spec.rb index cf398a7df18..53cafb60dfb 100644 --- a/spec/features/merge_request/user_sees_merge_button_depending_on_unresolved_discussions_spec.rb +++ b/spec/features/merge_request/user_sees_merge_button_depending_on_unresolved_discussions_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Merge request > User sees merge button depending on unresolved threads', :js do diff --git a/spec/features/merge_request/user_sees_merge_widget_spec.rb b/spec/features/merge_request/user_sees_merge_widget_spec.rb index 30e30751693..b5d0240e9de 100644 --- a/spec/features/merge_request/user_sees_merge_widget_spec.rb +++ b/spec/features/merge_request/user_sees_merge_widget_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Merge request > User sees merge widget', :js do diff --git a/spec/features/merge_request/user_sees_mini_pipeline_graph_spec.rb b/spec/features/merge_request/user_sees_mini_pipeline_graph_spec.rb index dd8900a3698..eb89d616b14 100644 --- a/spec/features/merge_request/user_sees_mini_pipeline_graph_spec.rb +++ b/spec/features/merge_request/user_sees_mini_pipeline_graph_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Merge request < User sees mini pipeline graph', :js do diff --git a/spec/features/merge_request/user_sees_mr_from_deleted_forked_project_spec.rb b/spec/features/merge_request/user_sees_mr_from_deleted_forked_project_spec.rb index fc4a188d4a7..80ee35f2a91 100644 --- a/spec/features/merge_request/user_sees_mr_from_deleted_forked_project_spec.rb +++ b/spec/features/merge_request/user_sees_mr_from_deleted_forked_project_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Merge request > User sees MR from deleted forked project', :js do diff --git a/spec/features/merge_request/user_sees_mr_with_deleted_source_branch_spec.rb b/spec/features/merge_request/user_sees_mr_with_deleted_source_branch_spec.rb index fd4175d5227..d9dc32d0594 100644 --- a/spec/features/merge_request/user_sees_mr_with_deleted_source_branch_spec.rb +++ b/spec/features/merge_request/user_sees_mr_with_deleted_source_branch_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' # This test serves as a regression test for a bug that caused an error diff --git a/spec/features/merge_request/user_sees_notes_from_forked_project_spec.rb b/spec/features/merge_request/user_sees_notes_from_forked_project_spec.rb index a6118453540..195592531f2 100644 --- a/spec/features/merge_request/user_sees_notes_from_forked_project_spec.rb +++ b/spec/features/merge_request/user_sees_notes_from_forked_project_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Merge request > User sees notes from forked project', :js do diff --git a/spec/features/merge_request/user_sees_pipelines_from_forked_project_spec.rb b/spec/features/merge_request/user_sees_pipelines_from_forked_project_spec.rb index 97093bbc2f6..68c9e0b123d 100644 --- a/spec/features/merge_request/user_sees_pipelines_from_forked_project_spec.rb +++ b/spec/features/merge_request/user_sees_pipelines_from_forked_project_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Merge request > User sees pipelines from forked project', :js do diff --git a/spec/features/merge_request/user_sees_pipelines_spec.rb b/spec/features/merge_request/user_sees_pipelines_spec.rb index 8faddee4daa..e057f59e00c 100644 --- a/spec/features/merge_request/user_sees_pipelines_spec.rb +++ b/spec/features/merge_request/user_sees_pipelines_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Merge request > User sees pipelines', :js do diff --git a/spec/features/merge_request/user_sees_system_notes_spec.rb b/spec/features/merge_request/user_sees_system_notes_spec.rb index c6811d4161a..26cdd5ba21c 100644 --- a/spec/features/merge_request/user_sees_system_notes_spec.rb +++ b/spec/features/merge_request/user_sees_system_notes_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Merge request > User sees system notes', :js do diff --git a/spec/features/merge_request/user_sees_versions_spec.rb b/spec/features/merge_request/user_sees_versions_spec.rb index 6eae3fd4676..dae5845adec 100644 --- a/spec/features/merge_request/user_sees_versions_spec.rb +++ b/spec/features/merge_request/user_sees_versions_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Merge request > User sees versions', :js do diff --git a/spec/features/merge_request/user_sees_wip_help_message_spec.rb b/spec/features/merge_request/user_sees_wip_help_message_spec.rb index 92cc73ddf1f..46209237faf 100644 --- a/spec/features/merge_request/user_sees_wip_help_message_spec.rb +++ b/spec/features/merge_request/user_sees_wip_help_message_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Merge request > User sees WIP help message' do diff --git a/spec/features/merge_request/user_selects_branches_for_new_mr_spec.rb b/spec/features/merge_request/user_selects_branches_for_new_mr_spec.rb index ae41cf90576..a1f027cbb1d 100644 --- a/spec/features/merge_request/user_selects_branches_for_new_mr_spec.rb +++ b/spec/features/merge_request/user_selects_branches_for_new_mr_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Merge request > User selects branches for new MR', :js do diff --git a/spec/features/merge_request/user_toggles_whitespace_changes_spec.rb b/spec/features/merge_request/user_toggles_whitespace_changes_spec.rb index 0decdfe3a14..61b9904dde5 100644 --- a/spec/features/merge_request/user_toggles_whitespace_changes_spec.rb +++ b/spec/features/merge_request/user_toggles_whitespace_changes_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Merge request > User toggles whitespace changes', :js do diff --git a/spec/features/merge_request/user_tries_to_access_private_repository_through_new_mr_spec.rb b/spec/features/merge_request/user_tries_to_access_private_project_info_through_new_mr_spec.rb index 9318b5f1ebb..1ebe9e2e409 100644 --- a/spec/features/merge_request/user_tries_to_access_private_repository_through_new_mr_spec.rb +++ b/spec/features/merge_request/user_tries_to_access_private_project_info_through_new_mr_spec.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + require 'spec_helper' -describe 'Merge Request > Tries to access private repo of public project' do +describe 'Merge Request > User tries to access private project information through the new mr page' do let(:current_user) { create(:user) } let(:private_project) do create(:project, :public, :repository, @@ -33,5 +35,22 @@ describe 'Merge Request > Tries to access private repo of public project' do it "does not mention the project the user can't see the repo of" do expect(page).not_to have_content('nothing-to-see-here') end + + context 'when the user enters label information from the private project in the querystring' do + let(:inaccessible_label) { create(:label, project: private_project) } + let(:mr_path) do + project_new_merge_request_path( + owned_project, + merge_request: { + label_ids: [inaccessible_label.id], + source_branch: 'feature' + } + ) + end + + it 'does not expose the label name' do + expect(page).not_to have_content(inaccessible_label.name) + end + end end end diff --git a/spec/features/merge_request/user_views_diffs_spec.rb b/spec/features/merge_request/user_views_diffs_spec.rb index 74342b16cb2..6d58d43a295 100644 --- a/spec/features/merge_request/user_views_diffs_spec.rb +++ b/spec/features/merge_request/user_views_diffs_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User views diffs', :js do diff --git a/spec/features/merge_request/user_views_open_merge_request_spec.rb b/spec/features/merge_request/user_views_open_merge_request_spec.rb index 849fab62fc6..a788fc71286 100644 --- a/spec/features/merge_request/user_views_open_merge_request_spec.rb +++ b/spec/features/merge_request/user_views_open_merge_request_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User views an open merge request' do diff --git a/spec/features/merge_requests/filters_generic_behavior_spec.rb b/spec/features/merge_requests/filters_generic_behavior_spec.rb index 0e7fac6b409..404e591cf4b 100644 --- a/spec/features/merge_requests/filters_generic_behavior_spec.rb +++ b/spec/features/merge_requests/filters_generic_behavior_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Merge Requests > Filters generic behavior', :js do diff --git a/spec/features/merge_requests/user_filters_by_assignees_spec.rb b/spec/features/merge_requests/user_filters_by_assignees_spec.rb index 0cbf1bcae30..b896b6392f1 100644 --- a/spec/features/merge_requests/user_filters_by_assignees_spec.rb +++ b/spec/features/merge_requests/user_filters_by_assignees_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Merge Requests > User filters by assignees', :js do diff --git a/spec/features/merge_requests/user_filters_by_labels_spec.rb b/spec/features/merge_requests/user_filters_by_labels_spec.rb index 08d741af93d..9fb149ca58d 100644 --- a/spec/features/merge_requests/user_filters_by_labels_spec.rb +++ b/spec/features/merge_requests/user_filters_by_labels_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Merge Requests > User filters by labels', :js do diff --git a/spec/features/merge_requests/user_filters_by_milestones_spec.rb b/spec/features/merge_requests/user_filters_by_milestones_spec.rb index 727a236d980..2fb3c86ea94 100644 --- a/spec/features/merge_requests/user_filters_by_milestones_spec.rb +++ b/spec/features/merge_requests/user_filters_by_milestones_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Merge Requests > User filters by milestones', :js do diff --git a/spec/features/merge_requests/user_filters_by_multiple_criteria_spec.rb b/spec/features/merge_requests/user_filters_by_multiple_criteria_spec.rb index 4627931f26a..3dd0f93ddfa 100644 --- a/spec/features/merge_requests/user_filters_by_multiple_criteria_spec.rb +++ b/spec/features/merge_requests/user_filters_by_multiple_criteria_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Merge requests > User filters by multiple criteria', :js do diff --git a/spec/features/merge_requests/user_filters_by_target_branch_spec.rb b/spec/features/merge_requests/user_filters_by_target_branch_spec.rb index ffbdacc68f6..b5969f656b0 100644 --- a/spec/features/merge_requests/user_filters_by_target_branch_spec.rb +++ b/spec/features/merge_requests/user_filters_by_target_branch_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Merge Requests > User filters by target branch', :js do diff --git a/spec/features/merge_requests/user_lists_merge_requests_spec.rb b/spec/features/merge_requests/user_lists_merge_requests_spec.rb index 2dee0e26954..69d4650d1ac 100644 --- a/spec/features/merge_requests/user_lists_merge_requests_spec.rb +++ b/spec/features/merge_requests/user_lists_merge_requests_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Merge requests > User lists merge requests' do diff --git a/spec/features/merge_requests/user_mass_updates_spec.rb b/spec/features/merge_requests/user_mass_updates_spec.rb index c2dd105324d..48c92a87c63 100644 --- a/spec/features/merge_requests/user_mass_updates_spec.rb +++ b/spec/features/merge_requests/user_mass_updates_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Merge requests > User mass updates', :js do diff --git a/spec/features/merge_requests/user_sorts_merge_requests_spec.rb b/spec/features/merge_requests/user_sorts_merge_requests_spec.rb index fa887110c13..ca3e24d7036 100644 --- a/spec/features/merge_requests/user_sorts_merge_requests_spec.rb +++ b/spec/features/merge_requests/user_sorts_merge_requests_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User sorts merge requests' do diff --git a/spec/features/merge_requests/user_squashes_merge_request_spec.rb b/spec/features/merge_requests/user_squashes_merge_request_spec.rb index bf9c55cf22c..4fc8c71e47e 100644 --- a/spec/features/merge_requests/user_squashes_merge_request_spec.rb +++ b/spec/features/merge_requests/user_squashes_merge_request_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User squashes a merge request', :js do diff --git a/spec/features/merge_requests/user_views_all_merge_requests_spec.rb b/spec/features/merge_requests/user_views_all_merge_requests_spec.rb index 6c695bd7aa9..60496d61e87 100644 --- a/spec/features/merge_requests/user_views_all_merge_requests_spec.rb +++ b/spec/features/merge_requests/user_views_all_merge_requests_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User views all merge requests' do diff --git a/spec/features/merge_requests/user_views_closed_merge_requests_spec.rb b/spec/features/merge_requests/user_views_closed_merge_requests_spec.rb index 853809fe87a..dc0d35e4fea 100644 --- a/spec/features/merge_requests/user_views_closed_merge_requests_spec.rb +++ b/spec/features/merge_requests/user_views_closed_merge_requests_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User views closed merge requests' do diff --git a/spec/features/merge_requests/user_views_merged_merge_requests_spec.rb b/spec/features/merge_requests/user_views_merged_merge_requests_spec.rb index eb012694f1e..ddb354204c9 100644 --- a/spec/features/merge_requests/user_views_merged_merge_requests_spec.rb +++ b/spec/features/merge_requests/user_views_merged_merge_requests_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User views merged merge requests' do diff --git a/spec/features/merge_requests/user_views_open_merge_requests_spec.rb b/spec/features/merge_requests/user_views_open_merge_requests_spec.rb index 115e548b691..cefac9690ce 100644 --- a/spec/features/merge_requests/user_views_open_merge_requests_spec.rb +++ b/spec/features/merge_requests/user_views_open_merge_requests_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User views open merge requests' do diff --git a/spec/features/milestone_spec.rb b/spec/features/milestone_spec.rb index adac59b89ef..6d5acc894b1 100644 --- a/spec/features/milestone_spec.rb +++ b/spec/features/milestone_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Milestone' do diff --git a/spec/features/milestones/user_creates_milestone_spec.rb b/spec/features/milestones/user_creates_milestone_spec.rb index 5de0c381cdf..73f4f187501 100644 --- a/spec/features/milestones/user_creates_milestone_spec.rb +++ b/spec/features/milestones/user_creates_milestone_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" describe "User creates milestone", :js do diff --git a/spec/features/milestones/user_deletes_milestone_spec.rb b/spec/features/milestones/user_deletes_milestone_spec.rb index f68ed1cde07..5666c1dd507 100644 --- a/spec/features/milestones/user_deletes_milestone_spec.rb +++ b/spec/features/milestones/user_deletes_milestone_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" describe "User deletes milestone", :js do diff --git a/spec/features/milestones/user_edits_milestone_spec.rb b/spec/features/milestones/user_edits_milestone_spec.rb index 077295f1cc0..f8e96eac3ea 100644 --- a/spec/features/milestones/user_edits_milestone_spec.rb +++ b/spec/features/milestones/user_edits_milestone_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" describe "User edits milestone", :js do diff --git a/spec/features/milestones/user_promotes_milestone_spec.rb b/spec/features/milestones/user_promotes_milestone_spec.rb index df1bc502134..acceb5cad62 100644 --- a/spec/features/milestones/user_promotes_milestone_spec.rb +++ b/spec/features/milestones/user_promotes_milestone_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'User promotes milestone' do diff --git a/spec/features/milestones/user_sees_breadcrumb_links_spec.rb b/spec/features/milestones/user_sees_breadcrumb_links_spec.rb index d3906ea73bd..f58242759cc 100644 --- a/spec/features/milestones/user_sees_breadcrumb_links_spec.rb +++ b/spec/features/milestones/user_sees_breadcrumb_links_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'New project milestone breadcrumb' do diff --git a/spec/features/milestones/user_views_milestone_spec.rb b/spec/features/milestones/user_views_milestone_spec.rb index 83d8e2ff9e9..aa0cdf66b75 100644 --- a/spec/features/milestones/user_views_milestone_spec.rb +++ b/spec/features/milestones/user_views_milestone_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" describe "User views milestone" do diff --git a/spec/features/milestones/user_views_milestones_spec.rb b/spec/features/milestones/user_views_milestones_spec.rb index bebe40f73fd..6868791f584 100644 --- a/spec/features/milestones/user_views_milestones_spec.rb +++ b/spec/features/milestones/user_views_milestones_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" describe "User views milestones" do diff --git a/spec/features/oauth_login_spec.rb b/spec/features/oauth_login_spec.rb index 86331728f88..a47eaa9bda7 100644 --- a/spec/features/oauth_login_spec.rb +++ b/spec/features/oauth_login_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'OAuth Login', :js, :allow_forgery_protection do @@ -34,6 +36,7 @@ describe 'OAuth Login', :js, :allow_forgery_protection do before do stub_omniauth_config(provider) + expect(ActiveSession).to receive(:cleanup).with(user).at_least(:once).and_call_original end context 'when two-factor authentication is disabled' do diff --git a/spec/features/participants_autocomplete_spec.rb b/spec/features/participants_autocomplete_spec.rb index 134731a4639..312285ca2cb 100644 --- a/spec/features/participants_autocomplete_spec.rb +++ b/spec/features/participants_autocomplete_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Member autocomplete', :js do diff --git a/spec/features/password_reset_spec.rb b/spec/features/password_reset_spec.rb index dcc63dff9f5..8ceca1e3175 100644 --- a/spec/features/password_reset_spec.rb +++ b/spec/features/password_reset_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Password reset' do diff --git a/spec/features/profile_spec.rb b/spec/features/profile_spec.rb index 2e0753c3bfb..e80a3cd32cc 100644 --- a/spec/features/profile_spec.rb +++ b/spec/features/profile_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Profile account page', :js do diff --git a/spec/features/profiles/account_spec.rb b/spec/features/profiles/account_spec.rb index 90d0e9bb77c..741e41adbf1 100644 --- a/spec/features/profiles/account_spec.rb +++ b/spec/features/profiles/account_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Profile > Account', :js do diff --git a/spec/features/profiles/active_sessions_spec.rb b/spec/features/profiles/active_sessions_spec.rb index 2aa0177af5d..709cca7d178 100644 --- a/spec/features/profiles/active_sessions_spec.rb +++ b/spec/features/profiles/active_sessions_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Profile > Active Sessions', :clean_gitlab_redis_shared_state do diff --git a/spec/features/profiles/chat_names_spec.rb b/spec/features/profiles/chat_names_spec.rb index c72069f6262..0219dacbc38 100644 --- a/spec/features/profiles/chat_names_spec.rb +++ b/spec/features/profiles/chat_names_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Profile > Chat' do diff --git a/spec/features/profiles/emails_spec.rb b/spec/features/profiles/emails_spec.rb index bc6d54b5ed7..40e2988730b 100644 --- a/spec/features/profiles/emails_spec.rb +++ b/spec/features/profiles/emails_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Profile > Emails' do diff --git a/spec/features/profiles/gpg_keys_spec.rb b/spec/features/profiles/gpg_keys_spec.rb index ec3ec795b63..4237f037c27 100644 --- a/spec/features/profiles/gpg_keys_spec.rb +++ b/spec/features/profiles/gpg_keys_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Profile > GPG Keys' do diff --git a/spec/features/profiles/keys_spec.rb b/spec/features/profiles/keys_spec.rb index e6586fc8a0a..c1b142c4e12 100644 --- a/spec/features/profiles/keys_spec.rb +++ b/spec/features/profiles/keys_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Profile > SSH Keys' do diff --git a/spec/features/profiles/oauth_applications_spec.rb b/spec/features/profiles/oauth_applications_spec.rb index 7d204f89fba..94c9897a7a9 100644 --- a/spec/features/profiles/oauth_applications_spec.rb +++ b/spec/features/profiles/oauth_applications_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Profile > Applications' do diff --git a/spec/features/profiles/password_spec.rb b/spec/features/profiles/password_spec.rb index 5e3569e4beb..8c0c426f689 100644 --- a/spec/features/profiles/password_spec.rb +++ b/spec/features/profiles/password_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Profile > Password' do diff --git a/spec/features/profiles/personal_access_tokens_spec.rb b/spec/features/profiles/personal_access_tokens_spec.rb index dee213a11d4..22f9c8d8afc 100644 --- a/spec/features/profiles/personal_access_tokens_spec.rb +++ b/spec/features/profiles/personal_access_tokens_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Profile > Personal Access Tokens', :js do diff --git a/spec/features/profiles/user_changes_notified_of_own_activity_spec.rb b/spec/features/profiles/user_changes_notified_of_own_activity_spec.rb index f618bc330ea..5af48c4503d 100644 --- a/spec/features/profiles/user_changes_notified_of_own_activity_spec.rb +++ b/spec/features/profiles/user_changes_notified_of_own_activity_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Profile > Notifications > User changes notified_of_own_activity setting', :js do diff --git a/spec/features/profiles/user_edit_profile_spec.rb b/spec/features/profiles/user_edit_profile_spec.rb index a53da94ef7d..1ab7742b36e 100644 --- a/spec/features/profiles/user_edit_profile_spec.rb +++ b/spec/features/profiles/user_edit_profile_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User edit profile' do @@ -40,7 +42,7 @@ describe 'User edit profile' do simulate_input('#user_name', 'Martin 😀') submit_settings - page.within('.qa-full-name') do + page.within('.rspec-full-name') do expect(page).to have_css '.gl-field-error-outline' expect(find('.gl-field-error')).not_to have_selector('.hidden') expect(find('.gl-field-error')).to have_content('Using emojis in names seems fun, but please try to set a status message instead') diff --git a/spec/features/profiles/user_manages_applications_spec.rb b/spec/features/profiles/user_manages_applications_spec.rb index 34aaab240cc..7a961855c92 100644 --- a/spec/features/profiles/user_manages_applications_spec.rb +++ b/spec/features/profiles/user_manages_applications_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User manages applications' do diff --git a/spec/features/profiles/user_manages_emails_spec.rb b/spec/features/profiles/user_manages_emails_spec.rb index 7283c76eb54..09da819a187 100644 --- a/spec/features/profiles/user_manages_emails_spec.rb +++ b/spec/features/profiles/user_manages_emails_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User manages emails' do diff --git a/spec/features/profiles/user_visits_notifications_tab_spec.rb b/spec/features/profiles/user_visits_notifications_tab_spec.rb index db797bb586f..1472cc882a7 100644 --- a/spec/features/profiles/user_visits_notifications_tab_spec.rb +++ b/spec/features/profiles/user_visits_notifications_tab_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User visits the notifications tab', :js do diff --git a/spec/features/profiles/user_visits_profile_account_page_spec.rb b/spec/features/profiles/user_visits_profile_account_page_spec.rb index a8c08a680d7..f576a2bf9e1 100644 --- a/spec/features/profiles/user_visits_profile_account_page_spec.rb +++ b/spec/features/profiles/user_visits_profile_account_page_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User visits the profile account page' do diff --git a/spec/features/profiles/user_visits_profile_authentication_log_spec.rb b/spec/features/profiles/user_visits_profile_authentication_log_spec.rb index 0f419c3c2c0..2f6f8ebee9c 100644 --- a/spec/features/profiles/user_visits_profile_authentication_log_spec.rb +++ b/spec/features/profiles/user_visits_profile_authentication_log_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User visits the authentication log' do diff --git a/spec/features/profiles/user_visits_profile_preferences_page_spec.rb b/spec/features/profiles/user_visits_profile_preferences_page_spec.rb index 1b3718968b9..5e52c82a234 100644 --- a/spec/features/profiles/user_visits_profile_preferences_page_spec.rb +++ b/spec/features/profiles/user_visits_profile_preferences_page_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User visits the profile preferences page' do diff --git a/spec/features/profiles/user_visits_profile_spec.rb b/spec/features/profiles/user_visits_profile_spec.rb index 2dc4547b2d8..1c90a794099 100644 --- a/spec/features/profiles/user_visits_profile_spec.rb +++ b/spec/features/profiles/user_visits_profile_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User visits their profile' do diff --git a/spec/features/profiles/user_visits_profile_ssh_keys_page_spec.rb b/spec/features/profiles/user_visits_profile_ssh_keys_page_spec.rb index 685bf44619d..05ad9096f65 100644 --- a/spec/features/profiles/user_visits_profile_ssh_keys_page_spec.rb +++ b/spec/features/profiles/user_visits_profile_ssh_keys_page_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User visits the profile SSH keys page' do diff --git a/spec/features/projects/activity/rss_spec.rb b/spec/features/projects/activity/rss_spec.rb index 411134e7b8e..e1efe6ca64d 100644 --- a/spec/features/projects/activity/rss_spec.rb +++ b/spec/features/projects/activity/rss_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Project Activity RSS' do diff --git a/spec/features/projects/activity/user_sees_activity_spec.rb b/spec/features/projects/activity/user_sees_activity_spec.rb index bb4b2abc3c7..664002d909c 100644 --- a/spec/features/projects/activity/user_sees_activity_spec.rb +++ b/spec/features/projects/activity/user_sees_activity_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Activity > User sees activity' do diff --git a/spec/features/projects/activity/user_sees_private_activity_spec.rb b/spec/features/projects/activity/user_sees_private_activity_spec.rb index 61ec2ce9d29..0ec4752d418 100644 --- a/spec/features/projects/activity/user_sees_private_activity_spec.rb +++ b/spec/features/projects/activity/user_sees_private_activity_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Project > Activity > User sees private activity', :js do diff --git a/spec/features/projects/actve_tabs_spec.rb b/spec/features/projects/actve_tabs_spec.rb index 7c6110c533b..56f587f23ee 100644 --- a/spec/features/projects/actve_tabs_spec.rb +++ b/spec/features/projects/actve_tabs_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Project active tab' do diff --git a/spec/features/projects/artifacts/file_spec.rb b/spec/features/projects/artifacts/file_spec.rb index 993d0040434..f7eaae12072 100644 --- a/spec/features/projects/artifacts/file_spec.rb +++ b/spec/features/projects/artifacts/file_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Artifact file', :js do diff --git a/spec/features/projects/artifacts/raw_spec.rb b/spec/features/projects/artifacts/raw_spec.rb index d8ee9adda6b..0606ab0ed08 100644 --- a/spec/features/projects/artifacts/raw_spec.rb +++ b/spec/features/projects/artifacts/raw_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Raw artifact', :js do diff --git a/spec/features/projects/artifacts/user_browses_artifacts_spec.rb b/spec/features/projects/artifacts/user_browses_artifacts_spec.rb index a1fcd4024c0..ecc07181d09 100644 --- a/spec/features/projects/artifacts/user_browses_artifacts_spec.rb +++ b/spec/features/projects/artifacts/user_browses_artifacts_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "spec_helper" describe "User browses artifacts" do diff --git a/spec/features/projects/artifacts/user_downloads_artifacts_spec.rb b/spec/features/projects/artifacts/user_downloads_artifacts_spec.rb index 5cb015e80be..254ebfb839a 100644 --- a/spec/features/projects/artifacts/user_downloads_artifacts_spec.rb +++ b/spec/features/projects/artifacts/user_downloads_artifacts_spec.rb @@ -1,8 +1,10 @@ +# frozen_string_literal: true + require "spec_helper" describe "User downloads artifacts" do - set(:project) { create(:project, :public) } - set(:pipeline) { create(:ci_empty_pipeline, status: :success, project: project) } + set(:project) { create(:project, :repository, :public) } + set(:pipeline) { create(:ci_empty_pipeline, status: :success, sha: project.commit.id, project: project) } set(:job) { create(:ci_build, :artifacts, :success, pipeline: pipeline) } shared_examples "downloading" do diff --git a/spec/features/projects/badges/coverage_spec.rb b/spec/features/projects/badges/coverage_spec.rb index 8522ea747fa..46aa104fdd7 100644 --- a/spec/features/projects/badges/coverage_spec.rb +++ b/spec/features/projects/badges/coverage_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'test coverage badge' do diff --git a/spec/features/projects/badges/list_spec.rb b/spec/features/projects/badges/list_spec.rb index e30b908c60d..7a90457c942 100644 --- a/spec/features/projects/badges/list_spec.rb +++ b/spec/features/projects/badges/list_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'list of badges' do diff --git a/spec/features/projects/badges/pipeline_badge_spec.rb b/spec/features/projects/badges/pipeline_badge_spec.rb index 4ac4e8f0fcb..f2c57d702a5 100644 --- a/spec/features/projects/badges/pipeline_badge_spec.rb +++ b/spec/features/projects/badges/pipeline_badge_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Pipeline Badge' do diff --git a/spec/features/projects/blobs/blob_line_permalink_updater_spec.rb b/spec/features/projects/blobs/blob_line_permalink_updater_spec.rb index 96f514f4f04..1fc490ecbfe 100644 --- a/spec/features/projects/blobs/blob_line_permalink_updater_spec.rb +++ b/spec/features/projects/blobs/blob_line_permalink_updater_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Blob button line permalinks (BlobLinePermalinkUpdater)', :js do diff --git a/spec/features/projects/blobs/blob_show_spec.rb b/spec/features/projects/blobs/blob_show_spec.rb index aa2e538cc8e..af6bb8c271f 100644 --- a/spec/features/projects/blobs/blob_show_spec.rb +++ b/spec/features/projects/blobs/blob_show_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'File blob', :js do diff --git a/spec/features/projects/blobs/edit_spec.rb b/spec/features/projects/blobs/edit_spec.rb index 57d21f3e182..3b32d213754 100644 --- a/spec/features/projects/blobs/edit_spec.rb +++ b/spec/features/projects/blobs/edit_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Editing file blob', :js do diff --git a/spec/features/projects/blobs/shortcuts_blob_spec.rb b/spec/features/projects/blobs/shortcuts_blob_spec.rb index 3925de6cfb9..bc12a8ff007 100644 --- a/spec/features/projects/blobs/shortcuts_blob_spec.rb +++ b/spec/features/projects/blobs/shortcuts_blob_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Blob shortcuts', :js do diff --git a/spec/features/projects/blobs/user_creates_new_blob_in_new_project_spec.rb b/spec/features/projects/blobs/user_creates_new_blob_in_new_project_spec.rb index 8a0b92190dd..b90129d6176 100644 --- a/spec/features/projects/blobs/user_creates_new_blob_in_new_project_spec.rb +++ b/spec/features/projects/blobs/user_creates_new_blob_in_new_project_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User creates blob in new project', :js do diff --git a/spec/features/projects/branches/download_buttons_spec.rb b/spec/features/projects/branches/download_buttons_spec.rb index 3e75890725e..401425187b0 100644 --- a/spec/features/projects/branches/download_buttons_spec.rb +++ b/spec/features/projects/branches/download_buttons_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Download buttons in branches page' do diff --git a/spec/features/projects/branches/new_branch_ref_dropdown_spec.rb b/spec/features/projects/branches/new_branch_ref_dropdown_spec.rb index 0faf73db7da..4b6b07f6cda 100644 --- a/spec/features/projects/branches/new_branch_ref_dropdown_spec.rb +++ b/spec/features/projects/branches/new_branch_ref_dropdown_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'New Branch Ref Dropdown', :js do diff --git a/spec/features/projects/branches/user_creates_branch_spec.rb b/spec/features/projects/branches/user_creates_branch_spec.rb index b706ad64954..156edb973cd 100644 --- a/spec/features/projects/branches/user_creates_branch_spec.rb +++ b/spec/features/projects/branches/user_creates_branch_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "spec_helper" describe "User creates branch", :js do diff --git a/spec/features/projects/branches/user_deletes_branch_spec.rb b/spec/features/projects/branches/user_deletes_branch_spec.rb index 96f215e1606..1f053b69646 100644 --- a/spec/features/projects/branches/user_deletes_branch_spec.rb +++ b/spec/features/projects/branches/user_deletes_branch_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "spec_helper" describe "User deletes branch", :js do diff --git a/spec/features/projects/branches/user_views_branches_spec.rb b/spec/features/projects/branches/user_views_branches_spec.rb index 777d30fdffd..f3810611094 100644 --- a/spec/features/projects/branches/user_views_branches_spec.rb +++ b/spec/features/projects/branches/user_views_branches_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "spec_helper" describe "User views branches" do diff --git a/spec/features/projects/branches_spec.rb b/spec/features/projects/branches_spec.rb index ee71c843b80..b35067d0f4d 100644 --- a/spec/features/projects/branches_spec.rb +++ b/spec/features/projects/branches_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Branches' do diff --git a/spec/features/projects/ci/lint_spec.rb b/spec/features/projects/ci/lint_spec.rb index 313950072e7..521cfb54cd2 100644 --- a/spec/features/projects/ci/lint_spec.rb +++ b/spec/features/projects/ci/lint_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'CI Lint', :js do diff --git a/spec/features/projects/clusters/applications_spec.rb b/spec/features/projects/clusters/applications_spec.rb index c75259d1b0c..d0182270d82 100644 --- a/spec/features/projects/clusters/applications_spec.rb +++ b/spec/features/projects/clusters/applications_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Clusters Applications', :js do diff --git a/spec/features/projects/clusters/gcp_spec.rb b/spec/features/projects/clusters/gcp_spec.rb index 974e0f84681..820ce48e52c 100644 --- a/spec/features/projects/clusters/gcp_spec.rb +++ b/spec/features/projects/clusters/gcp_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Gcp Cluster', :js do diff --git a/spec/features/projects/clusters/user_spec.rb b/spec/features/projects/clusters/user_spec.rb index 31cc09ae911..3899aab8170 100644 --- a/spec/features/projects/clusters/user_spec.rb +++ b/spec/features/projects/clusters/user_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User Cluster', :js do diff --git a/spec/features/projects/commit/builds_spec.rb b/spec/features/projects/commit/builds_spec.rb index d72476f36a9..d28ff5d3b5f 100644 --- a/spec/features/projects/commit/builds_spec.rb +++ b/spec/features/projects/commit/builds_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'project commit pipelines', :js do diff --git a/spec/features/projects/commit/cherry_pick_spec.rb b/spec/features/projects/commit/cherry_pick_spec.rb index acfb582dba9..46a6f62ba14 100644 --- a/spec/features/projects/commit/cherry_pick_spec.rb +++ b/spec/features/projects/commit/cherry_pick_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Cherry-pick Commits' do diff --git a/spec/features/projects/commit/comments/user_adds_comment_spec.rb b/spec/features/projects/commit/comments/user_adds_comment_spec.rb index 586e2e33112..bae8e6dc827 100644 --- a/spec/features/projects/commit/comments/user_adds_comment_spec.rb +++ b/spec/features/projects/commit/comments/user_adds_comment_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "spec_helper" describe "User adds a comment on a commit", :js do diff --git a/spec/features/projects/commit/comments/user_deletes_comments_spec.rb b/spec/features/projects/commit/comments/user_deletes_comments_spec.rb index a727cab4ac7..2993a402e37 100644 --- a/spec/features/projects/commit/comments/user_deletes_comments_spec.rb +++ b/spec/features/projects/commit/comments/user_deletes_comments_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "spec_helper" describe "User deletes comments on a commit", :js do diff --git a/spec/features/projects/commit/comments/user_edits_comments_spec.rb b/spec/features/projects/commit/comments/user_edits_comments_spec.rb index 75bccd99f59..0fa2b2ff232 100644 --- a/spec/features/projects/commit/comments/user_edits_comments_spec.rb +++ b/spec/features/projects/commit/comments/user_edits_comments_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "spec_helper" describe "User edits a comment on a commit", :js do diff --git a/spec/features/projects/commit/diff_notes_spec.rb b/spec/features/projects/commit/diff_notes_spec.rb index e2aefa35fad..04bd66df28d 100644 --- a/spec/features/projects/commit/diff_notes_spec.rb +++ b/spec/features/projects/commit/diff_notes_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Commit diff', :js do diff --git a/spec/features/projects/commit/mini_pipeline_graph_spec.rb b/spec/features/projects/commit/mini_pipeline_graph_spec.rb index 614f11c8392..1199a3bd226 100644 --- a/spec/features/projects/commit/mini_pipeline_graph_spec.rb +++ b/spec/features/projects/commit/mini_pipeline_graph_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Mini Pipeline Graph in Commit View', :js do diff --git a/spec/features/projects/commit/user_comments_on_commit_spec.rb b/spec/features/projects/commit/user_comments_on_commit_spec.rb index 73ce8d2b996..f4fea9b9ae0 100644 --- a/spec/features/projects/commit/user_comments_on_commit_spec.rb +++ b/spec/features/projects/commit/user_comments_on_commit_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "spec_helper" describe "User comments on commit", :js do diff --git a/spec/features/projects/commit/user_reverts_commit_spec.rb b/spec/features/projects/commit/user_reverts_commit_spec.rb index 42844a03ea6..39ee72a4a99 100644 --- a/spec/features/projects/commit/user_reverts_commit_spec.rb +++ b/spec/features/projects/commit/user_reverts_commit_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User reverts a commit', :js do diff --git a/spec/features/projects/commits/rss_spec.rb b/spec/features/projects/commits/rss_spec.rb index cfc2637f1b2..0266df48d4a 100644 --- a/spec/features/projects/commits/rss_spec.rb +++ b/spec/features/projects/commits/rss_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Project Commits RSS' do diff --git a/spec/features/projects/commits/user_browses_commits_spec.rb b/spec/features/projects/commits/user_browses_commits_spec.rb index fc74a370e72..085d8d63d52 100644 --- a/spec/features/projects/commits/user_browses_commits_spec.rb +++ b/spec/features/projects/commits/user_browses_commits_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User browses commits' do @@ -13,7 +15,7 @@ describe 'User browses commits' do it 'renders commit' do visit project_commit_path(project, sample_commit.id) - expect(page).to have_content(sample_commit.message.gsub!(/\s+/, ' ')) + expect(page).to have_content(sample_commit.message.gsub(/\s+/, ' ')) .and have_content("Showing #{sample_commit.files_changed_count} changed files") .and have_content('Side-by-side') end diff --git a/spec/features/projects/compare_spec.rb b/spec/features/projects/compare_spec.rb index 5f7cf68987e..2674617bcfc 100644 --- a/spec/features/projects/compare_spec.rb +++ b/spec/features/projects/compare_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "spec_helper" describe "Compare", :js do diff --git a/spec/features/projects/deploy_keys_spec.rb b/spec/features/projects/deploy_keys_spec.rb index 1fa9babaff5..0f3e7646673 100644 --- a/spec/features/projects/deploy_keys_spec.rb +++ b/spec/features/projects/deploy_keys_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Project deploy keys', :js do diff --git a/spec/features/projects/diffs/diff_show_spec.rb b/spec/features/projects/diffs/diff_show_spec.rb index df05625d105..df94d6debd6 100644 --- a/spec/features/projects/diffs/diff_show_spec.rb +++ b/spec/features/projects/diffs/diff_show_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Diff file viewer', :js do diff --git a/spec/features/projects/environments/environment_metrics_spec.rb b/spec/features/projects/environments/environment_metrics_spec.rb index b08ccdc2a7c..c027b776d67 100644 --- a/spec/features/projects/environments/environment_metrics_spec.rb +++ b/spec/features/projects/environments/environment_metrics_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Environment > Metrics' do diff --git a/spec/features/projects/environments/environment_spec.rb b/spec/features/projects/environments/environment_spec.rb index fbaf12be64e..497880a7835 100644 --- a/spec/features/projects/environments/environment_spec.rb +++ b/spec/features/projects/environments/environment_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Environment' do diff --git a/spec/features/projects/environments/environments_spec.rb b/spec/features/projects/environments/environments_spec.rb index 1b5d9083932..1a2302b3d0c 100644 --- a/spec/features/projects/environments/environments_spec.rb +++ b/spec/features/projects/environments/environments_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Environments page', :js do diff --git a/spec/features/projects/features_visibility_spec.rb b/spec/features/projects/features_visibility_spec.rb index 254e885ce46..ca383da5f5c 100644 --- a/spec/features/projects/features_visibility_spec.rb +++ b/spec/features/projects/features_visibility_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Edit Project Settings' do diff --git a/spec/features/projects/files/dockerfile_dropdown_spec.rb b/spec/features/projects/files/dockerfile_dropdown_spec.rb index 004585f7c9e..2e0c589e168 100644 --- a/spec/features/projects/files/dockerfile_dropdown_spec.rb +++ b/spec/features/projects/files/dockerfile_dropdown_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Files > User wants to add a Dockerfile file' do diff --git a/spec/features/projects/files/download_buttons_spec.rb b/spec/features/projects/files/download_buttons_spec.rb index 111972a6b00..a4889f8d4c4 100644 --- a/spec/features/projects/files/download_buttons_spec.rb +++ b/spec/features/projects/files/download_buttons_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Files > Download buttons in files tree' do diff --git a/spec/features/projects/files/edit_file_soft_wrap_spec.rb b/spec/features/projects/files/edit_file_soft_wrap_spec.rb index 41af70d8ebc..df6bc6883a9 100644 --- a/spec/features/projects/files/edit_file_soft_wrap_spec.rb +++ b/spec/features/projects/files/edit_file_soft_wrap_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Files > User uses soft wrap whilst editing file', :js do diff --git a/spec/features/projects/files/editing_a_file_spec.rb b/spec/features/projects/files/editing_a_file_spec.rb index 4074e67e2d2..085276f96a8 100644 --- a/spec/features/projects/files/editing_a_file_spec.rb +++ b/spec/features/projects/files/editing_a_file_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Files > User wants to edit a file' do diff --git a/spec/features/projects/files/files_sort_submodules_with_folders_spec.rb b/spec/features/projects/files/files_sort_submodules_with_folders_spec.rb index 51c884201a6..0e43f2fd26b 100644 --- a/spec/features/projects/files/files_sort_submodules_with_folders_spec.rb +++ b/spec/features/projects/files/files_sort_submodules_with_folders_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Files > User views files page' do diff --git a/spec/features/projects/files/find_file_keyboard_spec.rb b/spec/features/projects/files/find_file_keyboard_spec.rb index cd0235f2b9e..b680be09444 100644 --- a/spec/features/projects/files/find_file_keyboard_spec.rb +++ b/spec/features/projects/files/find_file_keyboard_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Files > Find file keyboard shortcuts', :js do diff --git a/spec/features/projects/files/gitignore_dropdown_spec.rb b/spec/features/projects/files/gitignore_dropdown_spec.rb index 9fa4c053a40..dcb960b880a 100644 --- a/spec/features/projects/files/gitignore_dropdown_spec.rb +++ b/spec/features/projects/files/gitignore_dropdown_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Files > User wants to add a .gitignore file' do diff --git a/spec/features/projects/files/gitlab_ci_yml_dropdown_spec.rb b/spec/features/projects/files/gitlab_ci_yml_dropdown_spec.rb index 53aff183562..875ae5d34d1 100644 --- a/spec/features/projects/files/gitlab_ci_yml_dropdown_spec.rb +++ b/spec/features/projects/files/gitlab_ci_yml_dropdown_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Files > User wants to add a .gitlab-ci.yml file' do diff --git a/spec/features/projects/files/project_owner_creates_license_file_spec.rb b/spec/features/projects/files/project_owner_creates_license_file_spec.rb index 44715261b8b..2944089358f 100644 --- a/spec/features/projects/files/project_owner_creates_license_file_spec.rb +++ b/spec/features/projects/files/project_owner_creates_license_file_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Files > Project owner creates a license file', :js do diff --git a/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb b/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb index 0b8474fb87a..556b7227403 100644 --- a/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb +++ b/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Files > Project owner sees a link to create a license file in empty project', :js do diff --git a/spec/features/projects/files/template_selector_menu_spec.rb b/spec/features/projects/files/template_selector_menu_spec.rb index 6b313824acd..838a484d62e 100644 --- a/spec/features/projects/files/template_selector_menu_spec.rb +++ b/spec/features/projects/files/template_selector_menu_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Template selector menu', :js do diff --git a/spec/features/projects/files/template_type_dropdown_spec.rb b/spec/features/projects/files/template_type_dropdown_spec.rb index 342a93b328f..8b385185e2e 100644 --- a/spec/features/projects/files/template_type_dropdown_spec.rb +++ b/spec/features/projects/files/template_type_dropdown_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Files > Template type dropdown selector', :js do diff --git a/spec/features/projects/files/undo_template_spec.rb b/spec/features/projects/files/undo_template_spec.rb index 91618145391..d3f8d36a0a9 100644 --- a/spec/features/projects/files/undo_template_spec.rb +++ b/spec/features/projects/files/undo_template_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Files > Template Undo Button', :js do diff --git a/spec/features/projects/files/user_browses_a_tree_with_a_folder_containing_only_a_folder.rb b/spec/features/projects/files/user_browses_a_tree_with_a_folder_containing_only_a_folder.rb index 2d67837763c..934de2fde8f 100644 --- a/spec/features/projects/files/user_browses_a_tree_with_a_folder_containing_only_a_folder.rb +++ b/spec/features/projects/files/user_browses_a_tree_with_a_folder_containing_only_a_folder.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' # This is a regression test for https://gitlab.com/gitlab-org/gitlab-ce/issues/37569 diff --git a/spec/features/projects/files/user_browses_files_spec.rb b/spec/features/projects/files/user_browses_files_spec.rb index a5d849db8a3..a090461261b 100644 --- a/spec/features/projects/files/user_browses_files_spec.rb +++ b/spec/features/projects/files/user_browses_files_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "spec_helper" describe "User browses files" do diff --git a/spec/features/projects/files/user_browses_lfs_files_spec.rb b/spec/features/projects/files/user_browses_lfs_files_spec.rb index d5cb8f9212d..08ebeed2cdd 100644 --- a/spec/features/projects/files/user_browses_lfs_files_spec.rb +++ b/spec/features/projects/files/user_browses_lfs_files_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Files > User browses LFS files' do diff --git a/spec/features/projects/files/user_creates_directory_spec.rb b/spec/features/projects/files/user_creates_directory_spec.rb index e29e867492e..19d95c87c6c 100644 --- a/spec/features/projects/files/user_creates_directory_spec.rb +++ b/spec/features/projects/files/user_creates_directory_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Files > User creates a directory', :js do diff --git a/spec/features/projects/files/user_creates_files_spec.rb b/spec/features/projects/files/user_creates_files_spec.rb index 264b288ab38..74c037641cd 100644 --- a/spec/features/projects/files/user_creates_files_spec.rb +++ b/spec/features/projects/files/user_creates_files_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Files > User creates files' do diff --git a/spec/features/projects/files/user_deletes_files_spec.rb b/spec/features/projects/files/user_deletes_files_spec.rb index 11ee87f245b..fd4783cfb6b 100644 --- a/spec/features/projects/files/user_deletes_files_spec.rb +++ b/spec/features/projects/files/user_deletes_files_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Files > User deletes files', :js do diff --git a/spec/features/projects/files/user_edits_files_spec.rb b/spec/features/projects/files/user_edits_files_spec.rb index e4b02408b49..56430721ed6 100644 --- a/spec/features/projects/files/user_edits_files_spec.rb +++ b/spec/features/projects/files/user_edits_files_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Files > User edits files', :js do diff --git a/spec/features/projects/files/user_find_file_spec.rb b/spec/features/projects/files/user_find_file_spec.rb index e2d881b34d2..72f6ccb20d6 100644 --- a/spec/features/projects/files/user_find_file_spec.rb +++ b/spec/features/projects/files/user_find_file_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User find project file' do diff --git a/spec/features/projects/files/user_reads_pipeline_status_spec.rb b/spec/features/projects/files/user_reads_pipeline_status_spec.rb index 5bce96d9b80..15f8fa7438d 100644 --- a/spec/features/projects/files/user_reads_pipeline_status_spec.rb +++ b/spec/features/projects/files/user_reads_pipeline_status_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'user reads pipeline status', :js do diff --git a/spec/features/projects/files/user_replaces_files_spec.rb b/spec/features/projects/files/user_replaces_files_spec.rb index bfd612e4cc8..d50bc0a7d18 100644 --- a/spec/features/projects/files/user_replaces_files_spec.rb +++ b/spec/features/projects/files/user_replaces_files_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Files > User replaces files', :js do diff --git a/spec/features/projects/files/user_searches_for_files_spec.rb b/spec/features/projects/files/user_searches_for_files_spec.rb index a90e4918fb1..e82f54fbe50 100644 --- a/spec/features/projects/files/user_searches_for_files_spec.rb +++ b/spec/features/projects/files/user_searches_for_files_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Files > User searches for files' do diff --git a/spec/features/projects/files/user_uploads_files_spec.rb b/spec/features/projects/files/user_uploads_files_spec.rb index 25ff3fdf411..74b5d7c5041 100644 --- a/spec/features/projects/files/user_uploads_files_spec.rb +++ b/spec/features/projects/files/user_uploads_files_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Files > User uploads files' do diff --git a/spec/features/projects/fork_spec.rb b/spec/features/projects/fork_spec.rb index 26b94bf58b2..2aed402652b 100644 --- a/spec/features/projects/fork_spec.rb +++ b/spec/features/projects/fork_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Project fork' do diff --git a/spec/features/projects/forks/fork_list_spec.rb b/spec/features/projects/forks/fork_list_spec.rb index 2c41c61a660..2dbe3d90bad 100644 --- a/spec/features/projects/forks/fork_list_spec.rb +++ b/spec/features/projects/forks/fork_list_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'listing forks of a project' do diff --git a/spec/features/projects/gfm_autocomplete_load_spec.rb b/spec/features/projects/gfm_autocomplete_load_spec.rb index 1c988726ae6..ad39dec0a43 100644 --- a/spec/features/projects/gfm_autocomplete_load_spec.rb +++ b/spec/features/projects/gfm_autocomplete_load_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'GFM autocomplete loading', :js do diff --git a/spec/features/projects/graph_spec.rb b/spec/features/projects/graph_spec.rb index e1bc18519a2..6082eb03374 100644 --- a/spec/features/projects/graph_spec.rb +++ b/spec/features/projects/graph_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Project Graph', :js do diff --git a/spec/features/projects/hook_logs/user_reads_log_spec.rb b/spec/features/projects/hook_logs/user_reads_log_spec.rb index 086cd4b9f03..8c666f5d67a 100644 --- a/spec/features/projects/hook_logs/user_reads_log_spec.rb +++ b/spec/features/projects/hook_logs/user_reads_log_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Hook logs' do diff --git a/spec/features/projects/import_export/export_file_spec.rb b/spec/features/projects/import_export/export_file_spec.rb index c71a778fc84..a1002f38936 100644 --- a/spec/features/projects/import_export/export_file_spec.rb +++ b/spec/features/projects/import_export/export_file_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' # Integration test that exports a file using the Import/Export feature diff --git a/spec/features/projects/import_export/import_file_spec.rb b/spec/features/projects/import_export/import_file_spec.rb index 8d2b1fc7e30..a12fc8b18ed 100644 --- a/spec/features/projects/import_export/import_file_spec.rb +++ b/spec/features/projects/import_export/import_file_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Import/Export - project import integration test', :js do diff --git a/spec/features/projects/issuable_templates_spec.rb b/spec/features/projects/issuable_templates_spec.rb index a57edc394f9..18eadb7c4a3 100644 --- a/spec/features/projects/issuable_templates_spec.rb +++ b/spec/features/projects/issuable_templates_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'issuable templates', :js do diff --git a/spec/features/projects/issues/viewing_issues_with_external_authorization_enabled_spec.rb b/spec/features/projects/issues/viewing_issues_with_external_authorization_enabled_spec.rb index a8612d77a5e..6c8f4b51ea0 100644 --- a/spec/features/projects/issues/viewing_issues_with_external_authorization_enabled_spec.rb +++ b/spec/features/projects/issues/viewing_issues_with_external_authorization_enabled_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'viewing an issue with cross project references' do diff --git a/spec/features/projects/jobs/permissions_spec.rb b/spec/features/projects/jobs/permissions_spec.rb index b5e711997a0..44309a9c4bf 100644 --- a/spec/features/projects/jobs/permissions_spec.rb +++ b/spec/features/projects/jobs/permissions_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Project Jobs Permissions' do diff --git a/spec/features/projects/jobs/user_browses_job_spec.rb b/spec/features/projects/jobs/user_browses_job_spec.rb index fbe765d4c44..6d0269dd96b 100644 --- a/spec/features/projects/jobs/user_browses_job_spec.rb +++ b/spec/features/projects/jobs/user_browses_job_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User browses a job', :js do diff --git a/spec/features/projects/jobs/user_browses_jobs_spec.rb b/spec/features/projects/jobs/user_browses_jobs_spec.rb index ebc20d15d67..44709cb1230 100644 --- a/spec/features/projects/jobs/user_browses_jobs_spec.rb +++ b/spec/features/projects/jobs/user_browses_jobs_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User browses jobs' do diff --git a/spec/features/projects/jobs_spec.rb b/spec/features/projects/jobs_spec.rb index f4ed89adc0f..8ed420300af 100644 --- a/spec/features/projects/jobs_spec.rb +++ b/spec/features/projects/jobs_spec.rb @@ -701,12 +701,12 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do it 'shows manual action empty state', :js do expect(page).to have_content(job.detailed_status(user).illustration[:title]) expect(page).to have_content('This job requires a manual action') - expect(page).to have_content('This job depends on a user to trigger its process. Often they are used to deploy code to production environments') - expect(page).to have_link('Trigger this manual action') + expect(page).to have_content('This job requires manual intervention to start. Before starting this job, you can add variables below for last-minute configuration changes.') + expect(page).to have_button('Trigger this manual action') end it 'plays manual action and shows pending status', :js do - click_link 'Trigger this manual action' + click_button 'Trigger this manual action' wait_for_requests expect(page).to have_content('This job has not started yet') @@ -734,8 +734,8 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do wait_for_requests expect(page).to have_content('This job requires a manual action') - expect(page).to have_content('This job depends on a user to trigger its process. Often they are used to deploy code to production environments') - expect(page).to have_link('Trigger this manual action') + expect(page).to have_content('This job requires manual intervention to start. Before starting this job, you can add variables below for last-minute configuration changes.') + expect(page).to have_button('Trigger this manual action') end end diff --git a/spec/features/projects/labels/issues_sorted_by_priority_spec.rb b/spec/features/projects/labels/issues_sorted_by_priority_spec.rb index 25417cf4955..55629376007 100644 --- a/spec/features/projects/labels/issues_sorted_by_priority_spec.rb +++ b/spec/features/projects/labels/issues_sorted_by_priority_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Issue prioritization' do diff --git a/spec/features/projects/labels/subscription_spec.rb b/spec/features/projects/labels/subscription_spec.rb index 49227eebf3d..1d0f9e73a1b 100644 --- a/spec/features/projects/labels/subscription_spec.rb +++ b/spec/features/projects/labels/subscription_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Labels subscription' do diff --git a/spec/features/projects/labels/update_prioritization_spec.rb b/spec/features/projects/labels/update_prioritization_spec.rb index f32b155790f..3a37ee6623d 100644 --- a/spec/features/projects/labels/update_prioritization_spec.rb +++ b/spec/features/projects/labels/update_prioritization_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Prioritize labels' do diff --git a/spec/features/projects/labels/user_creates_labels_spec.rb b/spec/features/projects/labels/user_creates_labels_spec.rb index c71b04fea09..257e064ae3d 100644 --- a/spec/features/projects/labels/user_creates_labels_spec.rb +++ b/spec/features/projects/labels/user_creates_labels_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "spec_helper" describe "User creates labels" do diff --git a/spec/features/projects/labels/user_edits_labels_spec.rb b/spec/features/projects/labels/user_edits_labels_spec.rb index 0708bbd40ce..da33ae3af3a 100644 --- a/spec/features/projects/labels/user_edits_labels_spec.rb +++ b/spec/features/projects/labels/user_edits_labels_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "spec_helper" describe "User edits labels" do diff --git a/spec/features/projects/labels/user_removes_labels_spec.rb b/spec/features/projects/labels/user_removes_labels_spec.rb index 7f49ddf560f..459adeeec30 100644 --- a/spec/features/projects/labels/user_removes_labels_spec.rb +++ b/spec/features/projects/labels/user_removes_labels_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "spec_helper" describe "User removes labels" do diff --git a/spec/features/projects/labels/user_sees_breadcrumb_links_spec.rb b/spec/features/projects/labels/user_sees_breadcrumb_links_spec.rb index 0c0501f438a..35c84204910 100644 --- a/spec/features/projects/labels/user_sees_breadcrumb_links_spec.rb +++ b/spec/features/projects/labels/user_sees_breadcrumb_links_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'New project label breadcrumb' do diff --git a/spec/features/projects/labels/user_sees_links_to_issuables.rb b/spec/features/projects/labels/user_sees_links_to_issuables.rb index c404fc8d66f..fd2151a1f8e 100644 --- a/spec/features/projects/labels/user_sees_links_to_issuables.rb +++ b/spec/features/projects/labels/user_sees_links_to_issuables.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Labels > User sees links to issuables' do diff --git a/spec/features/projects/members/anonymous_user_sees_members_spec.rb b/spec/features/projects/members/anonymous_user_sees_members_spec.rb index b3ed725f602..096cf97551a 100644 --- a/spec/features/projects/members/anonymous_user_sees_members_spec.rb +++ b/spec/features/projects/members/anonymous_user_sees_members_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Members > Anonymous user sees members' do diff --git a/spec/features/projects/members/group_member_cannot_leave_group_project_spec.rb b/spec/features/projects/members/group_member_cannot_leave_group_project_spec.rb index a645b917568..b6f6e2ca85f 100644 --- a/spec/features/projects/members/group_member_cannot_leave_group_project_spec.rb +++ b/spec/features/projects/members/group_member_cannot_leave_group_project_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Members > Group member cannot leave group project' do diff --git a/spec/features/projects/members/group_member_cannot_request_access_to_his_group_project_spec.rb b/spec/features/projects/members/group_member_cannot_request_access_to_his_group_project_spec.rb index bb475ea95e5..1f4d555c6ae 100644 --- a/spec/features/projects/members/group_member_cannot_request_access_to_his_group_project_spec.rb +++ b/spec/features/projects/members/group_member_cannot_request_access_to_his_group_project_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Members > Group member cannot request access to his group project' do diff --git a/spec/features/projects/members/group_members_spec.rb b/spec/features/projects/members/group_members_spec.rb index 0b2cd13b8ec..dd5fc82e058 100644 --- a/spec/features/projects/members/group_members_spec.rb +++ b/spec/features/projects/members/group_members_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects members' do diff --git a/spec/features/projects/members/group_requester_cannot_request_access_to_project_spec.rb b/spec/features/projects/members/group_requester_cannot_request_access_to_project_spec.rb index ea3894c92bd..fb4238f0a1f 100644 --- a/spec/features/projects/members/group_requester_cannot_request_access_to_project_spec.rb +++ b/spec/features/projects/members/group_requester_cannot_request_access_to_project_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Members > Group requester cannot request access to project', :js do diff --git a/spec/features/projects/members/groups_with_access_list_spec.rb b/spec/features/projects/members/groups_with_access_list_spec.rb index c0b5d943e96..7b1fded1834 100644 --- a/spec/features/projects/members/groups_with_access_list_spec.rb +++ b/spec/features/projects/members/groups_with_access_list_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Members > Groups with access list', :js do diff --git a/spec/features/projects/members/invite_group_spec.rb b/spec/features/projects/members/invite_group_spec.rb index 7432c600c1e..e76637039c6 100644 --- a/spec/features/projects/members/invite_group_spec.rb +++ b/spec/features/projects/members/invite_group_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Project > Members > Invite group', :js do @@ -58,7 +60,7 @@ describe 'Project > Members > Invite group', :js do end end - context 'for a project in a subgroup', :nested_groups do + context 'for a project in a subgroup' do let!(:group_to_share_with) { create(:group) } let(:root_group) { create(:group) } let(:subgroup) { create(:group, parent: root_group) } @@ -181,7 +183,7 @@ describe 'Project > Members > Invite group', :js do group_to_share_with.add_maintainer(maintainer) end - it 'the groups dropdown does not show ancestors', :nested_groups do + it 'the groups dropdown does not show ancestors' do visit project_settings_members_path(project) click_on 'invite-group-tab' diff --git a/spec/features/projects/members/list_spec.rb b/spec/features/projects/members/list_spec.rb index cf309492808..6d92c777033 100644 --- a/spec/features/projects/members/list_spec.rb +++ b/spec/features/projects/members/list_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Project members list' do diff --git a/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb b/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb index 26de6fb33fd..501dd05300a 100644 --- a/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb +++ b/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Members > Maintainer adds member with expiration date', :js do diff --git a/spec/features/projects/members/master_manages_access_requests_spec.rb b/spec/features/projects/members/master_manages_access_requests_spec.rb index adc8202cde7..17d6efbcaa5 100644 --- a/spec/features/projects/members/master_manages_access_requests_spec.rb +++ b/spec/features/projects/members/master_manages_access_requests_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Members > Maintainer manages access requests' do diff --git a/spec/features/projects/members/member_cannot_request_access_to_his_project_spec.rb b/spec/features/projects/members/member_cannot_request_access_to_his_project_spec.rb index f612ad8d551..606444b36a2 100644 --- a/spec/features/projects/members/member_cannot_request_access_to_his_project_spec.rb +++ b/spec/features/projects/members/member_cannot_request_access_to_his_project_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Members > Member cannot request access to his project' do diff --git a/spec/features/projects/members/member_leaves_project_spec.rb b/spec/features/projects/members/member_leaves_project_spec.rb index bd2ef9c07c4..fb1165838c7 100644 --- a/spec/features/projects/members/member_leaves_project_spec.rb +++ b/spec/features/projects/members/member_leaves_project_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Members > Member leaves project' do diff --git a/spec/features/projects/members/owner_cannot_leave_project_spec.rb b/spec/features/projects/members/owner_cannot_leave_project_spec.rb index 0aa005adb4d..781c584796d 100644 --- a/spec/features/projects/members/owner_cannot_leave_project_spec.rb +++ b/spec/features/projects/members/owner_cannot_leave_project_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Members > Owner cannot leave project' do diff --git a/spec/features/projects/members/owner_cannot_request_access_to_his_project_spec.rb b/spec/features/projects/members/owner_cannot_request_access_to_his_project_spec.rb index eb1b720af05..2fb76da36ad 100644 --- a/spec/features/projects/members/owner_cannot_request_access_to_his_project_spec.rb +++ b/spec/features/projects/members/owner_cannot_request_access_to_his_project_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Members > Owner cannot request access to his project' do diff --git a/spec/features/projects/members/sorting_spec.rb b/spec/features/projects/members/sorting_spec.rb index 220775b514d..332f07614da 100644 --- a/spec/features/projects/members/sorting_spec.rb +++ b/spec/features/projects/members/sorting_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Members > Sorting' do diff --git a/spec/features/projects/members/user_requests_access_spec.rb b/spec/features/projects/members/user_requests_access_spec.rb index f26941ab567..9f7327cd6e4 100644 --- a/spec/features/projects/members/user_requests_access_spec.rb +++ b/spec/features/projects/members/user_requests_access_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Members > User requests access', :js do diff --git a/spec/features/projects/merge_request_button_spec.rb b/spec/features/projects/merge_request_button_spec.rb index 69561b4d733..950af8b0ae0 100644 --- a/spec/features/projects/merge_request_button_spec.rb +++ b/spec/features/projects/merge_request_button_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Merge Request button' do diff --git a/spec/features/projects/milestones/milestone_spec.rb b/spec/features/projects/milestones/milestone_spec.rb index ff31092b910..5e94b2f721e 100644 --- a/spec/features/projects/milestones/milestone_spec.rb +++ b/spec/features/projects/milestones/milestone_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Project milestone' do diff --git a/spec/features/projects/milestones/milestones_sorting_spec.rb b/spec/features/projects/milestones/milestones_sorting_spec.rb index dc711377e6e..77cf696fb7c 100644 --- a/spec/features/projects/milestones/milestones_sorting_spec.rb +++ b/spec/features/projects/milestones/milestones_sorting_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Milestones sorting', :js do diff --git a/spec/features/projects/milestones/new_spec.rb b/spec/features/projects/milestones/new_spec.rb index 0b5ab547dce..b1b74bed59d 100644 --- a/spec/features/projects/milestones/new_spec.rb +++ b/spec/features/projects/milestones/new_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Creating a new project milestone', :js do diff --git a/spec/features/projects/milestones/user_interacts_with_labels_spec.rb b/spec/features/projects/milestones/user_interacts_with_labels_spec.rb index a6d58be7b13..0177871599a 100644 --- a/spec/features/projects/milestones/user_interacts_with_labels_spec.rb +++ b/spec/features/projects/milestones/user_interacts_with_labels_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User interacts with labels' do diff --git a/spec/features/projects/network_graph_spec.rb b/spec/features/projects/network_graph_spec.rb index 9f9a7787093..2f6a2e90ab9 100644 --- a/spec/features/projects/network_graph_spec.rb +++ b/spec/features/projects/network_graph_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Project Network Graph', :js do diff --git a/spec/features/projects/new_project_spec.rb b/spec/features/projects/new_project_spec.rb index 7602935b47e..010a5de6930 100644 --- a/spec/features/projects/new_project_spec.rb +++ b/spec/features/projects/new_project_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'New project' do @@ -294,7 +296,7 @@ describe 'New project' do end end - context 'from manifest file', :postgresql do + context 'from manifest file' do before do first('.import_manifest').click end diff --git a/spec/features/projects/pipeline_schedules_spec.rb b/spec/features/projects/pipeline_schedules_spec.rb index 24041a51383..c21b1e36f9a 100644 --- a/spec/features/projects/pipeline_schedules_spec.rb +++ b/spec/features/projects/pipeline_schedules_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Pipeline Schedules', :js do diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb index 885d5f85989..4fb72eb8737 100644 --- a/spec/features/projects/pipelines/pipelines_spec.rb +++ b/spec/features/projects/pipelines/pipelines_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Pipelines', :js do diff --git a/spec/features/projects/releases/user_views_releases_spec.rb b/spec/features/projects/releases/user_views_releases_spec.rb index 725d7173bce..a9b8ff9dc4d 100644 --- a/spec/features/projects/releases/user_views_releases_spec.rb +++ b/spec/features/projects/releases/user_views_releases_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User views releases', :js do diff --git a/spec/features/projects/remote_mirror_spec.rb b/spec/features/projects/remote_mirror_spec.rb index 33e9b73efe8..d357aabead7 100644 --- a/spec/features/projects/remote_mirror_spec.rb +++ b/spec/features/projects/remote_mirror_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Project remote mirror', :feature do diff --git a/spec/features/projects/services/disable_triggers_spec.rb b/spec/features/projects/services/disable_triggers_spec.rb index 1a13fe03a67..2785f74bee2 100644 --- a/spec/features/projects/services/disable_triggers_spec.rb +++ b/spec/features/projects/services/disable_triggers_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Disable individual triggers' do diff --git a/spec/features/projects/services/user_activates_asana_spec.rb b/spec/features/projects/services/user_activates_asana_spec.rb index c44e07dd3b4..b07c77da554 100644 --- a/spec/features/projects/services/user_activates_asana_spec.rb +++ b/spec/features/projects/services/user_activates_asana_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User activates Asana' do diff --git a/spec/features/projects/services/user_activates_assembla_spec.rb b/spec/features/projects/services/user_activates_assembla_spec.rb index 9c3884a7c74..56f7beb8f4b 100644 --- a/spec/features/projects/services/user_activates_assembla_spec.rb +++ b/spec/features/projects/services/user_activates_assembla_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User activates Assembla' do diff --git a/spec/features/projects/services/user_activates_atlassian_bamboo_ci_spec.rb b/spec/features/projects/services/user_activates_atlassian_bamboo_ci_spec.rb index 19573565265..c694eeb1cc2 100644 --- a/spec/features/projects/services/user_activates_atlassian_bamboo_ci_spec.rb +++ b/spec/features/projects/services/user_activates_atlassian_bamboo_ci_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User activates Atlassian Bamboo CI' do diff --git a/spec/features/projects/services/user_activates_emails_on_push_spec.rb b/spec/features/projects/services/user_activates_emails_on_push_spec.rb index cc55f7b2060..2015b658295 100644 --- a/spec/features/projects/services/user_activates_emails_on_push_spec.rb +++ b/spec/features/projects/services/user_activates_emails_on_push_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User activates Emails on push' do diff --git a/spec/features/projects/services/user_activates_flowdock_spec.rb b/spec/features/projects/services/user_activates_flowdock_spec.rb index f981b7e9da9..fc8e75daa0d 100644 --- a/spec/features/projects/services/user_activates_flowdock_spec.rb +++ b/spec/features/projects/services/user_activates_flowdock_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User activates Flowdock' do diff --git a/spec/features/projects/services/user_activates_irker_spec.rb b/spec/features/projects/services/user_activates_irker_spec.rb index 4c8e321b411..898e16ce835 100644 --- a/spec/features/projects/services/user_activates_irker_spec.rb +++ b/spec/features/projects/services/user_activates_irker_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User activates Irker (IRC gateway)' do diff --git a/spec/features/projects/services/user_activates_issue_tracker_spec.rb b/spec/features/projects/services/user_activates_issue_tracker_spec.rb index 74b9a2b20cd..5803500a4d2 100644 --- a/spec/features/projects/services/user_activates_issue_tracker_spec.rb +++ b/spec/features/projects/services/user_activates_issue_tracker_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User activates issue tracker', :js do diff --git a/spec/features/projects/services/user_activates_jetbrains_teamcity_ci_spec.rb b/spec/features/projects/services/user_activates_jetbrains_teamcity_ci_spec.rb index c50fd93e4cb..9842141285a 100644 --- a/spec/features/projects/services/user_activates_jetbrains_teamcity_ci_spec.rb +++ b/spec/features/projects/services/user_activates_jetbrains_teamcity_ci_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User activates JetBrains TeamCity CI' do diff --git a/spec/features/projects/services/user_activates_jira_spec.rb b/spec/features/projects/services/user_activates_jira_spec.rb index c52f38e2806..7847b7d5177 100644 --- a/spec/features/projects/services/user_activates_jira_spec.rb +++ b/spec/features/projects/services/user_activates_jira_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User activates Jira', :js do diff --git a/spec/features/projects/services/user_activates_mattermost_slash_command_spec.rb b/spec/features/projects/services/user_activates_mattermost_slash_command_spec.rb index 70f3a812ee9..f8179979018 100644 --- a/spec/features/projects/services/user_activates_mattermost_slash_command_spec.rb +++ b/spec/features/projects/services/user_activates_mattermost_slash_command_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Set up Mattermost slash commands', :js do diff --git a/spec/features/projects/services/user_activates_packagist_spec.rb b/spec/features/projects/services/user_activates_packagist_spec.rb index 756e9b33c07..85bd15adbe5 100644 --- a/spec/features/projects/services/user_activates_packagist_spec.rb +++ b/spec/features/projects/services/user_activates_packagist_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User activates Packagist' do diff --git a/spec/features/projects/services/user_activates_pivotaltracker_spec.rb b/spec/features/projects/services/user_activates_pivotaltracker_spec.rb index 1d6b19e0b0c..67ff99c0295 100644 --- a/spec/features/projects/services/user_activates_pivotaltracker_spec.rb +++ b/spec/features/projects/services/user_activates_pivotaltracker_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User activates PivotalTracker' do diff --git a/spec/features/projects/services/user_activates_prometheus_spec.rb b/spec/features/projects/services/user_activates_prometheus_spec.rb index 61361c8a2e3..a83d3e2e8be 100644 --- a/spec/features/projects/services/user_activates_prometheus_spec.rb +++ b/spec/features/projects/services/user_activates_prometheus_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User activates Prometheus' do diff --git a/spec/features/projects/services/user_activates_pushover_spec.rb b/spec/features/projects/services/user_activates_pushover_spec.rb index 24612ee1457..34e1cf33f36 100644 --- a/spec/features/projects/services/user_activates_pushover_spec.rb +++ b/spec/features/projects/services/user_activates_pushover_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User activates Pushover' do diff --git a/spec/features/projects/services/user_activates_slack_notifications_spec.rb b/spec/features/projects/services/user_activates_slack_notifications_spec.rb index 24b5d5259db..f23b1d3102a 100644 --- a/spec/features/projects/services/user_activates_slack_notifications_spec.rb +++ b/spec/features/projects/services/user_activates_slack_notifications_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User activates Slack notifications' do diff --git a/spec/features/projects/services/user_activates_slack_slash_command_spec.rb b/spec/features/projects/services/user_activates_slack_slash_command_spec.rb index 08cfddf7993..752ef8d592d 100644 --- a/spec/features/projects/services/user_activates_slack_slash_command_spec.rb +++ b/spec/features/projects/services/user_activates_slack_slash_command_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Slack slash commands' do diff --git a/spec/features/projects/services/user_activates_youtrack_spec.rb b/spec/features/projects/services/user_activates_youtrack_spec.rb index bb6a030c1cf..67f0aa214e2 100644 --- a/spec/features/projects/services/user_activates_youtrack_spec.rb +++ b/spec/features/projects/services/user_activates_youtrack_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User activates issue tracker', :js do diff --git a/spec/features/projects/services/user_views_services_spec.rb b/spec/features/projects/services/user_views_services_spec.rb index e9c8cf0fe34..d9358a40602 100644 --- a/spec/features/projects/services/user_views_services_spec.rb +++ b/spec/features/projects/services/user_views_services_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User views services' do diff --git a/spec/features/projects/settings/forked_project_settings_spec.rb b/spec/features/projects/settings/forked_project_settings_spec.rb index df33d215602..a2c6dd8e288 100644 --- a/spec/features/projects/settings/forked_project_settings_spec.rb +++ b/spec/features/projects/settings/forked_project_settings_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Settings > For a forked project', :js do diff --git a/spec/features/projects/settings/integration_settings_spec.rb b/spec/features/projects/settings/integration_settings_spec.rb index 016ccf63f58..26ea4ec5944 100644 --- a/spec/features/projects/settings/integration_settings_spec.rb +++ b/spec/features/projects/settings/integration_settings_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Settings > Integration settings' do diff --git a/spec/features/projects/settings/lfs_settings_spec.rb b/spec/features/projects/settings/lfs_settings_spec.rb index befb306b48d..56606df5a78 100644 --- a/spec/features/projects/settings/lfs_settings_spec.rb +++ b/spec/features/projects/settings/lfs_settings_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Projects > Settings > LFS settings' do diff --git a/spec/features/projects/settings/pipelines_settings_spec.rb b/spec/features/projects/settings/pipelines_settings_spec.rb index bf0c0de89b2..23358d5cd67 100644 --- a/spec/features/projects/settings/pipelines_settings_spec.rb +++ b/spec/features/projects/settings/pipelines_settings_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe "Projects > Settings > Pipelines settings" do @@ -126,7 +128,7 @@ describe "Projects > Settings > Pipelines settings" do end end - context 'when auto devops is turned on group parent level', :nested_groups do + context 'when auto devops is turned on group parent level' do before do group = create(:group, parent: create(:group, :auto_devops_enabled)) project.update!(namespace: group) diff --git a/spec/features/projects/settings/project_badges_spec.rb b/spec/features/projects/settings/project_badges_spec.rb index 42b5547d43b..5791e30a495 100644 --- a/spec/features/projects/settings/project_badges_spec.rb +++ b/spec/features/projects/settings/project_badges_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Project Badges' do diff --git a/spec/features/projects/settings/repository_settings_spec.rb b/spec/features/projects/settings/repository_settings_spec.rb index 1edfee705c8..1294c8822b6 100644 --- a/spec/features/projects/settings/repository_settings_spec.rb +++ b/spec/features/projects/settings/repository_settings_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Settings > Repository settings' do @@ -248,11 +250,11 @@ describe 'Projects > Settings > Repository settings' do visit project_settings_repository_path(project) - mirror = find('.qa-mirrored-repository-row') + mirror = find('.rspec-mirrored-repository-row') - expect(mirror).to have_selector('.qa-delete-mirror') - expect(mirror).to have_selector('.qa-disabled-mirror-badge') - expect(mirror).not_to have_selector('.qa-update-now-button') + expect(mirror).to have_selector('.rspec-delete-mirror') + expect(mirror).to have_selector('.rspec-disabled-mirror-badge') + expect(mirror).not_to have_selector('.rspec-update-now-button') end end end diff --git a/spec/features/projects/settings/user_archives_project_spec.rb b/spec/features/projects/settings/user_archives_project_spec.rb index 5008eab4d39..7667fad7b03 100644 --- a/spec/features/projects/settings/user_archives_project_spec.rb +++ b/spec/features/projects/settings/user_archives_project_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Settings > User archives a project' do diff --git a/spec/features/projects/settings/user_changes_avatar_spec.rb b/spec/features/projects/settings/user_changes_avatar_spec.rb index 64335163016..67789b869da 100644 --- a/spec/features/projects/settings/user_changes_avatar_spec.rb +++ b/spec/features/projects/settings/user_changes_avatar_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Settings > User changes avatar' do diff --git a/spec/features/projects/settings/user_changes_default_branch_spec.rb b/spec/features/projects/settings/user_changes_default_branch_spec.rb index 7dc18601f50..411fc0c7e07 100644 --- a/spec/features/projects/settings/user_changes_default_branch_spec.rb +++ b/spec/features/projects/settings/user_changes_default_branch_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Settings > User changes default branch' do diff --git a/spec/features/projects/settings/user_interacts_with_deploy_keys_spec.rb b/spec/features/projects/settings/user_interacts_with_deploy_keys_spec.rb index ecfb49b9efe..cd9299150b2 100644 --- a/spec/features/projects/settings/user_interacts_with_deploy_keys_spec.rb +++ b/spec/features/projects/settings/user_interacts_with_deploy_keys_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "spec_helper" describe "User interacts with deploy keys", :js do diff --git a/spec/features/projects/settings/user_manages_group_links_spec.rb b/spec/features/projects/settings/user_manages_group_links_spec.rb index e5a58c44e41..7df0bbb9d02 100644 --- a/spec/features/projects/settings/user_manages_group_links_spec.rb +++ b/spec/features/projects/settings/user_manages_group_links_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Settings > User manages group links' do diff --git a/spec/features/projects/settings/user_manages_merge_requests_settings_spec.rb b/spec/features/projects/settings/user_manages_merge_requests_settings_spec.rb index 0739726f52c..9f09c5c4501 100644 --- a/spec/features/projects/settings/user_manages_merge_requests_settings_spec.rb +++ b/spec/features/projects/settings/user_manages_merge_requests_settings_spec.rb @@ -94,7 +94,7 @@ describe 'Projects > Settings > User manages merge request settings' do it 'when unchecked sets :printing_merge_request_link_enabled to false' do uncheck('project_printing_merge_request_link_enabled') within('.merge-request-settings-form') do - find('.qa-save-merge-request-changes') + find('.rspec-save-merge-request-changes') click_on('Save changes') end diff --git a/spec/features/projects/settings/user_manages_project_members_spec.rb b/spec/features/projects/settings/user_manages_project_members_spec.rb index b8ca11d53f0..6d94388a6e2 100644 --- a/spec/features/projects/settings/user_manages_project_members_spec.rb +++ b/spec/features/projects/settings/user_manages_project_members_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Settings > User manages project members' do diff --git a/spec/features/projects/settings/user_renames_a_project_spec.rb b/spec/features/projects/settings/user_renames_a_project_spec.rb index d3979b79910..d2daf8b922d 100644 --- a/spec/features/projects/settings/user_renames_a_project_spec.rb +++ b/spec/features/projects/settings/user_renames_a_project_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Settings > User renames a project' do diff --git a/spec/features/projects/settings/user_sees_revoke_deploy_token_modal_spec.rb b/spec/features/projects/settings/user_sees_revoke_deploy_token_modal_spec.rb index 069704a1305..9c77a08718e 100644 --- a/spec/features/projects/settings/user_sees_revoke_deploy_token_modal_spec.rb +++ b/spec/features/projects/settings/user_sees_revoke_deploy_token_modal_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Repository Settings > User sees revoke deploy token modal', :js do diff --git a/spec/features/projects/settings/user_tags_project_spec.rb b/spec/features/projects/settings/user_tags_project_spec.rb index e3f06c042b9..a919dd0e4af 100644 --- a/spec/features/projects/settings/user_tags_project_spec.rb +++ b/spec/features/projects/settings/user_tags_project_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Settings > User tags a project' do diff --git a/spec/features/projects/settings/user_transfers_a_project_spec.rb b/spec/features/projects/settings/user_transfers_a_project_spec.rb index 2fdbc04fa62..8989eac77b5 100644 --- a/spec/features/projects/settings/user_transfers_a_project_spec.rb +++ b/spec/features/projects/settings/user_transfers_a_project_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Settings > User transfers a project', :js do @@ -68,7 +70,7 @@ describe 'Projects > Settings > User transfers a project', :js do end end - context 'when nested groups are available', :nested_groups do + context 'when nested groups are available' do it 'allows transferring a project to a subgroup' do subgroup = create(:group, parent: group) diff --git a/spec/features/projects/settings/visibility_settings_spec.rb b/spec/features/projects/settings/visibility_settings_spec.rb index 1fbc108697f..46fd676954d 100644 --- a/spec/features/projects/settings/visibility_settings_spec.rb +++ b/spec/features/projects/settings/visibility_settings_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Settings > Visibility settings', :js do diff --git a/spec/features/projects/show/developer_views_empty_project_instructions_spec.rb b/spec/features/projects/show/developer_views_empty_project_instructions_spec.rb index 8ba91fe7fd7..6f176c260a2 100644 --- a/spec/features/projects/show/developer_views_empty_project_instructions_spec.rb +++ b/spec/features/projects/show/developer_views_empty_project_instructions_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Projects > Show > Developer views empty project instructions' do diff --git a/spec/features/projects/show/download_buttons_spec.rb b/spec/features/projects/show/download_buttons_spec.rb index fee5f8001b0..5e7453bcdb7 100644 --- a/spec/features/projects/show/download_buttons_spec.rb +++ b/spec/features/projects/show/download_buttons_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Show > Download buttons' do diff --git a/spec/features/projects/show/no_password_spec.rb b/spec/features/projects/show/no_password_spec.rb index 8259d482fd9..0048b1bf017 100644 --- a/spec/features/projects/show/no_password_spec.rb +++ b/spec/features/projects/show/no_password_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'No Password Alert' do diff --git a/spec/features/projects/show/redirects_spec.rb b/spec/features/projects/show/redirects_spec.rb index 8d41c547d77..1b579ab0121 100644 --- a/spec/features/projects/show/redirects_spec.rb +++ b/spec/features/projects/show/redirects_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Show > Redirects' do diff --git a/spec/features/projects/show/rss_spec.rb b/spec/features/projects/show/rss_spec.rb index 4d9135b9677..4fe1fde5bdd 100644 --- a/spec/features/projects/show/rss_spec.rb +++ b/spec/features/projects/show/rss_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Show > RSS' do diff --git a/spec/features/projects/show/user_interacts_with_stars_spec.rb b/spec/features/projects/show/user_interacts_with_stars_spec.rb index ba28c0e1b8a..e4cd8294f7a 100644 --- a/spec/features/projects/show/user_interacts_with_stars_spec.rb +++ b/spec/features/projects/show/user_interacts_with_stars_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Show > User interacts with project stars' do diff --git a/spec/features/projects/show/user_manages_notifications_spec.rb b/spec/features/projects/show/user_manages_notifications_spec.rb index e9dd1dc0f66..5e9c98428cf 100644 --- a/spec/features/projects/show/user_manages_notifications_spec.rb +++ b/spec/features/projects/show/user_manages_notifications_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Show > User manages notifications', :js do diff --git a/spec/features/projects/show/user_sees_collaboration_links_spec.rb b/spec/features/projects/show/user_sees_collaboration_links_spec.rb index 46586b891e7..bbb3a066ed5 100644 --- a/spec/features/projects/show/user_sees_collaboration_links_spec.rb +++ b/spec/features/projects/show/user_sees_collaboration_links_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Show > Collaboration links' do diff --git a/spec/features/projects/show/user_sees_deletion_failure_message_spec.rb b/spec/features/projects/show/user_sees_deletion_failure_message_spec.rb index d9d57298929..bdd0ab688f0 100644 --- a/spec/features/projects/show/user_sees_deletion_failure_message_spec.rb +++ b/spec/features/projects/show/user_sees_deletion_failure_message_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Show > User sees a deletion failure message' do diff --git a/spec/features/projects/show/user_sees_git_instructions_spec.rb b/spec/features/projects/show/user_sees_git_instructions_spec.rb index 0d59ef4a727..dde9490a5e1 100644 --- a/spec/features/projects/show/user_sees_git_instructions_spec.rb +++ b/spec/features/projects/show/user_sees_git_instructions_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Show > User sees Git instructions' do diff --git a/spec/features/projects/show/user_sees_last_commit_ci_status_spec.rb b/spec/features/projects/show/user_sees_last_commit_ci_status_spec.rb index 89ce4b50781..a1cad261875 100644 --- a/spec/features/projects/show/user_sees_last_commit_ci_status_spec.rb +++ b/spec/features/projects/show/user_sees_last_commit_ci_status_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Show > User sees last commit CI status' do diff --git a/spec/features/projects/show/user_sees_readme_spec.rb b/spec/features/projects/show/user_sees_readme_spec.rb index d80606c1c23..98906de4620 100644 --- a/spec/features/projects/show/user_sees_readme_spec.rb +++ b/spec/features/projects/show/user_sees_readme_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Show > User sees README' do diff --git a/spec/features/projects/show/user_sees_setup_shortcut_buttons_spec.rb b/spec/features/projects/show/user_sees_setup_shortcut_buttons_spec.rb index 58bd20d7551..c136d7607fd 100644 --- a/spec/features/projects/show/user_sees_setup_shortcut_buttons_spec.rb +++ b/spec/features/projects/show/user_sees_setup_shortcut_buttons_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Show > User sees setup shortcut buttons' do diff --git a/spec/features/projects/snippets/create_snippet_spec.rb b/spec/features/projects/snippets/create_snippet_spec.rb index 6d8a72dd6a3..430883fdf29 100644 --- a/spec/features/projects/snippets/create_snippet_spec.rb +++ b/spec/features/projects/snippets/create_snippet_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Projects > Snippets > Create Snippet', :js do diff --git a/spec/features/projects/snippets/show_spec.rb b/spec/features/projects/snippets/show_spec.rb index f3dc13fb52f..e448309356d 100644 --- a/spec/features/projects/snippets/show_spec.rb +++ b/spec/features/projects/snippets/show_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Snippets > Project snippet', :js do diff --git a/spec/features/projects/snippets/user_comments_on_snippet_spec.rb b/spec/features/projects/snippets/user_comments_on_snippet_spec.rb index 4e1e2f330ec..239d19d35d1 100644 --- a/spec/features/projects/snippets/user_comments_on_snippet_spec.rb +++ b/spec/features/projects/snippets/user_comments_on_snippet_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Snippets > User comments on a snippet', :js do diff --git a/spec/features/projects/snippets/user_deletes_snippet_spec.rb b/spec/features/projects/snippets/user_deletes_snippet_spec.rb index 2bd8bb9d551..1b56d7bf26d 100644 --- a/spec/features/projects/snippets/user_deletes_snippet_spec.rb +++ b/spec/features/projects/snippets/user_deletes_snippet_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Snippets > User deletes a snippet' do diff --git a/spec/features/projects/snippets/user_updates_snippet_spec.rb b/spec/features/projects/snippets/user_updates_snippet_spec.rb index 33f77d55f89..c7ff4f89fd6 100644 --- a/spec/features/projects/snippets/user_updates_snippet_spec.rb +++ b/spec/features/projects/snippets/user_updates_snippet_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Snippets > User updates a snippet' do diff --git a/spec/features/projects/snippets/user_views_snippets_spec.rb b/spec/features/projects/snippets/user_views_snippets_spec.rb index 1243db9d9f7..59869244b4a 100644 --- a/spec/features/projects/snippets/user_views_snippets_spec.rb +++ b/spec/features/projects/snippets/user_views_snippets_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Snippets > User views snippets' do diff --git a/spec/features/projects/sub_group_issuables_spec.rb b/spec/features/projects/sub_group_issuables_spec.rb index 50e7e934cf6..d6faec2078d 100644 --- a/spec/features/projects/sub_group_issuables_spec.rb +++ b/spec/features/projects/sub_group_issuables_spec.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + require 'spec_helper' -describe 'Subgroup Issuables', :js, :nested_groups do +describe 'Subgroup Issuables', :js do let!(:group) { create(:group, name: 'group') } let!(:subgroup) { create(:group, parent: group, name: 'subgroup') } let!(:project) { create(:project, namespace: subgroup, name: 'project') } diff --git a/spec/features/projects/tags/download_buttons_spec.rb b/spec/features/projects/tags/download_buttons_spec.rb index 4c8ec53836a..76b2704ae49 100644 --- a/spec/features/projects/tags/download_buttons_spec.rb +++ b/spec/features/projects/tags/download_buttons_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Download buttons in tags page' do diff --git a/spec/features/projects/tree/create_directory_spec.rb b/spec/features/projects/tree/create_directory_spec.rb index 8585e24bc35..7ac5da86702 100644 --- a/spec/features/projects/tree/create_directory_spec.rb +++ b/spec/features/projects/tree/create_directory_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Multi-file editor new directory', :js do diff --git a/spec/features/projects/tree/create_file_spec.rb b/spec/features/projects/tree/create_file_spec.rb index 8623b10562d..00eefe9db42 100644 --- a/spec/features/projects/tree/create_file_spec.rb +++ b/spec/features/projects/tree/create_file_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Multi-file editor new file', :js do diff --git a/spec/features/projects/tree/rss_spec.rb b/spec/features/projects/tree/rss_spec.rb index 022167d9c5f..4300574210f 100644 --- a/spec/features/projects/tree/rss_spec.rb +++ b/spec/features/projects/tree/rss_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Project Tree RSS' do diff --git a/spec/features/projects/tree/tree_show_spec.rb b/spec/features/projects/tree/tree_show_spec.rb index 3ccea2db705..ca616be341d 100644 --- a/spec/features/projects/tree/tree_show_spec.rb +++ b/spec/features/projects/tree/tree_show_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects tree', :js do diff --git a/spec/features/projects/tree/upload_file_spec.rb b/spec/features/projects/tree/upload_file_spec.rb index e5dd2f40fdf..38c29263b1e 100644 --- a/spec/features/projects/tree/upload_file_spec.rb +++ b/spec/features/projects/tree/upload_file_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Multi-file editor upload file', :js do diff --git a/spec/features/projects/user_creates_project_spec.rb b/spec/features/projects/user_creates_project_spec.rb index c0932539131..361367f1a3d 100644 --- a/spec/features/projects/user_creates_project_spec.rb +++ b/spec/features/projects/user_creates_project_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User creates a project', :js do @@ -26,7 +28,7 @@ describe 'User creates a project', :js do expect(page).to have_content(project.url_to_repo) end - context 'in a subgroup they do not own', :nested_groups do + context 'in a subgroup they do not own' do let(:parent) { create(:group) } let!(:subgroup) { create(:group, parent: parent) } diff --git a/spec/features/projects/user_sees_sidebar_spec.rb b/spec/features/projects/user_sees_sidebar_spec.rb index 383e8824b7b..4226cdcc759 100644 --- a/spec/features/projects/user_sees_sidebar_spec.rb +++ b/spec/features/projects/user_sees_sidebar_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > User sees sidebar' do diff --git a/spec/features/projects/user_uses_shortcuts_spec.rb b/spec/features/projects/user_uses_shortcuts_spec.rb index 64f9a4fcd39..ff24730acef 100644 --- a/spec/features/projects/user_uses_shortcuts_spec.rb +++ b/spec/features/projects/user_uses_shortcuts_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User uses shortcuts', :js do diff --git a/spec/features/projects/user_views_empty_project_spec.rb b/spec/features/projects/user_views_empty_project_spec.rb index b7c0834d33a..cb6b63d4dd5 100644 --- a/spec/features/projects/user_views_empty_project_spec.rb +++ b/spec/features/projects/user_views_empty_project_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User views an empty project' do diff --git a/spec/features/projects/view_on_env_spec.rb b/spec/features/projects/view_on_env_spec.rb index 7bfcd46713e..beb32104809 100644 --- a/spec/features/projects/view_on_env_spec.rb +++ b/spec/features/projects/view_on_env_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'View on environment', :js do diff --git a/spec/features/projects/wiki/markdown_preview_spec.rb b/spec/features/projects/wiki/markdown_preview_spec.rb index 49058d1372a..7b511c4d3d5 100644 --- a/spec/features/projects/wiki/markdown_preview_spec.rb +++ b/spec/features/projects/wiki/markdown_preview_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Wiki > User previews markdown changes', :js do diff --git a/spec/features/projects/wiki/shortcuts_spec.rb b/spec/features/projects/wiki/shortcuts_spec.rb index c01be1f14ed..806d2f28bb9 100644 --- a/spec/features/projects/wiki/shortcuts_spec.rb +++ b/spec/features/projects/wiki/shortcuts_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Wiki shortcuts', :js do diff --git a/spec/features/projects/wiki/user_creates_wiki_page_spec.rb b/spec/features/projects/wiki/user_creates_wiki_page_spec.rb index aac095bfa6b..1080976f7ce 100644 --- a/spec/features/projects/wiki/user_creates_wiki_page_spec.rb +++ b/spec/features/projects/wiki/user_creates_wiki_page_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "spec_helper" describe "User creates wiki page" do @@ -132,9 +134,15 @@ describe "User creates wiki page" do fill_in(:wiki_content, with: ascii_content) - page.within(".wiki-form") do - click_button("Create page") - end + # This is the dumbest bug in the world: + # When the #wiki_content textarea is filled in, JS captures the `Enter` keydown event in order to do + # auto-indentation and manually inserts a newline. However, for whatever reason, when you try to click on the + # submit button in Capybara, it will not trigger the `click` event if a \n or \r character has been manually + # added to the textarea. It will, however, trigger ALL OTHER EVENTS, including `mouseover`/down/up, focus, and + # blur. Just not `click`. But only when you manually insert \n or \r - if you manually insert any other sequence + # then `click` is fired normally. And it's only Capybara. Browsers and JSDOM don't have this issue. + # So that's why the next line performs the click via JS. + page.execute_script("document.querySelector('.rspec-create-page-button').click()") page.within ".md" do expect(page).to have_selector(".katex", count: 3).and have_content("2+2 is 4") 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 18ccd31f3d0..38e5e292064 100644 --- a/spec/features/projects/wiki/user_deletes_wiki_page_spec.rb +++ b/spec/features/projects/wiki/user_deletes_wiki_page_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User deletes wiki page', :js do diff --git a/spec/features/projects/wiki/user_git_access_wiki_page_spec.rb b/spec/features/projects/wiki/user_git_access_wiki_page_spec.rb index db97d59e918..ab3d912dd15 100644 --- a/spec/features/projects/wiki/user_git_access_wiki_page_spec.rb +++ b/spec/features/projects/wiki/user_git_access_wiki_page_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Wiki > User views Git access wiki page' do diff --git a/spec/features/projects/wiki/user_updates_wiki_page_spec.rb b/spec/features/projects/wiki/user_updates_wiki_page_spec.rb index dbf8af3e5bb..2aab8fda62d 100644 --- a/spec/features/projects/wiki/user_updates_wiki_page_spec.rb +++ b/spec/features/projects/wiki/user_updates_wiki_page_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User updates wiki page' do diff --git a/spec/features/projects/wiki/user_views_wiki_empty_spec.rb b/spec/features/projects/wiki/user_views_wiki_empty_spec.rb index e94b3a9432b..ab0f9b750d2 100644 --- a/spec/features/projects/wiki/user_views_wiki_empty_spec.rb +++ b/spec/features/projects/wiki/user_views_wiki_empty_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User views empty wiki' do diff --git a/spec/features/projects/wiki/user_views_wiki_in_project_page_spec.rb b/spec/features/projects/wiki/user_views_wiki_in_project_page_spec.rb index fb0ebe22bf7..471e80b27dc 100644 --- a/spec/features/projects/wiki/user_views_wiki_in_project_page_spec.rb +++ b/spec/features/projects/wiki/user_views_wiki_in_project_page_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Projects > Wiki > User views wiki in project page' do diff --git a/spec/features/projects/wiki/user_views_wiki_page_spec.rb b/spec/features/projects/wiki/user_views_wiki_page_spec.rb index 6e28ec0d7b2..05742b63c43 100644 --- a/spec/features/projects/wiki/user_views_wiki_page_spec.rb +++ b/spec/features/projects/wiki/user_views_wiki_page_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User views a wiki page' do @@ -129,7 +131,7 @@ describe 'User views a wiki page' do end context 'when page has invalid content encoding' do - let(:content) { 'whatever'.force_encoding('ISO-8859-1') } + let(:content) { (+'whatever').force_encoding('ISO-8859-1') } before do allow(Gitlab::EncodingHelper).to receive(:encode!).and_return(content) diff --git a/spec/features/projects/wiki/user_views_wiki_pages_spec.rb b/spec/features/projects/wiki/user_views_wiki_pages_spec.rb index 5c16d7783f0..6740df1d4ed 100644 --- a/spec/features/projects/wiki/user_views_wiki_pages_spec.rb +++ b/spec/features/projects/wiki/user_views_wiki_pages_spec.rb @@ -42,7 +42,7 @@ describe 'User views wiki pages' do context 'desc' do before do page.within('.wiki-sort-dropdown') do - page.find('.qa-reverse-sort').click + page.find('.rspec-reverse-sort').click end end @@ -75,7 +75,7 @@ describe 'User views wiki pages' do context 'desc' do before do page.within('.wiki-sort-dropdown') do - page.find('.qa-reverse-sort').click + page.find('.rspec-reverse-sort').click end end diff --git a/spec/features/projects_spec.rb b/spec/features/projects_spec.rb index b5112758475..67ae26d8d1e 100644 --- a/spec/features/projects_spec.rb +++ b/spec/features/projects_spec.rb @@ -314,7 +314,7 @@ describe 'Project' do end end - context 'for subgroups', :js, :nested_groups do + context 'for subgroups', :js do let(:group) { create(:group) } let(:subgroup) { create(:group, parent: group) } let(:project) { create(:project, :repository, group: subgroup) } @@ -387,7 +387,7 @@ describe 'Project' do end it_behaves_like 'dirty submit form', [{ form: '.js-general-settings-form', input: 'input[name="project[name]"]' }, - { form: '.qa-merge-request-settings', input: '#project_printing_merge_request_link_enabled' }] + { form: '.rspec-merge-request-settings', input: '#project_printing_merge_request_link_enabled' }] end def remove_with_confirm(button_text, confirm_with) diff --git a/spec/features/protected_branches_spec.rb b/spec/features/protected_branches_spec.rb index 0dbff5a2701..80937223016 100644 --- a/spec/features/protected_branches_spec.rb +++ b/spec/features/protected_branches_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Protected Branches', :js do diff --git a/spec/features/protected_tags_spec.rb b/spec/features/protected_tags_spec.rb index 652542b1719..3322a747cf5 100644 --- a/spec/features/protected_tags_spec.rb +++ b/spec/features/protected_tags_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Protected Tags', :js do @@ -14,6 +16,7 @@ describe 'Protected Tags', :js do it "allows creating explicit protected tags" do visit project_protected_tags_path(project) set_protected_tag_name('some-tag') + set_allowed_to('create') if Gitlab.ee? click_on "Protect" within(".protected-tags-list") { expect(page).to have_content('some-tag') } @@ -27,6 +30,7 @@ describe 'Protected Tags', :js do visit project_protected_tags_path(project) set_protected_tag_name('some-tag') + set_allowed_to('create') if Gitlab.ee? click_on "Protect" within(".protected-tags-list") { expect(page).to have_content(commit.id[0..7]) } @@ -35,6 +39,7 @@ describe 'Protected Tags', :js do it "displays an error message if the named tag does not exist" do visit project_protected_tags_path(project) set_protected_tag_name('some-tag') + set_allowed_to('create') if Gitlab.ee? click_on "Protect" within(".protected-tags-list") { expect(page).to have_content('tag was removed') } @@ -45,6 +50,7 @@ describe 'Protected Tags', :js do it "allows creating protected tags with a wildcard" do visit project_protected_tags_path(project) set_protected_tag_name('*-stable') + set_allowed_to('create') if Gitlab.ee? click_on "Protect" within(".protected-tags-list") { expect(page).to have_content('*-stable') } @@ -58,6 +64,7 @@ describe 'Protected Tags', :js do visit project_protected_tags_path(project) set_protected_tag_name('*-stable') + set_allowed_to('create') if Gitlab.ee? click_on "Protect" within(".protected-tags-list") do @@ -73,6 +80,7 @@ describe 'Protected Tags', :js do visit project_protected_tags_path(project) set_protected_tag_name('*-stable') + set_allowed_to('create') if Gitlab.ee? click_on "Protect" visit project_protected_tags_path(project) diff --git a/spec/features/raven_js_spec.rb b/spec/features/raven_js_spec.rb index a4dd79b3179..38699f0cc1b 100644 --- a/spec/features/raven_js_spec.rb +++ b/spec/features/raven_js_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'RavenJS' do diff --git a/spec/features/read_only_spec.rb b/spec/features/read_only_spec.rb index 8bfaf558466..3af4b51b9b1 100644 --- a/spec/features/read_only_spec.rb +++ b/spec/features/read_only_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'read-only message' do diff --git a/spec/features/reportable_note/commit_spec.rb b/spec/features/reportable_note/commit_spec.rb index 54ebda9dcab..3502401095e 100644 --- a/spec/features/reportable_note/commit_spec.rb +++ b/spec/features/reportable_note/commit_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Reportable note on commit', :js do diff --git a/spec/features/reportable_note/issue_spec.rb b/spec/features/reportable_note/issue_spec.rb index bce1f7a3780..c45ef77df55 100644 --- a/spec/features/reportable_note/issue_spec.rb +++ b/spec/features/reportable_note/issue_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Reportable note on issue', :js do diff --git a/spec/features/reportable_note/merge_request_spec.rb b/spec/features/reportable_note/merge_request_spec.rb index d00324156c4..2e4d032754b 100644 --- a/spec/features/reportable_note/merge_request_spec.rb +++ b/spec/features/reportable_note/merge_request_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Reportable note on merge request', :js do diff --git a/spec/features/reportable_note/snippets_spec.rb b/spec/features/reportable_note/snippets_spec.rb index 06218d9b286..c2c853cdb05 100644 --- a/spec/features/reportable_note/snippets_spec.rb +++ b/spec/features/reportable_note/snippets_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Reportable note on snippets', :js do diff --git a/spec/features/runners_spec.rb b/spec/features/runners_spec.rb index 6eae0be4b9f..63d21d94b5f 100644 --- a/spec/features/runners_spec.rb +++ b/spec/features/runners_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Runners' do diff --git a/spec/features/search/user_searches_for_code_spec.rb b/spec/features/search/user_searches_for_code_spec.rb index ecec2f3e043..71af75640de 100644 --- a/spec/features/search/user_searches_for_code_spec.rb +++ b/spec/features/search/user_searches_for_code_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User searches for code' do diff --git a/spec/features/search/user_searches_for_comments_spec.rb b/spec/features/search/user_searches_for_comments_spec.rb index c7c469a262c..2ce3fa4735f 100644 --- a/spec/features/search/user_searches_for_comments_spec.rb +++ b/spec/features/search/user_searches_for_comments_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User searches for comments' do diff --git a/spec/features/search/user_searches_for_commits_spec.rb b/spec/features/search/user_searches_for_commits_spec.rb index 998f8521384..81c299752ea 100644 --- a/spec/features/search/user_searches_for_commits_spec.rb +++ b/spec/features/search/user_searches_for_commits_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User searches for commits' do diff --git a/spec/features/search/user_searches_for_issues_spec.rb b/spec/features/search/user_searches_for_issues_spec.rb index 4bff269f89e..f0fcf6df70c 100644 --- a/spec/features/search/user_searches_for_issues_spec.rb +++ b/spec/features/search/user_searches_for_issues_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User searches for issues', :js do diff --git a/spec/features/search/user_searches_for_merge_requests_spec.rb b/spec/features/search/user_searches_for_merge_requests_spec.rb index 75d44e413cb..d005b87cdfe 100644 --- a/spec/features/search/user_searches_for_merge_requests_spec.rb +++ b/spec/features/search/user_searches_for_merge_requests_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User searches for merge requests', :js do diff --git a/spec/features/search/user_searches_for_milestones_spec.rb b/spec/features/search/user_searches_for_milestones_spec.rb index 7d52c4c8bcc..00964ab4f1d 100644 --- a/spec/features/search/user_searches_for_milestones_spec.rb +++ b/spec/features/search/user_searches_for_milestones_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User searches for milestones', :js do diff --git a/spec/features/search/user_searches_for_projects_spec.rb b/spec/features/search/user_searches_for_projects_spec.rb index 242e437e41c..082c1ae8e4a 100644 --- a/spec/features/search/user_searches_for_projects_spec.rb +++ b/spec/features/search/user_searches_for_projects_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User searches for projects' do diff --git a/spec/features/search/user_searches_for_users_spec.rb b/spec/features/search/user_searches_for_users_spec.rb index 3725143291d..2517a843c62 100644 --- a/spec/features/search/user_searches_for_users_spec.rb +++ b/spec/features/search/user_searches_for_users_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User searches for users' do diff --git a/spec/features/search/user_searches_for_wiki_pages_spec.rb b/spec/features/search/user_searches_for_wiki_pages_spec.rb index ee43755262e..0a5abfbf46a 100644 --- a/spec/features/search/user_searches_for_wiki_pages_spec.rb +++ b/spec/features/search/user_searches_for_wiki_pages_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User searches for wiki pages', :js do diff --git a/spec/features/search/user_uses_header_search_field_spec.rb b/spec/features/search/user_uses_header_search_field_spec.rb index 7ddd5c12cdf..29ce5425323 100644 --- a/spec/features/search/user_uses_header_search_field_spec.rb +++ b/spec/features/search/user_uses_header_search_field_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User uses header search field', :js do diff --git a/spec/features/search/user_uses_search_filters_spec.rb b/spec/features/search/user_uses_search_filters_spec.rb index 0725ff178ac..f5cda15b38a 100644 --- a/spec/features/search/user_uses_search_filters_spec.rb +++ b/spec/features/search/user_uses_search_filters_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User uses search filters', :js do diff --git a/spec/features/security/admin_access_spec.rb b/spec/features/security/admin_access_spec.rb index ff679034a36..9b2c873b2aa 100644 --- a/spec/features/security/admin_access_spec.rb +++ b/spec/features/security/admin_access_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe "Admin::Projects" do diff --git a/spec/features/security/dashboard_access_spec.rb b/spec/features/security/dashboard_access_spec.rb index 07cddc92ac4..13fafd88a4c 100644 --- a/spec/features/security/dashboard_access_spec.rb +++ b/spec/features/security/dashboard_access_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe "Dashboard access" do diff --git a/spec/features/security/group/internal_access_spec.rb b/spec/features/security/group/internal_access_spec.rb index 51b32ba6c03..f4f3872aa09 100644 --- a/spec/features/security/group/internal_access_spec.rb +++ b/spec/features/security/group/internal_access_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Internal Group access' do diff --git a/spec/features/security/group/private_access_spec.rb b/spec/features/security/group/private_access_spec.rb index a776169a8e5..9cef8ef777c 100644 --- a/spec/features/security/group/private_access_spec.rb +++ b/spec/features/security/group/private_access_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Private Group access' do diff --git a/spec/features/security/group/public_access_spec.rb b/spec/features/security/group/public_access_spec.rb index 3a53c3c2bc7..bbe74f0dab0 100644 --- a/spec/features/security/group/public_access_spec.rb +++ b/spec/features/security/group/public_access_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Public Group access' do diff --git a/spec/features/security/project/internal_access_spec.rb b/spec/features/security/project/internal_access_spec.rb index e23000fa676..42c747c674f 100644 --- a/spec/features/security/project/internal_access_spec.rb +++ b/spec/features/security/project/internal_access_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe "Internal Project Access" do diff --git a/spec/features/security/project/private_access_spec.rb b/spec/features/security/project/private_access_spec.rb index f380bc122a7..a86d240b7d6 100644 --- a/spec/features/security/project/private_access_spec.rb +++ b/spec/features/security/project/private_access_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe "Private Project Access" do @@ -126,7 +128,7 @@ describe "Private Project Access" do describe "GET /:project_path/blob" do let(:commit) { project.repository.commit } - subject { project_blob_path(project, File.join(commit.id, '.gitignore'))} + subject { project_blob_path(project, File.join(commit.id, '.gitignore')) } it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } diff --git a/spec/features/security/project/public_access_spec.rb b/spec/features/security/project/public_access_spec.rb index 57d56371719..8d7f8c84358 100644 --- a/spec/features/security/project/public_access_spec.rb +++ b/spec/features/security/project/public_access_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe "Public Project Access" do diff --git a/spec/features/security/project/snippet/internal_access_spec.rb b/spec/features/security/project/snippet/internal_access_spec.rb index 0c58fdf2f12..4b6c7d2c8fb 100644 --- a/spec/features/security/project/snippet/internal_access_spec.rb +++ b/spec/features/security/project/snippet/internal_access_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe "Internal Project Snippets Access" do diff --git a/spec/features/security/project/snippet/private_access_spec.rb b/spec/features/security/project/snippet/private_access_spec.rb index 420f1938763..3135d25cc10 100644 --- a/spec/features/security/project/snippet/private_access_spec.rb +++ b/spec/features/security/project/snippet/private_access_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe "Private Project Snippets Access" do diff --git a/spec/features/security/project/snippet/public_access_spec.rb b/spec/features/security/project/snippet/public_access_spec.rb index 6c75902c6e9..81689a7bcb5 100644 --- a/spec/features/security/project/snippet/public_access_spec.rb +++ b/spec/features/security/project/snippet/public_access_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe "Public Project Snippets Access" do diff --git a/spec/features/snippets/embedded_snippet_spec.rb b/spec/features/snippets/embedded_snippet_spec.rb index ab661f6fc69..d6275b5a265 100644 --- a/spec/features/snippets/embedded_snippet_spec.rb +++ b/spec/features/snippets/embedded_snippet_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Embedded Snippets' do diff --git a/spec/features/snippets/explore_spec.rb b/spec/features/snippets/explore_spec.rb index c08f25875f8..b48a5691e96 100644 --- a/spec/features/snippets/explore_spec.rb +++ b/spec/features/snippets/explore_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Explore Snippets' do diff --git a/spec/features/snippets/internal_snippet_spec.rb b/spec/features/snippets/internal_snippet_spec.rb index f6215b481dc..8454a347382 100644 --- a/spec/features/snippets/internal_snippet_spec.rb +++ b/spec/features/snippets/internal_snippet_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Internal Snippets', :js do diff --git a/spec/features/snippets/notes_on_personal_snippets_spec.rb b/spec/features/snippets/notes_on_personal_snippets_spec.rb index 78e0a43ce6d..2bd01be25e9 100644 --- a/spec/features/snippets/notes_on_personal_snippets_spec.rb +++ b/spec/features/snippets/notes_on_personal_snippets_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Comments on personal snippets', :js do diff --git a/spec/features/snippets/public_snippets_spec.rb b/spec/features/snippets/public_snippets_spec.rb index 71c72b98fad..e32a9292e22 100644 --- a/spec/features/snippets/public_snippets_spec.rb +++ b/spec/features/snippets/public_snippets_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Public Snippets', :js do diff --git a/spec/features/snippets/search_snippets_spec.rb b/spec/features/snippets/search_snippets_spec.rb index c137b0bcd96..4a8c5f9b1fe 100644 --- a/spec/features/snippets/search_snippets_spec.rb +++ b/spec/features/snippets/search_snippets_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Search Snippets' do diff --git a/spec/features/snippets/show_spec.rb b/spec/features/snippets/show_spec.rb index 74fdfcf492e..edf7d37fd6d 100644 --- a/spec/features/snippets/show_spec.rb +++ b/spec/features/snippets/show_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Snippet', :js do diff --git a/spec/features/snippets/user_creates_snippet_spec.rb b/spec/features/snippets/user_creates_snippet_spec.rb index 93d77d5b5ce..a4a5407d1f7 100644 --- a/spec/features/snippets/user_creates_snippet_spec.rb +++ b/spec/features/snippets/user_creates_snippet_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'User creates snippet', :js do diff --git a/spec/features/snippets/user_deletes_snippet_spec.rb b/spec/features/snippets/user_deletes_snippet_spec.rb index 7bdccacb0fa..9773aca849a 100644 --- a/spec/features/snippets/user_deletes_snippet_spec.rb +++ b/spec/features/snippets/user_deletes_snippet_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'User deletes snippet' do diff --git a/spec/features/snippets/user_edits_snippet_spec.rb b/spec/features/snippets/user_edits_snippet_spec.rb index 77f62990158..92e34a1f510 100644 --- a/spec/features/snippets/user_edits_snippet_spec.rb +++ b/spec/features/snippets/user_edits_snippet_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'User edits snippet', :js do diff --git a/spec/features/snippets/user_sees_breadcrumb_links.rb b/spec/features/snippets/user_sees_breadcrumb_links.rb index 696f2b93390..5b10984ce1d 100644 --- a/spec/features/snippets/user_sees_breadcrumb_links.rb +++ b/spec/features/snippets/user_sees_breadcrumb_links.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'New user snippet breadcrumbs' do diff --git a/spec/features/snippets/user_snippets_spec.rb b/spec/features/snippets/user_snippets_spec.rb index e3065a899cc..4e9215db945 100644 --- a/spec/features/snippets/user_snippets_spec.rb +++ b/spec/features/snippets/user_snippets_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'User Snippets' do diff --git a/spec/features/snippets_spec.rb b/spec/features/snippets_spec.rb index 96c50f6c804..9df6fe7d16b 100644 --- a/spec/features/snippets_spec.rb +++ b/spec/features/snippets_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Snippets' do diff --git a/spec/features/tags/developer_creates_tag_spec.rb b/spec/features/tags/developer_creates_tag_spec.rb index b2ad7ed8f3f..a2d53b04c9d 100644 --- a/spec/features/tags/developer_creates_tag_spec.rb +++ b/spec/features/tags/developer_creates_tag_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Developer creates tag' do diff --git a/spec/features/tags/developer_deletes_tag_spec.rb b/spec/features/tags/developer_deletes_tag_spec.rb index dc4c7a4fb0a..82b416c3a7f 100644 --- a/spec/features/tags/developer_deletes_tag_spec.rb +++ b/spec/features/tags/developer_deletes_tag_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Developer deletes tag' do diff --git a/spec/features/tags/developer_updates_tag_spec.rb b/spec/features/tags/developer_updates_tag_spec.rb index 1e11fc9e5d5..0cdd953b9ae 100644 --- a/spec/features/tags/developer_updates_tag_spec.rb +++ b/spec/features/tags/developer_updates_tag_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Developer updates tag' do diff --git a/spec/features/tags/developer_views_tags_spec.rb b/spec/features/tags/developer_views_tags_spec.rb index 09e644c6b97..b892b2b4d12 100644 --- a/spec/features/tags/developer_views_tags_spec.rb +++ b/spec/features/tags/developer_views_tags_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Developer views tags' do diff --git a/spec/features/task_lists_spec.rb b/spec/features/task_lists_spec.rb index 33d9c10f5e8..acffc4ce580 100644 --- a/spec/features/task_lists_spec.rb +++ b/spec/features/task_lists_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Task Lists' do diff --git a/spec/features/triggers_spec.rb b/spec/features/triggers_spec.rb index 7c44680e9f7..19cd21e4161 100644 --- a/spec/features/triggers_spec.rb +++ b/spec/features/triggers_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Triggers', :js do @@ -81,29 +83,6 @@ describe 'Triggers', :js do end end - describe 'trigger "Take ownership" workflow' do - before do - create(:ci_trigger, owner: user2, project: @project, description: trigger_title) - visit project_settings_ci_cd_path(@project) - end - - it 'button "Take ownership" has correct alert' do - expected_alert = 'By taking ownership you will bind this trigger to your user account. With this the trigger will have access to all your projects as if it was you. Are you sure?' - expect(page.find('a.btn-trigger-take-ownership')['data-confirm']).to eq expected_alert - end - - it 'take trigger ownership' do - # See if "Take ownership" on trigger works post trigger creation - page.accept_confirm do - first(:link, "Take ownership").send_keys(:return) - end - - expect(page.find('.flash-notice')).to have_content 'Trigger was re-assigned.' - expect(page.find('.triggers-list')).to have_content trigger_title - expect(page.find('.triggers-list .trigger-owner')).to have_content user.name - end - end - describe 'trigger "Revoke" workflow' do before do create(:ci_trigger, owner: user2, project: @project, description: trigger_title) diff --git a/spec/features/u2f_spec.rb b/spec/features/u2f_spec.rb index ea02f36d9d0..bb18703f90e 100644 --- a/spec/features/u2f_spec.rb +++ b/spec/features/u2f_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Using U2F (Universal 2nd Factor) Devices for Authentication', :js do diff --git a/spec/features/unsubscribe_links_spec.rb b/spec/features/unsubscribe_links_spec.rb index 392d8e3e1c1..2f8b715289c 100644 --- a/spec/features/unsubscribe_links_spec.rb +++ b/spec/features/unsubscribe_links_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Unsubscribe links' do diff --git a/spec/features/uploads/user_uploads_avatar_to_group_spec.rb b/spec/features/uploads/user_uploads_avatar_to_group_spec.rb index 72b53bae46a..40d864e0002 100644 --- a/spec/features/uploads/user_uploads_avatar_to_group_spec.rb +++ b/spec/features/uploads/user_uploads_avatar_to_group_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'User uploads avatar to group' do diff --git a/spec/features/uploads/user_uploads_avatar_to_profile_spec.rb b/spec/features/uploads/user_uploads_avatar_to_profile_spec.rb index 48f8b8bf77e..4c694365e3b 100644 --- a/spec/features/uploads/user_uploads_avatar_to_profile_spec.rb +++ b/spec/features/uploads/user_uploads_avatar_to_profile_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'User uploads avatar to profile' do diff --git a/spec/features/uploads/user_uploads_file_to_note_spec.rb b/spec/features/uploads/user_uploads_file_to_note_spec.rb index 24a00c86b0a..6bf8e8ea74f 100644 --- a/spec/features/uploads/user_uploads_file_to_note_spec.rb +++ b/spec/features/uploads/user_uploads_file_to_note_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'User uploads file to note' do diff --git a/spec/features/usage_stats_consent_spec.rb b/spec/features/usage_stats_consent_spec.rb index dd8f3179895..14232b1b370 100644 --- a/spec/features/usage_stats_consent_spec.rb +++ b/spec/features/usage_stats_consent_spec.rb @@ -8,7 +8,15 @@ describe 'Usage stats consent' do let(:message) { 'To help improve GitLab, we would like to periodically collect usage information.' } before do - allow(user).to receive(:has_current_license?).and_return false + if Gitlab.ee? + allow_any_instance_of(EE::User) + .to receive(:has_current_license?) + .and_return(false) + else + allow(user) + .to receive(:has_current_license?) + .and_return(false) + end gitlab_sign_in(user) end diff --git a/spec/features/user_can_display_performance_bar_spec.rb b/spec/features/user_can_display_performance_bar_spec.rb index e069c2fddd1..b2036108d42 100644 --- a/spec/features/user_can_display_performance_bar_spec.rb +++ b/spec/features/user_can_display_performance_bar_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'User can display performance bar', :js do diff --git a/spec/features/user_sees_revert_modal_spec.rb b/spec/features/user_sees_revert_modal_spec.rb index d2cdade88d1..35828b5f086 100644 --- a/spec/features/user_sees_revert_modal_spec.rb +++ b/spec/features/user_sees_revert_modal_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe 'Merge request > User sees revert modal', :js do diff --git a/spec/features/user_sorts_things_spec.rb b/spec/features/user_sorts_things_spec.rb index 0295f588326..41f8f3761e8 100644 --- a/spec/features/user_sorts_things_spec.rb +++ b/spec/features/user_sorts_things_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "spec_helper" # The main goal of this spec is not to check whether the sorting UI works, but diff --git a/spec/features/users/active_sessions_spec.rb b/spec/features/users/active_sessions_spec.rb index 25349b5d036..c717e89eafb 100644 --- a/spec/features/users/active_sessions_spec.rb +++ b/spec/features/users/active_sessions_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Active user sessions', :clean_gitlab_redis_shared_state do diff --git a/spec/features/users/add_email_to_existing_account.rb b/spec/features/users/add_email_to_existing_account.rb index 4355f769429..42e352399a8 100644 --- a/spec/features/users/add_email_to_existing_account.rb +++ b/spec/features/users/add_email_to_existing_account.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'AdditionalEmailToExistingAccount' do diff --git a/spec/features/users/login_spec.rb b/spec/features/users/login_spec.rb index efba303033b..dac8c8e7a29 100644 --- a/spec/features/users/login_spec.rb +++ b/spec/features/users/login_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Login' do @@ -132,7 +134,6 @@ describe 'Login' do it 'does not show a "You are already signed in." error message' do expect(authentication_metrics) .to increment(:user_authenticated_counter) - .and increment(:user_session_override_counter) .and increment(:user_two_factor_authenticated_counter) enter_code(user.current_otp) @@ -144,7 +145,6 @@ describe 'Login' do it 'allows login with valid code' do expect(authentication_metrics) .to increment(:user_authenticated_counter) - .and increment(:user_session_override_counter) .and increment(:user_two_factor_authenticated_counter) enter_code(user.current_otp) @@ -170,7 +170,6 @@ describe 'Login' do it 'allows login with invalid code, then valid code' do expect(authentication_metrics) .to increment(:user_authenticated_counter) - .and increment(:user_session_override_counter) .and increment(:user_two_factor_authenticated_counter) enter_code('foo') @@ -179,6 +178,15 @@ describe 'Login' do enter_code(user.current_otp) expect(current_path).to eq root_path end + + it 'triggers ActiveSession.cleanup for the user' do + expect(authentication_metrics) + .to increment(:user_authenticated_counter) + .and increment(:user_two_factor_authenticated_counter) + expect(ActiveSession).to receive(:cleanup).with(user).once.and_call_original + + enter_code(user.current_otp) + end end context 'using backup code' do @@ -195,7 +203,6 @@ describe 'Login' do it 'allows login' do expect(authentication_metrics) .to increment(:user_authenticated_counter) - .and increment(:user_session_override_counter) .and increment(:user_two_factor_authenticated_counter) enter_code(codes.sample) @@ -206,7 +213,6 @@ describe 'Login' do it 'invalidates the used code' do expect(authentication_metrics) .to increment(:user_authenticated_counter) - .and increment(:user_session_override_counter) .and increment(:user_two_factor_authenticated_counter) expect { enter_code(codes.sample) } @@ -216,7 +222,6 @@ describe 'Login' do it 'invalidates backup codes twice in a row' do expect(authentication_metrics) .to increment(:user_authenticated_counter).twice - .and increment(:user_session_override_counter).twice .and increment(:user_two_factor_authenticated_counter).twice .and increment(:user_session_destroyed_counter) @@ -230,6 +235,15 @@ describe 'Login' do expect { enter_code(codes.sample) } .to change { user.reload.otp_backup_codes.size }.by(-1) end + + it 'triggers ActiveSession.cleanup for the user' do + expect(authentication_metrics) + .to increment(:user_authenticated_counter) + .and increment(:user_two_factor_authenticated_counter) + expect(ActiveSession).to receive(:cleanup).with(user).once.and_call_original + + enter_code(codes.sample) + end end context 'with invalid code' do @@ -274,7 +288,7 @@ describe 'Login' do expect(authentication_metrics) .to increment(:user_authenticated_counter) - .and increment(:user_session_override_counter) + expect(ActiveSession).to receive(:cleanup).with(user).once.and_call_original sign_in_using_saml! @@ -287,8 +301,8 @@ describe 'Login' do it 'shows 2FA prompt after OAuth login' do expect(authentication_metrics) .to increment(:user_authenticated_counter) - .and increment(:user_session_override_counter) .and increment(:user_two_factor_authenticated_counter) + expect(ActiveSession).to receive(:cleanup).with(user).once.and_call_original sign_in_using_saml! @@ -329,6 +343,14 @@ describe 'Login' do expect(page).not_to have_content(I18n.t('devise.failure.already_authenticated')) end + + it 'triggers ActiveSession.cleanup for the user' do + expect(authentication_metrics) + .to increment(:user_authenticated_counter) + expect(ActiveSession).to receive(:cleanup).with(user).once.and_call_original + + gitlab_sign_in(user) + end end context 'with invalid username and password' do @@ -649,7 +671,6 @@ describe 'Login' do it 'asks the user to accept the terms' do expect(authentication_metrics) .to increment(:user_authenticated_counter) - .and increment(:user_session_override_counter) .and increment(:user_two_factor_authenticated_counter) visit new_user_session_path @@ -708,7 +729,6 @@ describe 'Login' do it 'asks the user to accept the terms before setting an email' do expect(authentication_metrics) .to increment(:user_authenticated_counter) - .and increment(:user_session_override_counter) gitlab_sign_in_via('saml', user, 'my-uid') diff --git a/spec/features/users/logout_spec.rb b/spec/features/users/logout_spec.rb index 635729efa53..64202776b9b 100644 --- a/spec/features/users/logout_spec.rb +++ b/spec/features/users/logout_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Logout/Sign out', :js do diff --git a/spec/features/users/overview_spec.rb b/spec/features/users/overview_spec.rb index bfa85696e19..b3531d040e4 100644 --- a/spec/features/users/overview_spec.rb +++ b/spec/features/users/overview_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Overview tab on a user profile', :js do diff --git a/spec/features/users/rss_spec.rb b/spec/features/users/rss_spec.rb index 9af4447056e..ecdbf032623 100644 --- a/spec/features/users/rss_spec.rb +++ b/spec/features/users/rss_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User RSS' do diff --git a/spec/features/users/show_spec.rb b/spec/features/users/show_spec.rb index 351750c0179..932c1d8d4bd 100644 --- a/spec/features/users/show_spec.rb +++ b/spec/features/users/show_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'User page' do diff --git a/spec/features/users/signup_spec.rb b/spec/features/users/signup_spec.rb index 50befa7028d..f5897bffaf0 100644 --- a/spec/features/users/signup_spec.rb +++ b/spec/features/users/signup_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Signup' do diff --git a/spec/features/users/snippets_spec.rb b/spec/features/users/snippets_spec.rb index 8c697e33436..8b6bf54b642 100644 --- a/spec/features/users/snippets_spec.rb +++ b/spec/features/users/snippets_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Snippets tab on a user profile', :js do diff --git a/spec/features/users/terms_spec.rb b/spec/features/users/terms_spec.rb index a770309e6b0..d44e3622a56 100644 --- a/spec/features/users/terms_spec.rb +++ b/spec/features/users/terms_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Users > Terms' do diff --git a/spec/features/users/user_browses_projects_on_user_page_spec.rb b/spec/features/users/user_browses_projects_on_user_page_spec.rb index 6a9b281fb4c..9a1ee7715d6 100644 --- a/spec/features/users/user_browses_projects_on_user_page_spec.rb +++ b/spec/features/users/user_browses_projects_on_user_page_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'Users > User browses projects on user page', :js do @@ -53,6 +55,19 @@ describe 'Users > User browses projects on user page', :js do expect(page).to have_content(project2.name) end + it 'does not have incorrectly interpolated message', :js do + project = create(:project, namespace: user.namespace, updated_at: 2.minutes.since) + + sign_in(user) + visit user_path(user) + click_nav_link('Personal projects') + + wait_for_requests + + expect(page).to have_content(project.name) + expect(page).not_to have_content("_('Updated')") + end + context 'when not signed in' do it 'renders user public project' do visit user_path(user) diff --git a/spec/finders/autocomplete/users_finder_spec.rb b/spec/finders/autocomplete/users_finder_spec.rb index bcde115b1a6..f3b54ca0461 100644 --- a/spec/finders/autocomplete/users_finder_spec.rb +++ b/spec/finders/autocomplete/users_finder_spec.rb @@ -50,7 +50,7 @@ describe Autocomplete::UsersFinder do it { is_expected.to match_array([user1]) } end - context 'when passed a subgroup', :nested_groups do + context 'when passed a subgroup' do let(:grandparent) { create(:group, :public) } let(:parent) { create(:group, :public, parent: grandparent) } let(:child) { create(:group, :public, parent: parent) } diff --git a/spec/finders/cluster_ancestors_finder_spec.rb b/spec/finders/cluster_ancestors_finder_spec.rb index 750042b6b54..4aedb41d446 100644 --- a/spec/finders/cluster_ancestors_finder_spec.rb +++ b/spec/finders/cluster_ancestors_finder_spec.rb @@ -32,7 +32,7 @@ describe ClusterAncestorsFinder, '#execute' do is_expected.to eq([project_cluster, group_cluster, instance_cluster]) end - context 'nested groups', :nested_groups do + context 'nested groups' do let(:group) { create(:group, parent: parent_group) } let(:parent_group) { create(:group) } @@ -65,7 +65,7 @@ describe ClusterAncestorsFinder, '#execute' do is_expected.to eq([group_cluster, instance_cluster]) end - context 'nested groups', :nested_groups do + context 'nested groups' do let(:group) { create(:group, parent: parent_group) } let(:parent_group) { create(:group) } diff --git a/spec/finders/group_descendants_finder_spec.rb b/spec/finders/group_descendants_finder_spec.rb index c28fd7cad11..5fb6739d6e2 100644 --- a/spec/finders/group_descendants_finder_spec.rb +++ b/spec/finders/group_descendants_finder_spec.rb @@ -19,7 +19,7 @@ describe GroupDescendantsFinder do expect(finder.has_children?).to be_truthy end - context 'when there are subgroups', :nested_groups do + context 'when there are subgroups' do it 'is true when there are projects' do create(:group, parent: group) @@ -99,7 +99,7 @@ describe GroupDescendantsFinder do ) end - context 'with nested groups', :nested_groups do + context 'with nested groups' do let!(:subgroup1) { create(:group, parent: group, name: 'a', path: 'sub-a') } let!(:subgroup2) { create(:group, parent: group, name: 'z', path: 'sub-z') } @@ -126,7 +126,7 @@ describe GroupDescendantsFinder do end end - context 'with nested groups', :nested_groups do + context 'with nested groups' do let!(:project) { create(:project, namespace: group) } let!(:subgroup) { create(:group, :private, parent: group) } diff --git a/spec/finders/group_members_finder_spec.rb b/spec/finders/group_members_finder_spec.rb index 8975ea0f063..49b0e14241e 100644 --- a/spec/finders/group_members_finder_spec.rb +++ b/spec/finders/group_members_finder_spec.rb @@ -18,7 +18,7 @@ describe GroupMembersFinder, '#execute' do expect(result.to_a).to match_array([member3, member2, member1]) end - it 'returns members for nested group', :nested_groups do + it 'returns members for nested group' do group.add_developer(user2) nested_group.request_access(user4) member1 = group.add_maintainer(user1) @@ -30,7 +30,7 @@ describe GroupMembersFinder, '#execute' do expect(result.to_a).to match_array([member1, member3, member4]) end - it 'returns members for descendant groups if requested', :nested_groups do + it 'returns members for descendant groups if requested' do member1 = group.add_maintainer(user2) member2 = group.add_maintainer(user1) nested_group.add_maintainer(user2) diff --git a/spec/finders/group_projects_finder_spec.rb b/spec/finders/group_projects_finder_spec.rb index f8fcc2d0e40..f4bd8a3f6ba 100644 --- a/spec/finders/group_projects_finder_spec.rb +++ b/spec/finders/group_projects_finder_spec.rb @@ -19,7 +19,7 @@ describe GroupProjectsFinder do context "only owned" do let(:options) { { only_owned: true } } - context 'with subgroups projects', :nested_groups do + context 'with subgroups projects' do before do options[:include_subgroups] = true end @@ -33,7 +33,7 @@ describe GroupProjectsFinder do end context "all" do - context 'with subgroups projects', :nested_groups do + context 'with subgroups projects' do before do options[:include_subgroups] = true end @@ -78,7 +78,7 @@ describe GroupProjectsFinder do subgroup_private_project.add_maintainer(current_user) end - context 'with subgroups projects', :nested_groups do + context 'with subgroups projects' do before do options[:include_subgroups] = true end @@ -96,7 +96,7 @@ describe GroupProjectsFinder do current_user.update(external: true) end - context 'with subgroups projects', :nested_groups do + context 'with subgroups projects' do before do options[:include_subgroups] = true end @@ -111,7 +111,7 @@ describe GroupProjectsFinder do end context "all" do - context 'with subgroups projects', :nested_groups do + context 'with subgroups projects' do before do options[:include_subgroups] = true end @@ -153,7 +153,7 @@ describe GroupProjectsFinder do context "only owned" do let(:options) { { only_owned: true } } - context 'with subgroups projects', :nested_groups do + context 'with subgroups projects' do before do options[:include_subgroups] = true end diff --git a/spec/finders/groups_finder_spec.rb b/spec/finders/groups_finder_spec.rb index 367ca43bdfe..c8875d1f92d 100644 --- a/spec/finders/groups_finder_spec.rb +++ b/spec/finders/groups_finder_spec.rb @@ -65,7 +65,7 @@ describe GroupsFinder do end end - context 'subgroups', :nested_groups do + context 'subgroups' do let(:user) { create(:user) } let!(:parent_group) { create(:group, :public) } let!(:public_subgroup) { create(:group, :public, parent: parent_group) } diff --git a/spec/finders/issues_finder_spec.rb b/spec/finders/issues_finder_spec.rb index bf38d083ca6..879ff01f294 100644 --- a/spec/finders/issues_finder_spec.rb +++ b/spec/finders/issues_finder_spec.rb @@ -51,7 +51,7 @@ describe IssuesFinder do end end - context 'when include_subgroup param is true', :nested_groups do + context 'when include_subgroup param is true' do before do params[:include_subgroups] = true end @@ -690,7 +690,6 @@ describe IssuesFinder do let(:finder) { described_class.new(nil, params) } before do - allow(Gitlab::Database).to receive(:postgresql?).and_return(true) stub_feature_flags(attempt_group_search_optimizations: true) end @@ -702,18 +701,6 @@ describe IssuesFinder do end end - context 'when the database is not Postgres' do - let(:params) { { search: 'foo', attempt_group_search_optimizations: true } } - - before do - allow(Gitlab::Database).to receive(:postgresql?).and_return(false) - end - - it 'returns false' do - expect(finder.use_cte_for_search?).to be_falsey - end - end - context 'when the force_cte param is falsey' do let(:params) { { search: 'foo' } } diff --git a/spec/finders/labels_finder_spec.rb b/spec/finders/labels_finder_spec.rb index 98b4933fef6..ba41ded112a 100644 --- a/spec/finders/labels_finder_spec.rb +++ b/spec/finders/labels_finder_spec.rb @@ -89,7 +89,7 @@ describe LabelsFinder do end end - context 'when including labels from group ancestors', :nested_groups do + context 'when including labels from group ancestors' do it 'returns labels from group and its ancestors' do private_group_1.add_developer(user) private_subgroup_1.add_developer(user) @@ -108,7 +108,7 @@ describe LabelsFinder do end end - context 'when including labels from group descendants', :nested_groups do + context 'when including labels from group descendants' do it 'returns labels from group and its descendants' do private_group_1.add_developer(user) private_subgroup_1.add_developer(user) @@ -128,7 +128,7 @@ describe LabelsFinder do end end - context 'filtering by project_id', :nested_groups do + context 'filtering by project_id' do context 'when include_ancestor_groups is true' do let!(:sub_project) { create(:project, namespace: private_subgroup_1 ) } let!(:project_label) { create(:label, project: sub_project, title: 'Label 5') } diff --git a/spec/finders/members_finder_spec.rb b/spec/finders/members_finder_spec.rb index 83348457caa..4203f58fe81 100644 --- a/spec/finders/members_finder_spec.rb +++ b/spec/finders/members_finder_spec.rb @@ -9,7 +9,7 @@ describe MembersFinder, '#execute' do set(:user3) { create(:user) } set(:user4) { create(:user) } - it 'returns members for project and parent groups', :nested_groups do + it 'returns members for project and parent groups' do nested_group.request_access(user1) member1 = group.add_maintainer(user2) member2 = nested_group.add_maintainer(user3) @@ -20,7 +20,7 @@ describe MembersFinder, '#execute' do expect(result.to_a).to match_array([member1, member2, member3]) end - it 'includes nested group members if asked', :nested_groups do + it 'includes nested group members if asked' do project = create(:project, namespace: group) nested_group.request_access(user1) member1 = group.add_maintainer(user2) @@ -32,7 +32,7 @@ describe MembersFinder, '#execute' do expect(result.to_a).to match_array([member1, member2, member3]) end - context 'when include_invited_groups_members == true', :nested_groups do + context 'when include_invited_groups_members == true' do subject { described_class.new(project, user2).execute(include_invited_groups_members: true) } set(:linked_group) { create(:group, :public, :access_requestable) } @@ -40,7 +40,7 @@ describe MembersFinder, '#execute' do set(:linked_group_member) { linked_group.add_developer(user1) } set(:nested_linked_group_member) { nested_linked_group.add_developer(user2) } - it 'includes all the invited_groups members including members inherited from ancestor groups', :nested_groups do + it 'includes all the invited_groups members including members inherited from ancestor groups' do create(:project_group_link, project: project, group: nested_linked_group) expect(subject).to contain_exactly(linked_group_member, nested_linked_group_member) diff --git a/spec/finders/merge_requests_finder_spec.rb b/spec/finders/merge_requests_finder_spec.rb index da5e9dab058..78224f0b9da 100644 --- a/spec/finders/merge_requests_finder_spec.rb +++ b/spec/finders/merge_requests_finder_spec.rb @@ -42,7 +42,7 @@ describe MergeRequestsFinder do expect(merge_requests).to contain_exactly(merge_request1, merge_request2) end - it 'filters by group including subgroups', :nested_groups do + it 'filters by group including subgroups' do params = { group_id: group.id, include_subgroups: true } merge_requests = described_class.new(user, params).execute diff --git a/spec/finders/todos_finder_spec.rb b/spec/finders/todos_finder_spec.rb index 22318a9946a..f7b35e76925 100644 --- a/spec/finders/todos_finder_spec.rb +++ b/spec/finders/todos_finder_spec.rb @@ -36,7 +36,7 @@ describe TodosFinder do expect(todos).to match_array([todo1]) end - context 'with subgroups', :nested_groups do + context 'with subgroups' do let(:subgroup) { create(:group, parent: group) } let!(:todo3) { create(:todo, user: user, group: subgroup, target: issue) } diff --git a/spec/fixtures/lib/gitlab/metrics/dashboard/schemas/dashboard.json b/spec/fixtures/lib/gitlab/metrics/dashboard/schemas/dashboard.json index 1ee1205e29a..5d779a323c2 100644 --- a/spec/fixtures/lib/gitlab/metrics/dashboard/schemas/dashboard.json +++ b/spec/fixtures/lib/gitlab/metrics/dashboard/schemas/dashboard.json @@ -1,6 +1,10 @@ { "type": "object", - "required": ["dashboard", "priority", "panel_groups"], + "required": [ + "dashboard", + "priority", + "panel_groups" + ], "properties": { "dashboard": { "type": "string" }, "priority": { "type": "number" }, diff --git a/spec/fixtures/security-reports/dependency_list/gl-dependency-scanning-report.json b/spec/fixtures/security-reports/dependency_list/gl-dependency-scanning-report.json index 1e62d020026..8fb66f6652b 100644 --- a/spec/fixtures/security-reports/dependency_list/gl-dependency-scanning-report.json +++ b/spec/fixtures/security-reports/dependency_list/gl-dependency-scanning-report.json @@ -7,7 +7,7 @@ "message": "Vulnerabilities in libxml2 in nokogiri", "description": " The version of libxml2 packaged with Nokogiri contains several vulnerabilities.\r\n Nokogiri has mitigated these issues by upgrading to libxml 2.9.5.\r\n\r\n It was discovered that a type confusion error existed in libxml2. An\r\n attacker could use this to specially construct XML data that\r\n could cause a denial of service or possibly execute arbitrary\r\n code. (CVE-2017-0663)\r\n\r\n It was discovered that libxml2 did not properly validate parsed entity\r\n references. An attacker could use this to specially construct XML\r\n data that could expose sensitive information. (CVE-2017-7375)\r\n\r\n It was discovered that a buffer overflow existed in libxml2 when\r\n handling HTTP redirects. An attacker could use this to specially\r\n construct XML data that could cause a denial of service or possibly\r\n execute arbitrary code. (CVE-2017-7376)\r\n\r\n Marcel Böhme and Van-Thuan Pham discovered a buffer overflow in\r\n libxml2 when handling elements. An attacker could use this to specially\r\n construct XML data that could cause a denial of service or possibly\r\n execute arbitrary code. (CVE-2017-9047)\r\n\r\n Marcel Böhme and Van-Thuan Pham discovered a buffer overread\r\n in libxml2 when handling elements. An attacker could use this\r\n to specially construct XML data that could cause a denial of\r\n service. (CVE-2017-9048)\r\n\r\n Marcel Böhme and Van-Thuan Pham discovered multiple buffer overreads\r\n in libxml2 when handling parameter-entity references. An attacker\r\n could use these to specially construct XML data that could cause a\r\n denial of service. (CVE-2017-9049, CVE-2017-9050)", "cve": "rails/Gemfile.lock:nokogiri:gemnasium:06565b64-486d-4326-b906-890d9915804d", - "severity": "Unknown", + "severity": "High", "solution": "Upgrade to latest version.", "scanner": { "id": "gemnasium", @@ -48,7 +48,7 @@ "message": "Infinite recursion in parameter entities in nokogiri", "description": "libxml2 incorrectly handles certain parameter entities. An attacker can leverage this with specially constructed XML data to cause libxml2 to consume resources, leading to a denial of service.", "cve": "rails/Gemfile.lock:nokogiri:gemnasium:6a0d56f6-2441-492a-9b14-edb95ac31919", - "severity": "Unknown", + "severity": "High", "solution": "Upgrade to latest version.", "scanner": { "id": "gemnasium", diff --git a/spec/frontend/helpers/indent_helper_spec.js b/spec/frontend/helpers/indent_helper_spec.js new file mode 100644 index 00000000000..fca12f0d1ef --- /dev/null +++ b/spec/frontend/helpers/indent_helper_spec.js @@ -0,0 +1,371 @@ +import IndentHelper from '~/helpers/indent_helper'; + +function createMockTextarea() { + const el = document.createElement('textarea'); + el.setCursor = pos => el.setSelectionRange(pos, pos); + el.setCursorToEnd = () => el.setCursor(el.value.length); + el.selection = () => [el.selectionStart, el.selectionEnd]; + el.cursor = () => { + const [start, end] = el.selection(); + return start === end ? start : undefined; + }; + return el; +} + +describe('indent_helper', () => { + let element; + let ih; + + beforeEach(() => { + element = createMockTextarea(); + ih = new IndentHelper(element); + }); + + describe('indents', () => { + describe('a single line', () => { + it('when on an empty line; and cursor follows', () => { + element.value = ''; + ih.indent(); + expect(element.value).toBe(' '); + expect(element.cursor()).toBe(4); + ih.indent(); + expect(element.value).toBe(' '); + expect(element.cursor()).toBe(8); + }); + + it('when at the start of a line; and cursor stays at start', () => { + element.value = 'foobar'; + element.setCursor(0); + ih.indent(); + expect(element.value).toBe(' foobar'); + expect(element.cursor()).toBe(4); + }); + + it('when the cursor is in the middle; and cursor follows', () => { + element.value = 'foobar'; + element.setCursor(3); + ih.indent(); + expect(element.value).toBe(' foobar'); + expect(element.cursor()).toBe(7); + }); + }); + + describe('several lines', () => { + it('when everything is selected; and everything remains selected', () => { + element.value = 'foo\nbar\nbaz'; + element.setSelectionRange(0, 11); + ih.indent(); + expect(element.value).toBe(' foo\n bar\n baz'); + expect(element.selection()).toEqual([0, 23]); + }); + + it('when all lines are partially selected; and the selection adapts', () => { + element.value = 'foo\nbar\nbaz'; + element.setSelectionRange(2, 9); + ih.indent(); + expect(element.value).toBe(' foo\n bar\n baz'); + expect(element.selection()).toEqual([6, 21]); + }); + + it('when some lines are entirely selected; and entire lines remain selected', () => { + element.value = 'foo\nbar\nbaz'; + element.setSelectionRange(4, 11); + ih.indent(); + expect(element.value).toBe('foo\n bar\n baz'); + expect(element.selection()).toEqual([4, 19]); + }); + + it('when some lines are partially selected; and the selection adapts', () => { + element.value = 'foo\nbar\nbaz'; + element.setSelectionRange(5, 9); + ih.indent(); + expect(element.value).toBe('foo\n bar\n baz'); + expect(element.selection()).toEqual([5 + 4, 9 + 2 * 4]); + }); + + it('having different indentation when some lines are entirely selected; and entire lines remain selected', () => { + element.value = ' foo\nbar\n baz'; + element.setSelectionRange(8, 19); + ih.indent(); + expect(element.value).toBe(' foo\n bar\n baz'); + expect(element.selection()).toEqual([8, 27]); + }); + + it('having different indentation when some lines are partially selected; and the selection adapts', () => { + element.value = ' foo\nbar\n baz'; + element.setSelectionRange(9, 14); + ih.indent(); + expect(element.value).toBe(' foo\n bar\n baz'); + expect(element.selection()).toEqual([13, 22]); + }); + }); + }); + + describe('unindents', () => { + describe('a single line', () => { + it('but does nothing if there is not indent', () => { + element.value = 'foobar'; + element.setCursor(2); + ih.unindent(); + expect(element.value).toBe('foobar'); + expect(element.cursor()).toBe(2); + }); + + it('but does nothing if there is a partial indent', () => { + element.value = ' foobar'; + element.setCursor(1); + ih.unindent(); + expect(element.value).toBe(' foobar'); + expect(element.cursor()).toBe(1); + }); + + it('when the cursor is in the line text; cursor follows', () => { + element.value = ' foobar'; + element.setCursor(6); + ih.unindent(); + expect(element.value).toBe('foobar'); + expect(element.cursor()).toBe(2); + }); + + it('when the cursor is in the indent; and cursor goes to start', () => { + element.value = ' foobar'; + element.setCursor(2); + ih.unindent(); + expect(element.value).toBe('foobar'); + expect(element.cursor()).toBe(0); + }); + + it('when the cursor is at line start; and cursor stays at start', () => { + element.value = ' foobar'; + element.setCursor(0); + ih.unindent(); + expect(element.value).toBe('foobar'); + expect(element.cursor()).toBe(0); + }); + + it('when a selection includes part of the indent and text', () => { + element.value = ' foobar'; + element.setSelectionRange(2, 8); + ih.unindent(); + expect(element.value).toBe('foobar'); + expect(element.selection()).toEqual([0, 4]); + }); + + it('when a selection includes part of the indent only', () => { + element.value = ' foobar'; + element.setSelectionRange(0, 4); + ih.unindent(); + expect(element.value).toBe('foobar'); + expect(element.cursor()).toBe(0); + + element.value = ' foobar'; + element.setSelectionRange(1, 3); + ih.unindent(); + expect(element.value).toBe('foobar'); + expect(element.cursor()).toBe(0); + }); + }); + + describe('several lines', () => { + it('when everything is selected', () => { + element.value = ' foo\n bar\n baz'; + element.setSelectionRange(0, 27); + ih.unindent(); + expect(element.value).toBe('foo\n bar\nbaz'); + expect(element.selection()).toEqual([0, 15]); + }); + + it('when all lines are partially selected', () => { + element.value = ' foo\n bar\n baz'; + element.setSelectionRange(5, 26); + ih.unindent(); + expect(element.value).toBe('foo\n bar\nbaz'); + expect(element.selection()).toEqual([1, 14]); + }); + + it('when all lines are entirely selected', () => { + element.value = ' foo\n bar\n baz'; + element.setSelectionRange(8, 27); + ih.unindent(); + expect(element.value).toBe(' foo\n bar\nbaz'); + expect(element.selection()).toEqual([8, 19]); + }); + + it('when some lines are entirely selected', () => { + element.value = ' foo\n bar\n baz'; + element.setSelectionRange(8, 27); + ih.unindent(); + expect(element.value).toBe(' foo\n bar\nbaz'); + expect(element.selection()).toEqual([8, 19]); + }); + + it('when some lines are partially selected', () => { + element.value = ' foo\n bar\n baz'; + element.setSelectionRange(17, 26); + ih.unindent(); + expect(element.value).toBe(' foo\n bar\nbaz'); + expect(element.selection()).toEqual([13, 18]); + }); + + it('when some lines are partially selected within their indents', () => { + element.value = ' foo\n bar\n baz'; + element.setSelectionRange(10, 22); + ih.unindent(); + expect(element.value).toBe(' foo\n bar\nbaz'); + expect(element.selection()).toEqual([8, 16]); + }); + }); + }); + + describe('newline', () => { + describe('on a single line', () => { + it('auto-indents the new line', () => { + element.value = 'foo\n bar\n baz\n qux'; + + element.setCursor(3); + ih.newline(); + expect(element.value).toBe('foo\n\n bar\n baz\n qux'); + expect(element.cursor()).toBe(4); + + element.setCursor(9); + ih.newline(); + expect(element.value).toBe('foo\n\n bar\n \n baz\n qux'); + expect(element.cursor()).toBe(11); + + element.setCursor(19); + ih.newline(); + expect(element.value).toBe('foo\n\n bar\n \n baz\n \n qux'); + expect(element.cursor()).toBe(24); + + element.setCursor(36); + ih.newline(); + expect(element.value).toBe('foo\n\n bar\n \n baz\n \n qux\n '); + expect(element.cursor()).toBe(45); + }); + + it('splits a line and auto-indents', () => { + element.value = ' foobar'; + element.setCursor(7); + ih.newline(); + expect(element.value).toBe(' foo\n bar'); + expect(element.cursor()).toBe(12); + }); + + it('replaces selection with an indented newline', () => { + element.value = ' foobarbaz'; + element.setSelectionRange(7, 10); + ih.newline(); + expect(element.value).toBe(' foo\n baz'); + expect(element.cursor()).toBe(12); + }); + }); + + it('on several lines.replaces selection with indented newline', () => { + element.value = ' foo\n bar\n baz'; + element.setSelectionRange(4, 17); + ih.newline(); + expect(element.value).toBe(' fo\n az'); + expect(element.cursor()).toBe(7); + }); + }); + + describe('backspace', () => { + let event; + + // This suite tests only the special indent-removing behaviour of the + // backspace() method, since non-special cases are handled natively as a + // backspace keypress. + + beforeEach(() => { + event = { preventDefault: jest.fn() }; + }); + + describe('on a single line', () => { + it('does nothing special if in the line text', () => { + element.value = ' foobar'; + element.setCursor(7); + ih.backspace(event); + expect(event.preventDefault).not.toHaveBeenCalled(); + }); + + it('does nothing special if after a non-leading indent', () => { + element.value = ' foo bar'; + element.setCursor(11); + ih.backspace(event); + expect(event.preventDefault).not.toHaveBeenCalled(); + }); + + it('deletes one leading indent', () => { + element.value = ' foo'; + element.setCursor(8); + ih.backspace(event); + expect(event.preventDefault).toHaveBeenCalled(); + expect(element.value).toBe(' foo'); + expect(element.cursor()).toBe(4); + }); + + it('does nothing if cursor is inside the leading indent', () => { + element.value = ' foo'; + element.setCursor(4); + ih.backspace(event); + expect(event.preventDefault).not.toHaveBeenCalled(); + }); + + it('does nothing if cursor is at the start of the line', () => { + element.value = ' foo'; + element.setCursor(0); + ih.backspace(event); + expect(event.preventDefault).not.toHaveBeenCalled(); + }); + + it('deletes one partial indent', () => { + element.value = ' foo'; + element.setCursor(6); + ih.backspace(event); + expect(event.preventDefault).toHaveBeenCalled(); + expect(element.value).toBe(' foo'); + expect(element.cursor()).toBe(4); + }); + + it('deletes indents sequentially', () => { + element.value = ' foo'; + element.setCursor(10); + ih.backspace(event); + ih.backspace(event); + ih.backspace(event); + expect(event.preventDefault).toHaveBeenCalled(); + expect(element.value).toBe('foo'); + expect(element.cursor()).toBe(0); + }); + }); + + describe('on several lines', () => { + it('deletes indent only on its own line', () => { + element.value = ' foo\n bar\n baz'; + element.setCursor(16); + ih.backspace(event); + expect(event.preventDefault).toHaveBeenCalled(); + expect(element.value).toBe(' foo\n bar\n baz'); + expect(element.cursor()).toBe(12); + }); + + it('has no special behaviour with any range selection', () => { + const text = ' foo\n bar\n baz'; + for (let start = 0; start < text.length; start += 1) { + for (let end = start + 1; end < text.length; end += 1) { + element.value = text; + element.setSelectionRange(start, end); + ih.backspace(event); + expect(event.preventDefault).not.toHaveBeenCalled(); + + // Ensure that the backspace() method doesn't change state + // In reality, these two statements won't hold because the browser + // will natively process the backspace event. + expect(element.value).toBe(text); + expect(element.selection()).toEqual([start, end]); + } + } + }); + }); + }); +}); diff --git a/spec/frontend/jobs/components/empty_state_spec.js b/spec/frontend/jobs/components/empty_state_spec.js index a2df79bdda0..dfba5a936ee 100644 --- a/spec/frontend/jobs/components/empty_state_spec.js +++ b/spec/frontend/jobs/components/empty_state_spec.js @@ -10,6 +10,8 @@ describe('Empty State', () => { illustrationPath: 'illustrations/pending_job_empty.svg', illustrationSizeClass: 'svg-430', title: 'This job has not started yet', + playable: false, + variablesSettingsUrl: '', }; const content = 'This job is in pending state and is waiting to be picked by a runner'; @@ -90,4 +92,44 @@ describe('Empty State', () => { expect(vm.$el.querySelector('.js-job-empty-state-action')).toBeNull(); }); }); + + describe('without playbale action', () => { + it('does not render manual variables form', () => { + vm = mountComponent(Component, { + ...props, + content, + }); + + expect(vm.$el.querySelector('.js-manual-vars-form')).toBeNull(); + }); + }); + + describe('with playbale action and not scheduled job', () => { + it('renders manual variables form', () => { + vm = mountComponent(Component, { + ...props, + content, + playable: true, + scheduled: false, + action: { + path: 'runner', + button_title: 'Check runner', + method: 'post', + }, + }); + + expect(vm.$el.querySelector('.js-manual-vars-form')).not.toBeNull(); + }); + }); + + describe('with playbale action and scheduled job', () => { + it('does not render manual variables form', () => { + vm = mountComponent(Component, { + ...props, + content, + }); + + expect(vm.$el.querySelector('.js-manual-vars-form')).toBeNull(); + }); + }); }); diff --git a/spec/frontend/lib/utils/color_utils_spec.js b/spec/frontend/lib/utils/color_utils_spec.js new file mode 100644 index 00000000000..433e9d5a85e --- /dev/null +++ b/spec/frontend/lib/utils/color_utils_spec.js @@ -0,0 +1,35 @@ +import { textColorForBackground, hexToRgb } from '~/lib/utils/color_utils'; + +describe('Color utils', () => { + describe('Converting hex code to rgb', () => { + it('convert hex code to rgb', () => { + expect(hexToRgb('#000000')).toEqual([0, 0, 0]); + expect(hexToRgb('#ffffff')).toEqual([255, 255, 255]); + }); + + it('convert short hex code to rgb', () => { + expect(hexToRgb('#000')).toEqual([0, 0, 0]); + expect(hexToRgb('#fff')).toEqual([255, 255, 255]); + }); + + it('handle conversion regardless of the characters case', () => { + expect(hexToRgb('#f0F')).toEqual([255, 0, 255]); + }); + }); + + describe('Getting text color for given background', () => { + // following tests are being ported from `text_color_for_bg` section in labels_helper_spec.rb + it('uses light text on dark backgrounds', () => { + expect(textColorForBackground('#222E2E')).toEqual('#FFFFFF'); + }); + + it('uses dark text on light backgrounds', () => { + expect(textColorForBackground('#EEEEEE')).toEqual('#333333'); + }); + + it('supports RGB triplets', () => { + expect(textColorForBackground('#FFF')).toEqual('#333333'); + expect(textColorForBackground('#000')).toEqual('#FFFFFF'); + }); + }); +}); diff --git a/spec/frontend/lib/utils/common_utils_spec.js b/spec/frontend/lib/utils/common_utils_spec.js new file mode 100644 index 00000000000..e3d3b82d2f3 --- /dev/null +++ b/spec/frontend/lib/utils/common_utils_spec.js @@ -0,0 +1,180 @@ +import * as cu from '~/lib/utils/common_utils'; + +const CMD_ENTITY = '⌘'; + +// Redefine `navigator.platform` because it's unsettable by default in JSDOM. +let platform; +Object.defineProperty(navigator, 'platform', { + configurable: true, + get: () => platform, + set: val => { + platform = val; + }, +}); + +describe('common_utils', () => { + describe('platform leader key helpers', () => { + const CTRL_EVENT = { ctrlKey: true }; + const META_EVENT = { metaKey: true }; + const BOTH_EVENT = { ctrlKey: true, metaKey: true }; + + it('should return "ctrl" if navigator.platform is unset', () => { + expect(cu.getPlatformLeaderKey()).toBe('ctrl'); + expect(cu.getPlatformLeaderKeyHTML()).toBe('Ctrl'); + expect(cu.isPlatformLeaderKey(CTRL_EVENT)).toBe(true); + expect(cu.isPlatformLeaderKey(META_EVENT)).toBe(false); + expect(cu.isPlatformLeaderKey(BOTH_EVENT)).toBe(true); + }); + + it('should return "meta" on MacOS', () => { + navigator.platform = 'MacIntel'; + expect(cu.getPlatformLeaderKey()).toBe('meta'); + expect(cu.getPlatformLeaderKeyHTML()).toBe(CMD_ENTITY); + expect(cu.isPlatformLeaderKey(CTRL_EVENT)).toBe(false); + expect(cu.isPlatformLeaderKey(META_EVENT)).toBe(true); + expect(cu.isPlatformLeaderKey(BOTH_EVENT)).toBe(true); + }); + + it('should return "ctrl" on Linux', () => { + navigator.platform = 'Linux is great'; + expect(cu.getPlatformLeaderKey()).toBe('ctrl'); + expect(cu.getPlatformLeaderKeyHTML()).toBe('Ctrl'); + expect(cu.isPlatformLeaderKey(CTRL_EVENT)).toBe(true); + expect(cu.isPlatformLeaderKey(META_EVENT)).toBe(false); + expect(cu.isPlatformLeaderKey(BOTH_EVENT)).toBe(true); + }); + + it('should return "ctrl" on Windows', () => { + navigator.platform = 'Win32'; + expect(cu.getPlatformLeaderKey()).toBe('ctrl'); + expect(cu.getPlatformLeaderKeyHTML()).toBe('Ctrl'); + expect(cu.isPlatformLeaderKey(CTRL_EVENT)).toBe(true); + expect(cu.isPlatformLeaderKey(META_EVENT)).toBe(false); + expect(cu.isPlatformLeaderKey(BOTH_EVENT)).toBe(true); + }); + }); + + describe('keystroke', () => { + const CODE_BACKSPACE = 8; + const CODE_TAB = 9; + const CODE_ENTER = 13; + const CODE_SPACE = 32; + const CODE_4 = 52; + const CODE_F = 70; + const CODE_Z = 90; + + // Helper function that quickly creates KeyboardEvents + const k = (code, modifiers = '') => ({ + keyCode: code, + which: code, + altKey: modifiers.includes('a'), + ctrlKey: modifiers.includes('c'), + metaKey: modifiers.includes('m'), + shiftKey: modifiers.includes('s'), + }); + + const EV_F = k(CODE_F); + const EV_ALT_F = k(CODE_F, 'a'); + const EV_CONTROL_F = k(CODE_F, 'c'); + const EV_META_F = k(CODE_F, 'm'); + const EV_SHIFT_F = k(CODE_F, 's'); + const EV_CONTROL_SHIFT_F = k(CODE_F, 'cs'); + const EV_ALL_F = k(CODE_F, 'scma'); + const EV_ENTER = k(CODE_ENTER); + const EV_TAB = k(CODE_TAB); + const EV_SPACE = k(CODE_SPACE); + const EV_BACKSPACE = k(CODE_BACKSPACE); + const EV_4 = k(CODE_4); + const EV_$ = k(CODE_4, 's'); + + const { keystroke } = cu; + + it('short-circuits with bad arguments', () => { + expect(keystroke()).toBe(false); + expect(keystroke({})).toBe(false); + }); + + it('handles keystrokes using key codes', () => { + // Test a letter key with modifiers + expect(keystroke(EV_F, CODE_F)).toBe(true); + expect(keystroke(EV_F, CODE_F, '')).toBe(true); + expect(keystroke(EV_ALT_F, CODE_F, 'a')).toBe(true); + expect(keystroke(EV_CONTROL_F, CODE_F, 'c')).toBe(true); + expect(keystroke(EV_META_F, CODE_F, 'm')).toBe(true); + expect(keystroke(EV_SHIFT_F, CODE_F, 's')).toBe(true); + expect(keystroke(EV_CONTROL_SHIFT_F, CODE_F, 'cs')).toBe(true); + expect(keystroke(EV_ALL_F, CODE_F, 'acms')).toBe(true); + + // Test non-letter keys + expect(keystroke(EV_TAB, CODE_TAB)).toBe(true); + expect(keystroke(EV_ENTER, CODE_ENTER)).toBe(true); + expect(keystroke(EV_SPACE, CODE_SPACE)).toBe(true); + expect(keystroke(EV_BACKSPACE, CODE_BACKSPACE)).toBe(true); + + // Test a number/symbol key + expect(keystroke(EV_4, CODE_4)).toBe(true); + expect(keystroke(EV_$, CODE_4, 's')).toBe(true); + + // Test wrong input + expect(keystroke(EV_F, CODE_Z)).toBe(false); + expect(keystroke(EV_SHIFT_F, CODE_F)).toBe(false); + expect(keystroke(EV_SHIFT_F, CODE_F, 'c')).toBe(false); + }); + + it('is case-insensitive', () => { + expect(keystroke(EV_ALL_F, CODE_F, 'ACMS')).toBe(true); + }); + + it('handles bogus inputs', () => { + expect(keystroke(EV_F, 'not a keystroke')).toBe(false); + expect(keystroke(EV_F, null)).toBe(false); + }); + + it('handles exact modifier keys, in any order', () => { + // Test permutations of modifiers + expect(keystroke(EV_ALL_F, CODE_F, 'acms')).toBe(true); + expect(keystroke(EV_ALL_F, CODE_F, 'smca')).toBe(true); + expect(keystroke(EV_ALL_F, CODE_F, 'csma')).toBe(true); + expect(keystroke(EV_CONTROL_SHIFT_F, CODE_F, 'cs')).toBe(true); + expect(keystroke(EV_CONTROL_SHIFT_F, CODE_F, 'sc')).toBe(true); + + // Test wrong modifiers + expect(keystroke(EV_ALL_F, CODE_F, 'smca')).toBe(true); + expect(keystroke(EV_ALL_F, CODE_F)).toBe(false); + expect(keystroke(EV_ALL_F, CODE_F, '')).toBe(false); + expect(keystroke(EV_ALL_F, CODE_F, 'c')).toBe(false); + expect(keystroke(EV_ALL_F, CODE_F, 'ca')).toBe(false); + expect(keystroke(EV_ALL_F, CODE_F, 'ms')).toBe(false); + expect(keystroke(EV_CONTROL_SHIFT_F, CODE_F, 'cs')).toBe(true); + expect(keystroke(EV_CONTROL_SHIFT_F, CODE_F, 'c')).toBe(false); + expect(keystroke(EV_CONTROL_SHIFT_F, CODE_F, 's')).toBe(false); + expect(keystroke(EV_CONTROL_SHIFT_F, CODE_F, 'csa')).toBe(false); + expect(keystroke(EV_CONTROL_SHIFT_F, CODE_F, 'm')).toBe(false); + expect(keystroke(EV_SHIFT_F, CODE_F, 's')).toBe(true); + expect(keystroke(EV_SHIFT_F, CODE_F, 'c')).toBe(false); + expect(keystroke(EV_SHIFT_F, CODE_F, 'csm')).toBe(false); + }); + + it('handles the platform-dependent leader key', () => { + navigator.platform = 'Win32'; + let EV_UNDO = k(CODE_Z, 'c'); + let EV_REDO = k(CODE_Z, 'cs'); + expect(keystroke(EV_UNDO, CODE_Z, 'l')).toBe(true); + expect(keystroke(EV_UNDO, CODE_Z, 'c')).toBe(true); + expect(keystroke(EV_UNDO, CODE_Z, 'm')).toBe(false); + expect(keystroke(EV_REDO, CODE_Z, 'sl')).toBe(true); + expect(keystroke(EV_REDO, CODE_Z, 'sc')).toBe(true); + expect(keystroke(EV_REDO, CODE_Z, 'sm')).toBe(false); + + navigator.platform = 'MacIntel'; + EV_UNDO = k(CODE_Z, 'm'); + EV_REDO = k(CODE_Z, 'ms'); + expect(keystroke(EV_UNDO, CODE_Z, 'l')).toBe(true); + expect(keystroke(EV_UNDO, CODE_Z, 'c')).toBe(false); + expect(keystroke(EV_UNDO, CODE_Z, 'm')).toBe(true); + expect(keystroke(EV_REDO, CODE_Z, 'sl')).toBe(true); + expect(keystroke(EV_REDO, CODE_Z, 'sc')).toBe(false); + expect(keystroke(EV_REDO, CODE_Z, 'sm')).toBe(true); + }); + }); +}); diff --git a/spec/frontend/lib/utils/text_utility_spec.js b/spec/frontend/lib/utils/text_utility_spec.js index dc886d0db3b..b6f1aef9ce4 100644 --- a/spec/frontend/lib/utils/text_utility_spec.js +++ b/spec/frontend/lib/utils/text_utility_spec.js @@ -29,20 +29,6 @@ describe('text_utility', () => { }); }); - describe('pluralize', () => { - it('should pluralize given string', () => { - expect(textUtils.pluralize('test', 2)).toBe('tests'); - }); - - it('should pluralize when count is 0', () => { - expect(textUtils.pluralize('test', 0)).toBe('tests'); - }); - - it('should not pluralize when count is 1', () => { - expect(textUtils.pluralize('test', 1)).toBe('test'); - }); - }); - describe('dasherize', () => { it('should replace underscores with dashes', () => { expect(textUtils.dasherize('foo_bar_foo')).toEqual('foo-bar-foo'); diff --git a/spec/frontend/lib/utils/undo_stack_spec.js b/spec/frontend/lib/utils/undo_stack_spec.js new file mode 100644 index 00000000000..31ad0e77d6f --- /dev/null +++ b/spec/frontend/lib/utils/undo_stack_spec.js @@ -0,0 +1,237 @@ +import UndoStack from '~/lib/utils/undo_stack'; + +import { isEqual } from 'underscore'; + +describe('UndoStack', () => { + let stack; + + beforeEach(() => { + stack = new UndoStack(); + }); + + afterEach(() => { + // Make sure there's not pending saves + const history = Array.from(stack.history); + jest.runAllTimers(); + expect(stack.history).toEqual(history); + }); + + it('is blank on construction', () => { + expect(stack.isEmpty()).toBe(true); + expect(stack.history).toEqual([]); + expect(stack.cursor).toBe(-1); + expect(stack.canUndo()).toBe(false); + expect(stack.canRedo()).toBe(false); + }); + + it('handles simple undo/redo behaviour', () => { + stack.save(10); + stack.save(11); + stack.save(12); + + expect(stack.history).toEqual([10, 11, 12]); + expect(stack.cursor).toBe(2); + expect(stack.current()).toBe(12); + expect(stack.isEmpty()).toBe(false); + expect(stack.canUndo()).toBe(true); + expect(stack.canRedo()).toBe(false); + + stack.undo(); + expect(stack.history).toEqual([10, 11, 12]); + expect(stack.current()).toBe(11); + expect(stack.canUndo()).toBe(true); + expect(stack.canRedo()).toBe(true); + + stack.undo(); + expect(stack.current()).toBe(10); + expect(stack.canUndo()).toBe(false); + expect(stack.canRedo()).toBe(true); + + stack.redo(); + expect(stack.current()).toBe(11); + + stack.redo(); + expect(stack.current()).toBe(12); + expect(stack.isEmpty()).toBe(false); + expect(stack.canUndo()).toBe(true); + expect(stack.canRedo()).toBe(false); + + // Saving should clear the redo stack + stack.undo(); + stack.save(13); + expect(stack.history).toEqual([10, 11, 13]); + expect(stack.current()).toBe(13); + }); + + it('clear() should clear the undo history', () => { + stack.save(0); + stack.save(1); + stack.save(2); + stack.clear(); + expect(stack.history).toEqual([]); + expect(stack.current()).toBeUndefined(); + }); + + it('undo and redo are no-ops if unavailable', () => { + stack.save(10); + expect(stack.canRedo()).toBe(false); + expect(stack.canUndo()).toBe(false); + + stack.save(11); + expect(stack.canRedo()).toBe(false); + expect(stack.canUndo()).toBe(true); + + expect(stack.redo()).toBeUndefined(); + expect(stack.history).toEqual([10, 11]); + expect(stack.current()).toBe(11); + expect(stack.canRedo()).toBe(false); + expect(stack.canUndo()).toBe(true); + + expect(stack.undo()).toBe(10); + expect(stack.undo()).toBeUndefined(); + expect(stack.history).toEqual([10, 11]); + expect(stack.current()).toBe(10); + expect(stack.canRedo()).toBe(true); + expect(stack.canUndo()).toBe(false); + }); + + it('should not save a duplicate state', () => { + stack.save(10); + stack.save(11); + stack.save(11); + stack.save(10); + stack.save(10); + + expect(stack.history).toEqual([10, 11, 10]); + }); + + it('uses the === operator to detect duplicates', () => { + stack.save(10); + stack.save(10); + expect(stack.history).toEqual([10]); + + // eslint-disable-next-line eqeqeq + expect(2 == '2' && '2' == 2).toBe(true); + stack.clear(); + stack.save(2); + stack.save(2); + stack.save('2'); + stack.save('2'); + stack.save(2); + expect(stack.history).toEqual([2, '2', 2]); + + const obj = {}; + stack.clear(); + stack.save(obj); + stack.save(obj); + stack.save({}); + stack.save({}); + expect(stack.history).toEqual([{}, {}, {}]); + }); + + it('should allow custom comparators', () => { + stack.comparator = isEqual; + const obj = {}; + stack.clear(); + stack.save(obj); + stack.save(obj); + stack.save({}); + stack.save({}); + expect(stack.history).toEqual([{}]); + }); + + it('should enforce a max number of undo states', () => { + // Try 2000 saves. Only the last 1000 should be preserved. + const sequence = Array(2000) + .fill(0) + .map((el, i) => i); + sequence.forEach(stack.save.bind(stack)); + expect(stack.history.length).toBe(1000); + expect(stack.history).toEqual(sequence.slice(1000)); + expect(stack.current()).toBe(1999); + expect(stack.canUndo()).toBe(true); + expect(stack.canRedo()).toBe(false); + + // Saving drops the oldest elements from the stack + stack.save('end'); + expect(stack.history.length).toBe(1000); + expect(stack.current()).toBe('end'); + expect(stack.history).toEqual([...sequence.slice(1001), 'end']); + + // If states were undone but the history is full, can still add. + stack.undo(); + stack.undo(); + expect(stack.current()).toBe(1998); + stack.save(3000); + expect(stack.history.length).toBe(999); + // should be [1001, 1002, ..., 1998, 3000] + expect(stack.history).toEqual([...sequence.slice(1001, 1999), 3000]); + + // Try a different max length + stack = new UndoStack(2); + stack.save(0); + expect(stack.history).toEqual([0]); + stack.save(1); + expect(stack.history).toEqual([0, 1]); + stack.save(2); + expect(stack.history).toEqual([1, 2]); + }); + + describe('scheduled saves', () => { + it('should work', () => { + // Schedules 1000 ms ahead by default + stack.save(0); + stack.scheduleSave(1); + expect(stack.history).toEqual([0]); + jest.advanceTimersByTime(999); + expect(stack.history).toEqual([0]); + jest.advanceTimersByTime(1); + expect(stack.history).toEqual([0, 1]); + }); + + it('should have an adjustable delay', () => { + stack.scheduleSave(2, 100); + jest.advanceTimersByTime(100); + expect(stack.history).toEqual([2]); + }); + + it('should cancel previous scheduled saves', () => { + stack.scheduleSave(3); + jest.advanceTimersByTime(100); + stack.scheduleSave(4); + jest.runAllTimers(); + expect(stack.history).toEqual([4]); + }); + + it('should be canceled by explicit saves', () => { + stack.scheduleSave(5); + stack.save(6); + jest.runAllTimers(); + expect(stack.history).toEqual([6]); + }); + + it('should be canceled by undos and redos', () => { + stack.save(1); + stack.save(2); + stack.scheduleSave(3); + stack.undo(); + jest.runAllTimers(); + expect(stack.history).toEqual([1, 2]); + expect(stack.current()).toBe(1); + + stack.scheduleSave(4); + stack.redo(); + jest.runAllTimers(); + expect(stack.history).toEqual([1, 2]); + expect(stack.current()).toBe(2); + }); + + it('should be persisted immediately with saveNow()', () => { + stack.scheduleSave(7); + stack.scheduleSave(8); + stack.saveNow(); + jest.runAllTimers(); + expect(stack.history).toEqual([8]); + }); + }); +}); diff --git a/spec/frontend/projects/gke_cluster_namespace/gke_cluster_namespace_spec.js b/spec/frontend/projects/gke_cluster_namespace/gke_cluster_namespace_spec.js new file mode 100644 index 00000000000..7b8df03d3c3 --- /dev/null +++ b/spec/frontend/projects/gke_cluster_namespace/gke_cluster_namespace_spec.js @@ -0,0 +1,61 @@ +import initGkeNamespace from '~/projects/gke_cluster_namespace'; + +describe('GKE cluster namespace', () => { + const changeEvent = new Event('change'); + const isHidden = el => el.classList.contains('hidden'); + const hasDisabledInput = el => el.querySelector('input').disabled; + + let glManagedCheckbox; + let selfManaged; + let glManaged; + + beforeEach(() => { + setFixtures(` + <input class="js-gl-managed" type="checkbox" value="1" checked /> + <div class="js-namespace"> + <input type="text" /> + </div> + <div class="js-namespace-prefixed"> + <input type="text" /> + </div> + `); + + glManagedCheckbox = document.querySelector('.js-gl-managed'); + selfManaged = document.querySelector('.js-namespace'); + glManaged = document.querySelector('.js-namespace-prefixed'); + + initGkeNamespace(); + }); + + describe('GKE cluster namespace toggles', () => { + it('initially displays the GitLab-managed label and input', () => { + expect(isHidden(glManaged)).toEqual(false); + expect(hasDisabledInput(glManaged)).toEqual(false); + + expect(isHidden(selfManaged)).toEqual(true); + expect(hasDisabledInput(selfManaged)).toEqual(true); + }); + + it('displays the self-managed label and input when the Gitlab-managed checkbox is unchecked', () => { + glManagedCheckbox.checked = false; + glManagedCheckbox.dispatchEvent(changeEvent); + + expect(isHidden(glManaged)).toEqual(true); + expect(hasDisabledInput(glManaged)).toEqual(true); + + expect(isHidden(selfManaged)).toEqual(false); + expect(hasDisabledInput(selfManaged)).toEqual(false); + }); + + it('displays the GitLab-managed label and input when the Gitlab-managed checkbox is checked', () => { + glManagedCheckbox.checked = true; + glManagedCheckbox.dispatchEvent(changeEvent); + + expect(isHidden(glManaged)).toEqual(false); + expect(hasDisabledInput(glManaged)).toEqual(false); + + expect(isHidden(selfManaged)).toEqual(true); + expect(hasDisabledInput(selfManaged)).toEqual(true); + }); + }); +}); diff --git a/spec/frontend/vue_shared/components/markdown/header_spec.js b/spec/frontend/vue_shared/components/markdown/header_spec.js index aa0b544f948..48f2ee86619 100644 --- a/spec/frontend/vue_shared/components/markdown/header_spec.js +++ b/spec/frontend/vue_shared/components/markdown/header_spec.js @@ -101,7 +101,7 @@ describe('Markdown field header component', () => { vm.canSuggest = false; Vue.nextTick(() => { - expect(vm.$el.querySelector('.qa-suggestion-btn')).toBe(null); + expect(vm.$el.querySelector('.js-suggestion-btn')).toBe(null); }); }); }); diff --git a/spec/frontend/vue_shared/components/markdown/suggestion_diff_header_spec.js b/spec/frontend/vue_shared/components/markdown/suggestion_diff_header_spec.js index d69b4c7c162..6716e5cd794 100644 --- a/spec/frontend/vue_shared/components/markdown/suggestion_diff_header_spec.js +++ b/spec/frontend/vue_shared/components/markdown/suggestion_diff_header_spec.js @@ -28,8 +28,8 @@ describe('Suggestion Diff component', () => { wrapper.destroy(); }); - const findApplyButton = () => wrapper.find('.qa-apply-btn'); - const findHeader = () => wrapper.find('.qa-suggestion-diff-header'); + const findApplyButton = () => wrapper.find('.js-apply-btn'); + const findHeader = () => wrapper.find('.js-suggestion-diff-header'); const findHelpButton = () => wrapper.find('.js-help-btn'); const findLoading = () => wrapper.find(GlLoadingIcon); diff --git a/spec/graphql/resolvers/namespace_projects_resolver_spec.rb b/spec/graphql/resolvers/namespace_projects_resolver_spec.rb index 20e197e9f73..47591445fc0 100644 --- a/spec/graphql/resolvers/namespace_projects_resolver_spec.rb +++ b/spec/graphql/resolvers/namespace_projects_resolver_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Resolvers::NamespaceProjectsResolver, :nested_groups do +describe Resolvers::NamespaceProjectsResolver do include GraphqlHelpers let(:current_user) { create(:user) } diff --git a/spec/helpers/auto_devops_helper_spec.rb b/spec/helpers/auto_devops_helper_spec.rb index d2540696b17..e80388f9ea7 100644 --- a/spec/helpers/auto_devops_helper_spec.rb +++ b/spec/helpers/auto_devops_helper_spec.rb @@ -118,7 +118,7 @@ describe AutoDevopsHelper do it { is_expected.to eq('instance enabled') } end - context 'with groups', :nested_groups do + context 'with groups' do before do receiver.update(parent: parent) end @@ -170,7 +170,7 @@ describe AutoDevopsHelper do it { is_expected.to eq('instance enabled') } end - context 'with groups', :nested_groups do + context 'with groups' do let(:receiver) { create(:project, :repository, namespace: group) } before do @@ -203,7 +203,7 @@ describe AutoDevopsHelper do it { is_expected.to be_nil } end - context 'with groups', :nested_groups do + context 'with groups' do let(:receiver) { create(:project, :repository, namespace: group) } context 'when auto devops is disabled on group level' do diff --git a/spec/helpers/dashboard_helper_spec.rb b/spec/helpers/dashboard_helper_spec.rb index 023238ee0ae..49e23366355 100644 --- a/spec/helpers/dashboard_helper_spec.rb +++ b/spec/helpers/dashboard_helper_spec.rb @@ -22,6 +22,43 @@ describe DashboardHelper do end end + describe '#feature_entry' do + context 'when implicitly enabled' do + it 'considers feature enabled by default' do + entry = feature_entry('Demo', href: 'demo.link') + + expect(entry).to include('<p aria-label="Demo: status on">') + expect(entry).to include('<a href="demo.link">Demo</a>') + end + end + + context 'when explicitly enabled' do + it 'returns a link' do + entry = feature_entry('Demo', href: 'demo.link', enabled: true) + + expect(entry).to include('<p aria-label="Demo: status on">') + expect(entry).to include('<a href="demo.link">Demo</a>') + end + + it 'returns text if href is not provided' do + entry = feature_entry('Demo', enabled: true) + + expect(entry).to include('<p aria-label="Demo: status on">') + expect(entry).not_to match(/<a[^>]+>/) + end + end + + context 'when disabled' do + it 'returns text without link' do + entry = feature_entry('Demo', href: 'demo.link', enabled: false) + + expect(entry).to include('<p aria-label="Demo: status off">') + expect(entry).not_to match(/<a[^>]+>/) + expect(entry).to include('Demo') + end + end + end + describe '.has_start_trial?' do subject { helper.has_start_trial? } diff --git a/spec/helpers/groups_helper_spec.rb b/spec/helpers/groups_helper_spec.rb index 1763c46389a..037b16c90ed 100644 --- a/spec/helpers/groups_helper_spec.rb +++ b/spec/helpers/groups_helper_spec.rb @@ -86,7 +86,7 @@ describe GroupsHelper do end end - describe 'group_title', :nested_groups do + describe 'group_title' do let(:group) { create(:group) } let(:nested_group) { create(:group, parent: group) } let(:deep_nested_group) { create(:group, parent: nested_group) } @@ -99,7 +99,7 @@ describe GroupsHelper do end # rubocop:disable Layout/SpaceBeforeComma - describe '#share_with_group_lock_help_text', :nested_groups do + describe '#share_with_group_lock_help_text' do let!(:root_group) { create(:group) } let!(:subgroup) { create(:group, parent: root_group) } let!(:sub_subgroup) { create(:group, parent: subgroup) } @@ -230,7 +230,7 @@ describe GroupsHelper do end end - describe 'parent_group_options', :nested_groups do + describe 'parent_group_options' do let(:current_user) { create(:user) } let(:group) { create(:group, name: 'group') } let(:group2) { create(:group, name: 'group2') } diff --git a/spec/helpers/labels_helper_spec.rb b/spec/helpers/labels_helper_spec.rb index 314305d7a8e..4f1cab38f34 100644 --- a/spec/helpers/labels_helper_spec.rb +++ b/spec/helpers/labels_helper_spec.rb @@ -3,10 +3,8 @@ require 'spec_helper' describe LabelsHelper do describe '#show_label_issuables_link?' do shared_examples 'a valid response to show_label_issuables_link?' do |issuables_type, when_enabled = true, when_disabled = false| - let(:context_project) { project } - context "when asking for a #{issuables_type} link" do - subject { show_label_issuables_link?(label.present(issuable_subject: nil), issuables_type, project: context_project) } + subject { show_label_issuables_link?(label.present(issuable_subject: nil), issuables_type) } context "when #{issuables_type} are enabled for the project" do let(:project) { create(:project, "#{issuables_type}_access_level": ProjectFeature::ENABLED) } @@ -39,27 +37,11 @@ describe LabelsHelper do let(:label) { create(:group_label, group: group, title: 'bug') } context 'when asking for an issue link' do - context 'in the context of a project' do - it_behaves_like 'a valid response to show_label_issuables_link?', :issues, true, true - end - - context 'in the context of a group' do - let(:context_project) { nil } - - it_behaves_like 'a valid response to show_label_issuables_link?', :issues, true, true - end + it_behaves_like 'a valid response to show_label_issuables_link?', :issues, true, true end context 'when asking for a merge requests link' do - context 'in the context of a project' do - it_behaves_like 'a valid response to show_label_issuables_link?', :merge_requests, true, true - end - - context 'in the context of a group' do - let(:context_project) { nil } - - it_behaves_like 'a valid response to show_label_issuables_link?', :merge_requests, true, true - end + it_behaves_like 'a valid response to show_label_issuables_link?', :merge_requests, true, true end end end diff --git a/spec/helpers/namespaces_helper_spec.rb b/spec/helpers/namespaces_helper_spec.rb index 601f864ef36..e38513f6d94 100644 --- a/spec/helpers/namespaces_helper_spec.rb +++ b/spec/helpers/namespaces_helper_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe NamespacesHelper, :postgresql do +describe NamespacesHelper do let!(:admin) { create(:admin) } let!(:admin_project_creation_level) { nil } let!(:admin_group) do @@ -109,7 +109,7 @@ describe NamespacesHelper, :postgresql do expect(options).to include(user_group.name) end - context 'when nested groups are available', :nested_groups do + context 'when nested groups are available' do it 'includes groups nested in groups the user can administer' do allow(helper).to receive(:current_user).and_return(user) child_group = create(:group, :private, parent: user_group) diff --git a/spec/helpers/submodule_helper_spec.rb b/spec/helpers/submodule_helper_spec.rb index b922b910c89..ab4ef899119 100644 --- a/spec/helpers/submodule_helper_spec.rb +++ b/spec/helpers/submodule_helper_spec.rb @@ -229,6 +229,19 @@ describe SubmoduleHelper do end end end + + context 'unknown submodule' do + before do + # When there is no `.gitmodules` file, or if `.gitmodules` does not + # know the submodule at the specified path, + # `Repository#submodule_url_for` returns `nil` + stub_url(nil) + end + + it 'returns no links' do + expect(subject).to eq([nil, nil]) + end + end end context 'as view helpers in view context' do diff --git a/spec/helpers/wiki_helper_spec.rb b/spec/helpers/wiki_helper_spec.rb index 8eab40aeaf3..ee977e37ec1 100644 --- a/spec/helpers/wiki_helper_spec.rb +++ b/spec/helpers/wiki_helper_spec.rb @@ -22,7 +22,7 @@ describe WikiHelper do describe '#wiki_sort_controls' do let(:project) { create(:project) } let(:wiki_link) { helper.wiki_sort_controls(project, sort, direction) } - let(:classes) { "btn btn-default has-tooltip reverse-sort-btn qa-reverse-sort" } + let(:classes) { "btn btn-default has-tooltip reverse-sort-btn qa-reverse-sort rspec-reverse-sort" } def expected_link(sort, direction, icon_class) path = "/#{project.full_path}/wikis/pages?direction=#{direction}&sort=#{sort}" diff --git a/spec/javascripts/badges/components/badge_list_spec.js b/spec/javascripts/badges/components/badge_list_spec.js index 2f72c9ed89d..2fa807657de 100644 --- a/spec/javascripts/badges/components/badge_list_spec.js +++ b/spec/javascripts/badges/components/badge_list_spec.js @@ -60,7 +60,7 @@ describe('BadgeList component', () => { Vue.nextTick() .then(() => { - const loadingIcon = vm.$el.querySelector('.spinner'); + const loadingIcon = vm.$el.querySelector('.gl-spinner'); expect(loadingIcon).toBeVisible(); }) diff --git a/spec/javascripts/badges/components/badge_spec.js b/spec/javascripts/badges/components/badge_spec.js index 4e4d1ae2e99..c82a03a628a 100644 --- a/spec/javascripts/badges/components/badge_spec.js +++ b/spec/javascripts/badges/components/badge_spec.js @@ -15,7 +15,7 @@ describe('Badge component', () => { const buttons = vm.$el.querySelectorAll('button'); return { badgeImage: vm.$el.querySelector('img.project-badge'), - loadingIcon: vm.$el.querySelector('.spinner'), + loadingIcon: vm.$el.querySelector('.gl-spinner'), reloadButton: buttons[buttons.length - 1], }; }; diff --git a/spec/javascripts/boards/board_list_spec.js b/spec/javascripts/boards/board_list_spec.js index 9c9b435d7fd..6774a46ed58 100644 --- a/spec/javascripts/boards/board_list_spec.js +++ b/spec/javascripts/boards/board_list_spec.js @@ -148,7 +148,7 @@ describe('Board list component', () => { component.list.loadingMore = true; Vue.nextTick(() => { - expect(component.$el.querySelector('.board-list-count .spinner')).not.toBeNull(); + expect(component.$el.querySelector('.board-list-count .gl-spinner')).not.toBeNull(); done(); }); diff --git a/spec/javascripts/jobs/components/job_app_spec.js b/spec/javascripts/jobs/components/job_app_spec.js index f28d2c2a882..c58d59b4b16 100644 --- a/spec/javascripts/jobs/components/job_app_spec.js +++ b/spec/javascripts/jobs/components/job_app_spec.js @@ -19,6 +19,7 @@ describe('Job App ', () => { runnerHelpUrl: 'help/runner', deploymentHelpUrl: 'help/deployment', runnerSettingsUrl: 'settings/ci-cd/runners', + variablesSettingsUrl: 'settings/ci-cd/variables', terminalPath: 'jobs/123/terminal', pagePath: `${gl.TEST_HOST}jobs/123`, logState: diff --git a/spec/javascripts/jobs/components/manual_variables_form_spec.js b/spec/javascripts/jobs/components/manual_variables_form_spec.js new file mode 100644 index 00000000000..093aa905185 --- /dev/null +++ b/spec/javascripts/jobs/components/manual_variables_form_spec.js @@ -0,0 +1,88 @@ +import { shallowMount } from '@vue/test-utils'; +import { GlButton } from '@gitlab/ui'; +import Form from '~/jobs/components/manual_variables_form.vue'; + +describe('Manual Variables Form', () => { + let wrapper; + const requiredProps = { + action: { + path: '/play', + method: 'post', + button_title: 'Trigger this manual action', + }, + variablesSettingsUrl: '/settings', + }; + + const factory = (props = {}) => { + wrapper = shallowMount(Form, { + propsData: props, + }); + }; + + beforeEach(() => { + factory(requiredProps); + }); + + afterEach(() => { + wrapper.destroy(); + }); + + it('renders empty form with correct placeholders', () => { + expect(wrapper.find({ ref: 'inputKey' }).attributes('placeholder')).toBe('Input variable key'); + expect(wrapper.find({ ref: 'inputSecretValue' }).attributes('placeholder')).toBe( + 'Input variable value', + ); + }); + + it('renders help text with provided link', () => { + expect(wrapper.find('p').text()).toBe( + 'Specify variable values to be used in this run. The values specified in CI/CD settings will be used as default', + ); + + expect(wrapper.find('a').attributes('href')).toBe(requiredProps.variablesSettingsUrl); + }); + + describe('when adding a new variable', () => { + it('creates a new variable when user types a new key and resets the form', done => { + wrapper.vm + .$nextTick() + .then(() => wrapper.find({ ref: 'inputKey' }).setValue('new key')) + .then(() => { + expect(wrapper.vm.variables.length).toBe(1); + expect(wrapper.vm.variables[0].key).toBe('new key'); + expect(wrapper.find({ ref: 'inputKey' }).attributes('value')).toBe(undefined); + }) + .then(done) + .catch(done.fail); + }); + + it('creates a new variable when user types a new value and resets the form', done => { + wrapper.vm + .$nextTick() + .then(() => wrapper.find({ ref: 'inputSecretValue' }).setValue('new value')) + .then(() => { + expect(wrapper.vm.variables.length).toBe(1); + expect(wrapper.vm.variables[0].secret_value).toBe('new value'); + expect(wrapper.find({ ref: 'inputSecretValue' }).attributes('value')).toBe(undefined); + }) + .then(done) + .catch(done.fail); + }); + }); + + describe('when deleting a variable', () => { + it('removes the variable row', () => { + wrapper.vm.variables = [ + { + key: 'new key', + secret_value: 'value', + id: '1', + }, + ]; + + wrapper.find(GlButton).vm.$emit('click'); + + expect(wrapper.vm.variables.length).toBe(0); + }); + }); +}); diff --git a/spec/javascripts/monitoring/charts/empty_chart_spec.js b/spec/javascripts/monitoring/charts/empty_chart_spec.js new file mode 100644 index 00000000000..bbfca27dc5a --- /dev/null +++ b/spec/javascripts/monitoring/charts/empty_chart_spec.js @@ -0,0 +1,29 @@ +import { shallowMount } from '@vue/test-utils'; +import EmptyChart from '~/monitoring/components/charts/empty_chart.vue'; + +describe('Empty Chart component', () => { + let emptyChart; + const graphTitle = 'Memory Usage'; + + beforeEach(() => { + emptyChart = shallowMount(EmptyChart, { + propsData: { + graphTitle, + }, + }); + }); + + afterEach(() => { + emptyChart.destroy(); + }); + + it('render the chart title', () => { + expect(emptyChart.find({ ref: 'graphTitle' }).text()).toBe(graphTitle); + }); + + describe('Computed props', () => { + it('sets the height for the svg container', () => { + expect(emptyChart.vm.svgContainerStyle.height).toBe('300px'); + }); + }); +}); diff --git a/spec/javascripts/monitoring/panel_type_spec.js b/spec/javascripts/monitoring/panel_type_spec.js new file mode 100644 index 00000000000..8ce24041e97 --- /dev/null +++ b/spec/javascripts/monitoring/panel_type_spec.js @@ -0,0 +1,44 @@ +import { shallowMount } from '@vue/test-utils'; +import PanelType from '~/monitoring/components/panel_type.vue'; +import EmptyChart from '~/monitoring/components/charts/empty_chart.vue'; +import { graphDataPrometheusQueryRange } from './mock_data'; + +describe('Panel Type component', () => { + let panelType; + const dashboardWidth = 100; + + describe('When no graphData is available', () => { + let glEmptyChart; + const graphDataNoResult = graphDataPrometheusQueryRange; + graphDataNoResult.queries[0].result = []; + + beforeEach(() => { + panelType = shallowMount(PanelType, { + propsData: { + dashboardWidth, + graphData: graphDataNoResult, + }, + }); + }); + + afterEach(() => { + panelType.destroy(); + }); + + describe('Empty Chart component', () => { + beforeEach(() => { + glEmptyChart = panelType.find(EmptyChart); + }); + + it('is a Vue instance', () => { + expect(glEmptyChart.isVueInstance()).toBe(true); + }); + + it('it receives a graph title', () => { + const props = glEmptyChart.props(); + + expect(props.graphTitle).toBe(panelType.vm.graphData.title); + }); + }); + }); +}); diff --git a/spec/javascripts/performance_bar/components/detailed_metric_spec.js b/spec/javascripts/performance_bar/components/detailed_metric_spec.js index 8a7aa057186..0486b5fa3db 100644 --- a/spec/javascripts/performance_bar/components/detailed_metric_spec.js +++ b/spec/javascripts/performance_bar/components/detailed_metric_spec.js @@ -44,7 +44,6 @@ describe('detailedMetric', () => { }, metric: 'gitaly', header: 'Gitaly calls', - details: 'details', keys: ['feature', 'request'], }); }); @@ -79,8 +78,32 @@ describe('detailedMetric', () => { }); }); - it('displays the metric name', () => { + it('displays the metric title', () => { expect(vm.$el.innerText).toContain('gitaly'); }); + + describe('when using a custom metric title', () => { + beforeEach(() => { + vm = mountComponent(Vue.extend(detailedMetric), { + currentRequest: { + details: { + gitaly: { + duration: '123ms', + calls: '456', + details: requestDetails, + }, + }, + }, + metric: 'gitaly', + title: 'custom', + header: 'Gitaly calls', + keys: ['feature', 'request'], + }); + }); + + it('displays the custom title', () => { + expect(vm.$el.innerText).toContain('custom'); + }); + }); }); }); diff --git a/spec/javascripts/registry/components/app_spec.js b/spec/javascripts/registry/components/app_spec.js index 7b9b8d2b039..e7675669f7a 100644 --- a/spec/javascripts/registry/components/app_spec.js +++ b/spec/javascripts/registry/components/app_spec.js @@ -106,7 +106,7 @@ describe('Registry List', () => { it('should render a loading spinner', done => { Vue.nextTick(() => { - expect(vm.$el.querySelector('.spinner')).not.toBe(null); + expect(vm.$el.querySelector('.gl-spinner')).not.toBe(null); done(); }); }); diff --git a/spec/javascripts/reports/components/grouped_test_reports_app_spec.js b/spec/javascripts/reports/components/grouped_test_reports_app_spec.js index a17494966a3..1f1e626ed33 100644 --- a/spec/javascripts/reports/components/grouped_test_reports_app_spec.js +++ b/spec/javascripts/reports/components/grouped_test_reports_app_spec.js @@ -34,7 +34,7 @@ describe('Grouped Test Reports App', () => { it('renders success summary text', done => { setTimeout(() => { - expect(vm.$el.querySelector('.fa-spinner')).toBeNull(); + expect(vm.$el.querySelector('.gl-spinner')).toBeNull(); expect(vm.$el.querySelector('.js-code-text').textContent.trim()).toEqual( 'Test summary contained no changed test results out of 11 total tests', ); @@ -61,7 +61,7 @@ describe('Grouped Test Reports App', () => { it('renders success summary text', done => { setTimeout(() => { - expect(vm.$el.querySelector('.spinner')).not.toBeNull(); + expect(vm.$el.querySelector('.gl-spinner')).not.toBeNull(); expect(vm.$el.querySelector('.js-code-text').textContent.trim()).toEqual( 'Test summary results are being parsed', ); @@ -81,7 +81,7 @@ describe('Grouped Test Reports App', () => { it('renders failed summary text + new badge', done => { setTimeout(() => { - expect(vm.$el.querySelector('.spinner')).toBeNull(); + expect(vm.$el.querySelector('.gl-spinner')).toBeNull(); expect(vm.$el.querySelector('.js-code-text').textContent.trim()).toEqual( 'Test summary contained 2 failed test results out of 11 total tests', ); @@ -109,7 +109,7 @@ describe('Grouped Test Reports App', () => { it('renders summary text', done => { setTimeout(() => { - expect(vm.$el.querySelector('.spinner')).toBeNull(); + expect(vm.$el.querySelector('.gl-spinner')).toBeNull(); expect(vm.$el.querySelector('.js-code-text').textContent.trim()).toEqual( 'Test summary contained 2 failed test results and 2 fixed test results out of 11 total tests', ); @@ -137,7 +137,7 @@ describe('Grouped Test Reports App', () => { it('renders summary text', done => { setTimeout(() => { - expect(vm.$el.querySelector('.spinner')).toBeNull(); + expect(vm.$el.querySelector('.gl-spinner')).toBeNull(); expect(vm.$el.querySelector('.js-code-text').textContent.trim()).toEqual( 'Test summary contained 2 fixed test results out of 11 total tests', ); @@ -190,7 +190,7 @@ describe('Grouped Test Reports App', () => { }); it('renders loading summary text with loading icon', done => { - expect(vm.$el.querySelector('.spinner')).not.toBeNull(); + expect(vm.$el.querySelector('.gl-spinner')).not.toBeNull(); expect(vm.$el.querySelector('.js-code-text').textContent.trim()).toEqual( 'Test summary results are being parsed', ); diff --git a/spec/javascripts/vue_mr_widget/components/mr_widget_status_icon_spec.js b/spec/javascripts/vue_mr_widget/components/mr_widget_status_icon_spec.js index f622f52a7b9..5aac37d28df 100644 --- a/spec/javascripts/vue_mr_widget/components/mr_widget_status_icon_spec.js +++ b/spec/javascripts/vue_mr_widget/components/mr_widget_status_icon_spec.js @@ -18,7 +18,7 @@ describe('MR widget status icon component', () => { it('renders loading icon', () => { vm = mountComponent(Component, { status: 'loading' }); - expect(vm.$el.querySelector('.mr-widget-icon span').classList).toContain('spinner'); + expect(vm.$el.querySelector('.mr-widget-icon span').classList).toContain('gl-spinner'); }); }); diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_auto_merge_failed_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_auto_merge_failed_spec.js index d93badf8cd3..55a11a72551 100644 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_auto_merge_failed_spec.js +++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_auto_merge_failed_spec.js @@ -38,7 +38,9 @@ describe('MRWidgetAutoMergeFailed', () => { Vue.nextTick(() => { expect(vm.$el.querySelector('button').getAttribute('disabled')).toEqual('disabled'); - expect(vm.$el.querySelector('button .loading-container span').classList).toContain('spinner'); + expect(vm.$el.querySelector('button .loading-container span').classList).toContain( + 'gl-spinner', + ); done(); }); }); diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_checking_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_checking_spec.js index 96e512d222a..70c70eca746 100644 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_checking_spec.js +++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_checking_spec.js @@ -20,7 +20,7 @@ describe('MRWidgetChecking', () => { }); it('renders loading icon', () => { - expect(vm.$el.querySelector('.mr-widget-icon span').classList).toContain('spinner'); + expect(vm.$el.querySelector('.mr-widget-icon span').classList).toContain('gl-spinner'); }); it('renders information about merging', () => { diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_squash_before_merge_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_squash_before_merge_spec.js index d6d8eecfcb9..cb656525f06 100644 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_squash_before_merge_spec.js +++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_squash_before_merge_spec.js @@ -21,7 +21,7 @@ describe('Squash before merge component', () => { }); describe('checkbox', () => { - const findCheckbox = () => wrapper.find('.qa-squash-checkbox'); + const findCheckbox = () => wrapper.find('.js-squash-checkbox'); it('is unchecked if passed value prop is false', () => { createComponent({ diff --git a/spec/javascripts/vue_shared/components/file_icon_spec.js b/spec/javascripts/vue_shared/components/file_icon_spec.js index 5bea8c43da3..1f61e19fa84 100644 --- a/spec/javascripts/vue_shared/components/file_icon_spec.js +++ b/spec/javascripts/vue_shared/components/file_icon_spec.js @@ -72,7 +72,7 @@ describe('File Icon component', () => { const { classList } = vm.$el.querySelector('.loading-container span'); - expect(classList.contains('spinner')).toEqual(true); + expect(classList.contains('gl-spinner')).toEqual(true); }); it('should add a special class and a size class', () => { diff --git a/spec/javascripts/vue_shared/components/header_ci_component_spec.js b/spec/javascripts/vue_shared/components/header_ci_component_spec.js index a9c1a67b39b..2b059e5e9f4 100644 --- a/spec/javascripts/vue_shared/components/header_ci_component_spec.js +++ b/spec/javascripts/vue_shared/components/header_ci_component_spec.js @@ -88,7 +88,7 @@ describe('Header CI Component', () => { vm.actions[0].isLoading = true; Vue.nextTick(() => { - expect(vm.$el.querySelector('.btn .spinner').getAttribute('style')).toBeFalsy(); + expect(vm.$el.querySelector('.btn .gl-spinner').getAttribute('style')).toBeFalsy(); done(); }); }); diff --git a/spec/javascripts/vue_shared/components/markdown/suggestion_diff_spec.js b/spec/javascripts/vue_shared/components/markdown/suggestion_diff_spec.js index ea74cb9eb21..dc929e83eb7 100644 --- a/spec/javascripts/vue_shared/components/markdown/suggestion_diff_spec.js +++ b/spec/javascripts/vue_shared/components/markdown/suggestion_diff_spec.js @@ -60,7 +60,7 @@ describe('Suggestion Diff component', () => { describe('init', () => { it('renders a suggestion header', () => { - expect(vm.$el.querySelector('.qa-suggestion-diff-header')).not.toBeNull(); + expect(vm.$el.querySelector('.js-suggestion-diff-header')).not.toBeNull(); }); it('renders a diff table with syntax highlighting', () => { diff --git a/spec/lib/after_commit_queue_spec.rb b/spec/lib/after_commit_queue_spec.rb index 6e7c2ec2363..8e9dfd90338 100644 --- a/spec/lib/after_commit_queue_spec.rb +++ b/spec/lib/after_commit_queue_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe AfterCommitQueue do diff --git a/spec/lib/api/api_spec.rb b/spec/lib/api/api_spec.rb index ceef0b41e59..c83d068ca50 100644 --- a/spec/lib/api/api_spec.rb +++ b/spec/lib/api/api_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe API::API do diff --git a/spec/lib/api/helpers/custom_validators_spec.rb b/spec/lib/api/helpers/custom_validators_spec.rb index aed86b21cb7..1ebce2ab5c4 100644 --- a/spec/lib/api/helpers/custom_validators_spec.rb +++ b/spec/lib/api/helpers/custom_validators_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe API::Helpers::CustomValidators do diff --git a/spec/lib/api/helpers/pagination_spec.rb b/spec/lib/api/helpers/pagination_spec.rb index b0a00392957..b57adb46385 100644 --- a/spec/lib/api/helpers/pagination_spec.rb +++ b/spec/lib/api/helpers/pagination_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe API::Helpers::Pagination do diff --git a/spec/lib/api/helpers/related_resources_helpers_spec.rb b/spec/lib/api/helpers/related_resources_helpers_spec.rb index 99fe8795d91..fb26cc417e8 100644 --- a/spec/lib/api/helpers/related_resources_helpers_spec.rb +++ b/spec/lib/api/helpers/related_resources_helpers_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe API::Helpers::RelatedResourcesHelpers do diff --git a/spec/lib/api/helpers/version_spec.rb b/spec/lib/api/helpers/version_spec.rb index 34006e0930b..a9f33962537 100644 --- a/spec/lib/api/helpers/version_spec.rb +++ b/spec/lib/api/helpers/version_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe API::Helpers::Version do diff --git a/spec/lib/api/helpers_spec.rb b/spec/lib/api/helpers_spec.rb index 00916f80784..0624c25e734 100644 --- a/spec/lib/api/helpers_spec.rb +++ b/spec/lib/api/helpers_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe API::Helpers do diff --git a/spec/lib/backup/files_spec.rb b/spec/lib/backup/files_spec.rb index 63f2298357f..e903eada62d 100644 --- a/spec/lib/backup/files_spec.rb +++ b/spec/lib/backup/files_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Backup::Files do diff --git a/spec/lib/backup/manager_spec.rb b/spec/lib/backup/manager_spec.rb index ae1c881e1f6..fee7ffc60ee 100644 --- a/spec/lib/backup/manager_spec.rb +++ b/spec/lib/backup/manager_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Backup::Manager do diff --git a/spec/lib/backup/repository_spec.rb b/spec/lib/backup/repository_spec.rb index 5ace5c5b1a2..e1d46c25338 100644 --- a/spec/lib/backup/repository_spec.rb +++ b/spec/lib/backup/repository_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Backup::Repository do diff --git a/spec/lib/backup/uploads_spec.rb b/spec/lib/backup/uploads_spec.rb index 544d3754c0f..55b69f29812 100644 --- a/spec/lib/backup/uploads_spec.rb +++ b/spec/lib/backup/uploads_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Backup::Uploads do diff --git a/spec/lib/banzai/color_parser_spec.rb b/spec/lib/banzai/color_parser_spec.rb index af2a8f215c1..d9202ce77db 100644 --- a/spec/lib/banzai/color_parser_spec.rb +++ b/spec/lib/banzai/color_parser_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Banzai::ColorParser do diff --git a/spec/lib/banzai/commit_renderer_spec.rb b/spec/lib/banzai/commit_renderer_spec.rb index 316dbf052c3..e5a16b167be 100644 --- a/spec/lib/banzai/commit_renderer_spec.rb +++ b/spec/lib/banzai/commit_renderer_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Banzai::CommitRenderer do diff --git a/spec/lib/banzai/cross_project_reference_spec.rb b/spec/lib/banzai/cross_project_reference_spec.rb index ba995e16be7..cf41af7e7a1 100644 --- a/spec/lib/banzai/cross_project_reference_spec.rb +++ b/spec/lib/banzai/cross_project_reference_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Banzai::CrossProjectReference do diff --git a/spec/lib/banzai/filter/absolute_link_filter_spec.rb b/spec/lib/banzai/filter/absolute_link_filter_spec.rb index 50be551cd90..b61bd496dba 100644 --- a/spec/lib/banzai/filter/absolute_link_filter_spec.rb +++ b/spec/lib/banzai/filter/absolute_link_filter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Banzai::Filter::AbsoluteLinkFilter do diff --git a/spec/lib/banzai/filter/abstract_reference_filter_spec.rb b/spec/lib/banzai/filter/abstract_reference_filter_spec.rb index 1e82d18d056..3e8b0ea113f 100644 --- a/spec/lib/banzai/filter/abstract_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/abstract_reference_filter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Banzai::Filter::AbstractReferenceFilter do diff --git a/spec/lib/banzai/filter/ascii_doc_post_processing_filter_spec.rb b/spec/lib/banzai/filter/ascii_doc_post_processing_filter_spec.rb index 34f1657b6d3..bd06dae26ba 100644 --- a/spec/lib/banzai/filter/ascii_doc_post_processing_filter_spec.rb +++ b/spec/lib/banzai/filter/ascii_doc_post_processing_filter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Banzai::Filter::AsciiDocPostProcessingFilter do diff --git a/spec/lib/banzai/filter/autolink_filter_spec.rb b/spec/lib/banzai/filter/autolink_filter_spec.rb index 4972c4b4bd2..8fba72a23f6 100644 --- a/spec/lib/banzai/filter/autolink_filter_spec.rb +++ b/spec/lib/banzai/filter/autolink_filter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Banzai::Filter::AutolinkFilter do diff --git a/spec/lib/banzai/filter/blockquote_fence_filter_spec.rb b/spec/lib/banzai/filter/blockquote_fence_filter_spec.rb index 5b3f679084e..807f1b8bbd3 100644 --- a/spec/lib/banzai/filter/blockquote_fence_filter_spec.rb +++ b/spec/lib/banzai/filter/blockquote_fence_filter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe Banzai::Filter::BlockquoteFenceFilter do diff --git a/spec/lib/banzai/filter/color_filter_spec.rb b/spec/lib/banzai/filter/color_filter_spec.rb index a098b037510..f8931d37b99 100644 --- a/spec/lib/banzai/filter/color_filter_spec.rb +++ b/spec/lib/banzai/filter/color_filter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Banzai::Filter::ColorFilter, lib: true do diff --git a/spec/lib/banzai/filter/commit_range_reference_filter_spec.rb b/spec/lib/banzai/filter/commit_range_reference_filter_spec.rb index 4daf6be1bb7..a82b890be42 100644 --- a/spec/lib/banzai/filter/commit_range_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/commit_range_reference_filter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Banzai::Filter::CommitRangeReferenceFilter do diff --git a/spec/lib/banzai/filter/commit_reference_filter_spec.rb b/spec/lib/banzai/filter/commit_reference_filter_spec.rb index d6c9e9e4b19..1bc0335cfc0 100644 --- a/spec/lib/banzai/filter/commit_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/commit_reference_filter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Banzai::Filter::CommitReferenceFilter do diff --git a/spec/lib/banzai/filter/commit_trailers_filter_spec.rb b/spec/lib/banzai/filter/commit_trailers_filter_spec.rb index 068cdc85a07..bcb74be1034 100644 --- a/spec/lib/banzai/filter/commit_trailers_filter_spec.rb +++ b/spec/lib/banzai/filter/commit_trailers_filter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' require 'ffaker' diff --git a/spec/lib/banzai/filter/emoji_filter_spec.rb b/spec/lib/banzai/filter/emoji_filter_spec.rb index 85a4619e33d..4e163668a28 100644 --- a/spec/lib/banzai/filter/emoji_filter_spec.rb +++ b/spec/lib/banzai/filter/emoji_filter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Banzai::Filter::EmojiFilter do diff --git a/spec/lib/banzai/filter/external_issue_reference_filter_spec.rb b/spec/lib/banzai/filter/external_issue_reference_filter_spec.rb index 7c94cf37e32..78795a157f8 100644 --- a/spec/lib/banzai/filter/external_issue_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/external_issue_reference_filter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Banzai::Filter::ExternalIssueReferenceFilter do diff --git a/spec/lib/banzai/filter/external_link_filter_spec.rb b/spec/lib/banzai/filter/external_link_filter_spec.rb index 2acbe05f082..59fea5766ee 100644 --- a/spec/lib/banzai/filter/external_link_filter_spec.rb +++ b/spec/lib/banzai/filter/external_link_filter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' shared_examples 'an external link with rel attribute' do diff --git a/spec/lib/banzai/filter/front_matter_filter_spec.rb b/spec/lib/banzai/filter/front_matter_filter_spec.rb index 3071dc7cf21..90b383dbcff 100644 --- a/spec/lib/banzai/filter/front_matter_filter_spec.rb +++ b/spec/lib/banzai/filter/front_matter_filter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe Banzai::Filter::FrontMatterFilter do diff --git a/spec/lib/banzai/filter/gollum_tags_filter_spec.rb b/spec/lib/banzai/filter/gollum_tags_filter_spec.rb index 0e178b859c4..9d179ef2a49 100644 --- a/spec/lib/banzai/filter/gollum_tags_filter_spec.rb +++ b/spec/lib/banzai/filter/gollum_tags_filter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Banzai::Filter::GollumTagsFilter do diff --git a/spec/lib/banzai/filter/html_entity_filter_spec.rb b/spec/lib/banzai/filter/html_entity_filter_spec.rb index 1d98fc0d5db..6017380725d 100644 --- a/spec/lib/banzai/filter/html_entity_filter_spec.rb +++ b/spec/lib/banzai/filter/html_entity_filter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Banzai::Filter::HtmlEntityFilter do diff --git a/spec/lib/banzai/filter/image_lazy_load_filter_spec.rb b/spec/lib/banzai/filter/image_lazy_load_filter_spec.rb index d06c5535309..6475fd14ce4 100644 --- a/spec/lib/banzai/filter/image_lazy_load_filter_spec.rb +++ b/spec/lib/banzai/filter/image_lazy_load_filter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Banzai::Filter::ImageLazyLoadFilter do diff --git a/spec/lib/banzai/filter/image_link_filter_spec.rb b/spec/lib/banzai/filter/image_link_filter_spec.rb index c84b98eb225..7b0cb675551 100644 --- a/spec/lib/banzai/filter/image_link_filter_spec.rb +++ b/spec/lib/banzai/filter/image_link_filter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Banzai::Filter::ImageLinkFilter do diff --git a/spec/lib/banzai/filter/inline_diff_filter_spec.rb b/spec/lib/banzai/filter/inline_diff_filter_spec.rb index 63c4ab61b86..c09065fb746 100644 --- a/spec/lib/banzai/filter/inline_diff_filter_spec.rb +++ b/spec/lib/banzai/filter/inline_diff_filter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Banzai::Filter::InlineDiffFilter do diff --git a/spec/lib/banzai/filter/issuable_state_filter_spec.rb b/spec/lib/banzai/filter/issuable_state_filter_spec.rb index a5373517ac8..9f6dcded56f 100644 --- a/spec/lib/banzai/filter/issuable_state_filter_spec.rb +++ b/spec/lib/banzai/filter/issuable_state_filter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Banzai::Filter::IssuableStateFilter do diff --git a/spec/lib/banzai/filter/issue_reference_filter_spec.rb b/spec/lib/banzai/filter/issue_reference_filter_spec.rb index 914c4e2d823..4a412da27a7 100644 --- a/spec/lib/banzai/filter/issue_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/issue_reference_filter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Banzai::Filter::IssueReferenceFilter do diff --git a/spec/lib/banzai/filter/label_reference_filter_spec.rb b/spec/lib/banzai/filter/label_reference_filter_spec.rb index 108d7b43a26..213a5459118 100644 --- a/spec/lib/banzai/filter/label_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/label_reference_filter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' require 'html/pipeline' diff --git a/spec/lib/banzai/filter/markdown_filter_spec.rb b/spec/lib/banzai/filter/markdown_filter_spec.rb index 83fcda29680..06df67facf9 100644 --- a/spec/lib/banzai/filter/markdown_filter_spec.rb +++ b/spec/lib/banzai/filter/markdown_filter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Banzai::Filter::MarkdownFilter do diff --git a/spec/lib/banzai/filter/math_filter_spec.rb b/spec/lib/banzai/filter/math_filter_spec.rb index cade8cb409e..c8fd92edcdf 100644 --- a/spec/lib/banzai/filter/math_filter_spec.rb +++ b/spec/lib/banzai/filter/math_filter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Banzai::Filter::MathFilter do diff --git a/spec/lib/banzai/filter/merge_request_reference_filter_spec.rb b/spec/lib/banzai/filter/merge_request_reference_filter_spec.rb index 72dfd6ff9ea..12ee952b10e 100644 --- a/spec/lib/banzai/filter/merge_request_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/merge_request_reference_filter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Banzai::Filter::MergeRequestReferenceFilter do diff --git a/spec/lib/banzai/filter/mermaid_filter_spec.rb b/spec/lib/banzai/filter/mermaid_filter_spec.rb index f6474c8936d..ae6725cc14c 100644 --- a/spec/lib/banzai/filter/mermaid_filter_spec.rb +++ b/spec/lib/banzai/filter/mermaid_filter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Banzai::Filter::MermaidFilter do diff --git a/spec/lib/banzai/filter/milestone_reference_filter_spec.rb b/spec/lib/banzai/filter/milestone_reference_filter_spec.rb index f0a5dc8d0d7..3f021adc756 100644 --- a/spec/lib/banzai/filter/milestone_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/milestone_reference_filter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Banzai::Filter::MilestoneReferenceFilter do @@ -363,7 +365,7 @@ describe Banzai::Filter::MilestoneReferenceFilter do expect(doc.css('a')).to be_empty end - it 'supports parent group references', :nested_groups do + it 'supports parent group references' do milestone.update!(group: parent_group) doc = reference_filter("See #{reference}") @@ -396,7 +398,7 @@ describe Banzai::Filter::MilestoneReferenceFilter do context 'when group milestone' do let(:group_milestone) { create(:milestone, title: 'group_milestone', group: group) } - context 'for subgroups', :nested_groups do + context 'for subgroups' do let(:sub_group) { create(:group, parent: group) } let(:sub_group_milestone) { create(:milestone, title: 'sub_group_milestone', group: sub_group) } diff --git a/spec/lib/banzai/filter/plantuml_filter_spec.rb b/spec/lib/banzai/filter/plantuml_filter_spec.rb index 6f7acfe7072..713bab4527b 100644 --- a/spec/lib/banzai/filter/plantuml_filter_spec.rb +++ b/spec/lib/banzai/filter/plantuml_filter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Banzai::Filter::PlantumlFilter do diff --git a/spec/lib/banzai/filter/reference_filter_spec.rb b/spec/lib/banzai/filter/reference_filter_spec.rb index f96b6c83b0a..d889b0b832d 100644 --- a/spec/lib/banzai/filter/reference_filter_spec.rb +++ b/spec/lib/banzai/filter/reference_filter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Banzai::Filter::ReferenceFilter do diff --git a/spec/lib/banzai/filter/reference_redactor_filter_spec.rb b/spec/lib/banzai/filter/reference_redactor_filter_spec.rb index e87440895e0..dc888a47988 100644 --- a/spec/lib/banzai/filter/reference_redactor_filter_spec.rb +++ b/spec/lib/banzai/filter/reference_redactor_filter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Banzai::Filter::ReferenceRedactorFilter do diff --git a/spec/lib/banzai/filter/relative_link_filter_spec.rb b/spec/lib/banzai/filter/relative_link_filter_spec.rb index a714fa50f5f..ecb83b6cb66 100644 --- a/spec/lib/banzai/filter/relative_link_filter_spec.rb +++ b/spec/lib/banzai/filter/relative_link_filter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Banzai::Filter::RelativeLinkFilter do diff --git a/spec/lib/banzai/filter/sanitization_filter_spec.rb b/spec/lib/banzai/filter/sanitization_filter_spec.rb index f2a5d7b2c9f..8a4b819e4d6 100644 --- a/spec/lib/banzai/filter/sanitization_filter_spec.rb +++ b/spec/lib/banzai/filter/sanitization_filter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Banzai::Filter::SanitizationFilter do diff --git a/spec/lib/banzai/filter/snippet_reference_filter_spec.rb b/spec/lib/banzai/filter/snippet_reference_filter_spec.rb index 21cf092428d..62ce12406a2 100644 --- a/spec/lib/banzai/filter/snippet_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/snippet_reference_filter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Banzai::Filter::SnippetReferenceFilter do diff --git a/spec/lib/banzai/filter/spaced_link_filter_spec.rb b/spec/lib/banzai/filter/spaced_link_filter_spec.rb index 76d7644d76c..98c38813144 100644 --- a/spec/lib/banzai/filter/spaced_link_filter_spec.rb +++ b/spec/lib/banzai/filter/spaced_link_filter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Banzai::Filter::SpacedLinkFilter do diff --git a/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb b/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb index 80ca7a63435..f220ccecee1 100644 --- a/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb +++ b/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Banzai::Filter::SyntaxHighlightFilter do diff --git a/spec/lib/banzai/filter/table_of_contents_filter_spec.rb b/spec/lib/banzai/filter/table_of_contents_filter_spec.rb index 4a9880ac85a..5ca3c722e3e 100644 --- a/spec/lib/banzai/filter/table_of_contents_filter_spec.rb +++ b/spec/lib/banzai/filter/table_of_contents_filter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Banzai::Filter::TableOfContentsFilter do @@ -112,11 +114,11 @@ describe Banzai::Filter::TableOfContentsFilter do context 'table of contents nesting' do let(:results) do result( - header(1, 'Header 1') << - header(2, 'Header 1-1') << - header(3, 'Header 1-1-1') << - header(2, 'Header 1-2') << - header(1, 'Header 2') << + header(1, 'Header 1') + + header(2, 'Header 1-1') + + header(3, 'Header 1-1-1') + + header(2, 'Header 1-2') + + header(1, 'Header 2') + header(2, 'Header 2-1') ) end diff --git a/spec/lib/banzai/filter/user_reference_filter_spec.rb b/spec/lib/banzai/filter/user_reference_filter_spec.rb index 1e8a44b4549..6bc87d245f5 100644 --- a/spec/lib/banzai/filter/user_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/user_reference_filter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Banzai::Filter::UserReferenceFilter do diff --git a/spec/lib/banzai/filter/video_link_filter_spec.rb b/spec/lib/banzai/filter/video_link_filter_spec.rb index 81dda0687f3..483e806624c 100644 --- a/spec/lib/banzai/filter/video_link_filter_spec.rb +++ b/spec/lib/banzai/filter/video_link_filter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Banzai::Filter::VideoLinkFilter do diff --git a/spec/lib/banzai/filter/wiki_link_filter_spec.rb b/spec/lib/banzai/filter/wiki_link_filter_spec.rb index cce1cd0b284..d2d539a62fc 100644 --- a/spec/lib/banzai/filter/wiki_link_filter_spec.rb +++ b/spec/lib/banzai/filter/wiki_link_filter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Banzai::Filter::WikiLinkFilter do @@ -70,47 +72,5 @@ describe Banzai::Filter::WikiLinkFilter do expect(filtered_link.attribute('href').value).to eq(invalid_link) end end - - context "when the slug is deemed unsafe or invalid" do - let(:link) { "alert(1);" } - - invalid_slugs = [ - "javascript:", - "JaVaScRiPt:", - "\u0001java\u0003script:", - "javascript :", - "javascript: ", - "javascript : ", - ":javascript:", - "javascript:", - "javascript:", - "javascript:", - "javascript:", - "java\0script:", - "  javascript:" - ] - - invalid_slugs.each do |slug| - context "with the slug #{slug}" do - it "doesn't rewrite a (.) relative link" do - filtered_link = filter( - "<a href='.#{link}'>Link</a>", - project_wiki: wiki, - page_slug: slug).children[0] - - expect(filtered_link.attribute('href').value).not_to include(slug) - end - - it "doesn't rewrite a (..) relative link" do - filtered_link = filter( - "<a href='..#{link}'>Link</a>", - project_wiki: wiki, - page_slug: slug).children[0] - - expect(filtered_link.attribute('href').value).not_to include(slug) - end - end - end - end end end diff --git a/spec/lib/banzai/filter_array_spec.rb b/spec/lib/banzai/filter_array_spec.rb index ea84005e7f8..bed41a80d29 100644 --- a/spec/lib/banzai/filter_array_spec.rb +++ b/spec/lib/banzai/filter_array_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Banzai::FilterArray do diff --git a/spec/lib/banzai/issuable_extractor_spec.rb b/spec/lib/banzai/issuable_extractor_spec.rb index f42951d9781..7fa6048c1c6 100644 --- a/spec/lib/banzai/issuable_extractor_spec.rb +++ b/spec/lib/banzai/issuable_extractor_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Banzai::IssuableExtractor do diff --git a/spec/lib/banzai/object_renderer_spec.rb b/spec/lib/banzai/object_renderer_spec.rb index e3e6e22568c..a523608fa50 100644 --- a/spec/lib/banzai/object_renderer_spec.rb +++ b/spec/lib/banzai/object_renderer_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Banzai::ObjectRenderer do diff --git a/spec/lib/banzai/pipeline/description_pipeline_spec.rb b/spec/lib/banzai/pipeline/description_pipeline_spec.rb index 77cb1954ea3..d032ec71e45 100644 --- a/spec/lib/banzai/pipeline/description_pipeline_spec.rb +++ b/spec/lib/banzai/pipeline/description_pipeline_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe Banzai::Pipeline::DescriptionPipeline do diff --git a/spec/lib/banzai/pipeline/email_pipeline_spec.rb b/spec/lib/banzai/pipeline/email_pipeline_spec.rb index b99161109eb..eea25320f3d 100644 --- a/spec/lib/banzai/pipeline/email_pipeline_spec.rb +++ b/spec/lib/banzai/pipeline/email_pipeline_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe Banzai::Pipeline::EmailPipeline do diff --git a/spec/lib/banzai/pipeline/full_pipeline_spec.rb b/spec/lib/banzai/pipeline/full_pipeline_spec.rb index 3d3aa64d630..2b4d1b58676 100644 --- a/spec/lib/banzai/pipeline/full_pipeline_spec.rb +++ b/spec/lib/banzai/pipeline/full_pipeline_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe Banzai::Pipeline::FullPipeline do diff --git a/spec/lib/banzai/pipeline/gfm_pipeline_spec.rb b/spec/lib/banzai/pipeline/gfm_pipeline_spec.rb index 469692f7b5a..0a3e0962452 100644 --- a/spec/lib/banzai/pipeline/gfm_pipeline_spec.rb +++ b/spec/lib/banzai/pipeline/gfm_pipeline_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe Banzai::Pipeline::GfmPipeline do diff --git a/spec/lib/banzai/pipeline/wiki_pipeline_spec.rb b/spec/lib/banzai/pipeline/wiki_pipeline_spec.rb index 64ca3ec345d..015af20f220 100644 --- a/spec/lib/banzai/pipeline/wiki_pipeline_spec.rb +++ b/spec/lib/banzai/pipeline/wiki_pipeline_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe Banzai::Pipeline::WikiPipeline do @@ -177,6 +179,85 @@ describe Banzai::Pipeline::WikiPipeline do end end end + + describe "checking slug validity when assembling links" do + context "with a valid slug" do + let(:valid_slug) { "http://example.com" } + + it "includes the slug in a (.) relative link" do + output = described_class.to_html( + "[Link](./alert(1);)", + project: project, + project_wiki: project_wiki, + page_slug: valid_slug + ) + + expect(output).to include(valid_slug) + end + + it "includeds the slug in a (..) relative link" do + output = described_class.to_html( + "[Link](../alert(1);)", + project: project, + project_wiki: project_wiki, + page_slug: valid_slug + ) + + expect(output).to include(valid_slug) + end + end + + context "when the slug is deemed unsafe or invalid" do + invalid_slugs = [ + "javascript:", + "JaVaScRiPt:", + "\u0001java\u0003script:", + "javascript :", + "javascript: ", + "javascript : ", + ":javascript:", + "javascript:", + "javascript:", + "javascript:", + "javascript:", + "java\0script:", + "  javascript:" + ] + + invalid_js_links = [ + "alert(1);", + "alert(document.location);" + ] + + invalid_slugs.each do |slug| + context "with the invalid slug #{slug}" do + invalid_js_links.each do |link| + it "doesn't include a prohibited slug in a (.) relative link '#{link}'" do + output = described_class.to_html( + "[Link](./#{link})", + project: project, + project_wiki: project_wiki, + page_slug: slug + ) + + expect(output).not_to include(slug) + end + + it "doesn't include a prohibited slug in a (..) relative link '#{link}'" do + output = described_class.to_html( + "[Link](../#{link})", + project: project, + project_wiki: project_wiki, + page_slug: slug + ) + + expect(output).not_to include(slug) + end + end + end + end + end + end end describe 'videos' do diff --git a/spec/lib/banzai/querying_spec.rb b/spec/lib/banzai/querying_spec.rb index 27da2a7439c..b7a235b0558 100644 --- a/spec/lib/banzai/querying_spec.rb +++ b/spec/lib/banzai/querying_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Banzai::Querying do diff --git a/spec/lib/banzai/reference_parser/base_parser_spec.rb b/spec/lib/banzai/reference_parser/base_parser_spec.rb index c6e9fc414a1..7897164d985 100644 --- a/spec/lib/banzai/reference_parser/base_parser_spec.rb +++ b/spec/lib/banzai/reference_parser/base_parser_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Banzai::ReferenceParser::BaseParser do diff --git a/spec/lib/banzai/reference_parser/commit_parser_spec.rb b/spec/lib/banzai/reference_parser/commit_parser_spec.rb index f558dea209f..b44ae67e430 100644 --- a/spec/lib/banzai/reference_parser/commit_parser_spec.rb +++ b/spec/lib/banzai/reference_parser/commit_parser_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Banzai::ReferenceParser::CommitParser do diff --git a/spec/lib/banzai/reference_parser/commit_range_parser_spec.rb b/spec/lib/banzai/reference_parser/commit_range_parser_spec.rb index ff3b82cc482..da853233018 100644 --- a/spec/lib/banzai/reference_parser/commit_range_parser_spec.rb +++ b/spec/lib/banzai/reference_parser/commit_range_parser_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Banzai::ReferenceParser::CommitRangeParser do diff --git a/spec/lib/banzai/reference_parser/external_issue_parser_spec.rb b/spec/lib/banzai/reference_parser/external_issue_parser_spec.rb index 1cb31e57114..0f29a95bdcc 100644 --- a/spec/lib/banzai/reference_parser/external_issue_parser_spec.rb +++ b/spec/lib/banzai/reference_parser/external_issue_parser_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Banzai::ReferenceParser::ExternalIssueParser do diff --git a/spec/lib/banzai/reference_parser/issue_parser_spec.rb b/spec/lib/banzai/reference_parser/issue_parser_spec.rb index 77c2064caba..a925d294b1b 100644 --- a/spec/lib/banzai/reference_parser/issue_parser_spec.rb +++ b/spec/lib/banzai/reference_parser/issue_parser_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Banzai::ReferenceParser::IssueParser do diff --git a/spec/lib/banzai/reference_parser/label_parser_spec.rb b/spec/lib/banzai/reference_parser/label_parser_spec.rb index e4df2533821..cf8adb57ffc 100644 --- a/spec/lib/banzai/reference_parser/label_parser_spec.rb +++ b/spec/lib/banzai/reference_parser/label_parser_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Banzai::ReferenceParser::LabelParser do diff --git a/spec/lib/banzai/reference_parser/merge_request_parser_spec.rb b/spec/lib/banzai/reference_parser/merge_request_parser_spec.rb index 5417b1f00be..1561dabcdbf 100644 --- a/spec/lib/banzai/reference_parser/merge_request_parser_spec.rb +++ b/spec/lib/banzai/reference_parser/merge_request_parser_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Banzai::ReferenceParser::MergeRequestParser do diff --git a/spec/lib/banzai/reference_parser/milestone_parser_spec.rb b/spec/lib/banzai/reference_parser/milestone_parser_spec.rb index 751d042ffde..006f8e37690 100644 --- a/spec/lib/banzai/reference_parser/milestone_parser_spec.rb +++ b/spec/lib/banzai/reference_parser/milestone_parser_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Banzai::ReferenceParser::MilestoneParser do diff --git a/spec/lib/banzai/reference_parser/snippet_parser_spec.rb b/spec/lib/banzai/reference_parser/snippet_parser_spec.rb index d410bd4c164..528f79ed020 100644 --- a/spec/lib/banzai/reference_parser/snippet_parser_spec.rb +++ b/spec/lib/banzai/reference_parser/snippet_parser_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Banzai::ReferenceParser::SnippetParser do diff --git a/spec/lib/banzai/reference_parser/user_parser_spec.rb b/spec/lib/banzai/reference_parser/user_parser_spec.rb index 112447f098e..a5b4e59a3a1 100644 --- a/spec/lib/banzai/reference_parser/user_parser_spec.rb +++ b/spec/lib/banzai/reference_parser/user_parser_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Banzai::ReferenceParser::UserParser do diff --git a/spec/lib/banzai/reference_redactor_spec.rb b/spec/lib/banzai/reference_redactor_spec.rb index a3b47c4d826..c30a194a0b3 100644 --- a/spec/lib/banzai/reference_redactor_spec.rb +++ b/spec/lib/banzai/reference_redactor_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Banzai::ReferenceRedactor do diff --git a/spec/lib/banzai/renderer_spec.rb b/spec/lib/banzai/renderer_spec.rb index a099f7482c1..0d329b47aa3 100644 --- a/spec/lib/banzai/renderer_spec.rb +++ b/spec/lib/banzai/renderer_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Banzai::Renderer do diff --git a/spec/lib/bitbucket/collection_spec.rb b/spec/lib/bitbucket/collection_spec.rb index 9008cb3e870..5946be71565 100644 --- a/spec/lib/bitbucket/collection_spec.rb +++ b/spec/lib/bitbucket/collection_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' # Emulates paginator. It returns 2 pages with results diff --git a/spec/lib/bitbucket/connection_spec.rb b/spec/lib/bitbucket/connection_spec.rb index 14faeb231a9..ec8eac232cd 100644 --- a/spec/lib/bitbucket/connection_spec.rb +++ b/spec/lib/bitbucket/connection_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Bitbucket::Connection do diff --git a/spec/lib/bitbucket/page_spec.rb b/spec/lib/bitbucket/page_spec.rb index 04d5a0470b1..6301dd56faf 100644 --- a/spec/lib/bitbucket/page_spec.rb +++ b/spec/lib/bitbucket/page_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Bitbucket::Page do diff --git a/spec/lib/bitbucket/paginator_spec.rb b/spec/lib/bitbucket/paginator_spec.rb index bdf10a5e2a2..a1effa14000 100644 --- a/spec/lib/bitbucket/paginator_spec.rb +++ b/spec/lib/bitbucket/paginator_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Bitbucket::Paginator do diff --git a/spec/lib/bitbucket/representation/comment_spec.rb b/spec/lib/bitbucket/representation/comment_spec.rb index fec243a9f96..2dcc933ee61 100644 --- a/spec/lib/bitbucket/representation/comment_spec.rb +++ b/spec/lib/bitbucket/representation/comment_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Bitbucket::Representation::Comment do diff --git a/spec/lib/bitbucket/representation/issue_spec.rb b/spec/lib/bitbucket/representation/issue_spec.rb index 20f47224aa8..c7d1ebdd597 100644 --- a/spec/lib/bitbucket/representation/issue_spec.rb +++ b/spec/lib/bitbucket/representation/issue_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Bitbucket::Representation::Issue do diff --git a/spec/lib/bitbucket/representation/pull_request_comment_spec.rb b/spec/lib/bitbucket/representation/pull_request_comment_spec.rb index 673dcf22ce8..151055f510f 100644 --- a/spec/lib/bitbucket/representation/pull_request_comment_spec.rb +++ b/spec/lib/bitbucket/representation/pull_request_comment_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Bitbucket::Representation::PullRequestComment do diff --git a/spec/lib/bitbucket/representation/pull_request_spec.rb b/spec/lib/bitbucket/representation/pull_request_spec.rb index 30453528be4..7cf43b2b6fd 100644 --- a/spec/lib/bitbucket/representation/pull_request_spec.rb +++ b/spec/lib/bitbucket/representation/pull_request_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Bitbucket::Representation::PullRequest do diff --git a/spec/lib/bitbucket/representation/repo_spec.rb b/spec/lib/bitbucket/representation/repo_spec.rb index 405265cc669..a272695e681 100644 --- a/spec/lib/bitbucket/representation/repo_spec.rb +++ b/spec/lib/bitbucket/representation/repo_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Bitbucket::Representation::Repo do diff --git a/spec/lib/bitbucket/representation/user_spec.rb b/spec/lib/bitbucket/representation/user_spec.rb index f79ff4edb7b..0169887a24c 100644 --- a/spec/lib/bitbucket/representation/user_spec.rb +++ b/spec/lib/bitbucket/representation/user_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Bitbucket::Representation::User do diff --git a/spec/lib/bitbucket_server/client_spec.rb b/spec/lib/bitbucket_server/client_spec.rb index 4f0d57ca8a6..988710b7c4d 100644 --- a/spec/lib/bitbucket_server/client_spec.rb +++ b/spec/lib/bitbucket_server/client_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe BitbucketServer::Client do diff --git a/spec/lib/bitbucket_server/connection_spec.rb b/spec/lib/bitbucket_server/connection_spec.rb index ab8a5b89608..3a7fe4e7321 100644 --- a/spec/lib/bitbucket_server/connection_spec.rb +++ b/spec/lib/bitbucket_server/connection_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe BitbucketServer::Connection do diff --git a/spec/lib/bitbucket_server/page_spec.rb b/spec/lib/bitbucket_server/page_spec.rb index cf419a9045b..2da1d0995ca 100644 --- a/spec/lib/bitbucket_server/page_spec.rb +++ b/spec/lib/bitbucket_server/page_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe BitbucketServer::Page do diff --git a/spec/lib/bitbucket_server/paginator_spec.rb b/spec/lib/bitbucket_server/paginator_spec.rb index eadd7f68bfb..e01cbeb4270 100644 --- a/spec/lib/bitbucket_server/paginator_spec.rb +++ b/spec/lib/bitbucket_server/paginator_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe BitbucketServer::Paginator do diff --git a/spec/lib/bitbucket_server/representation/activity_spec.rb b/spec/lib/bitbucket_server/representation/activity_spec.rb index 15c50e40472..b548dedadfb 100644 --- a/spec/lib/bitbucket_server/representation/activity_spec.rb +++ b/spec/lib/bitbucket_server/representation/activity_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe BitbucketServer::Representation::Activity do diff --git a/spec/lib/bitbucket_server/representation/comment_spec.rb b/spec/lib/bitbucket_server/representation/comment_spec.rb index 53a20a1d80a..f8c73c3da35 100644 --- a/spec/lib/bitbucket_server/representation/comment_spec.rb +++ b/spec/lib/bitbucket_server/representation/comment_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe BitbucketServer::Representation::Comment do diff --git a/spec/lib/bitbucket_server/representation/pull_request_comment_spec.rb b/spec/lib/bitbucket_server/representation/pull_request_comment_spec.rb index bd7e3597486..db43e990812 100644 --- a/spec/lib/bitbucket_server/representation/pull_request_comment_spec.rb +++ b/spec/lib/bitbucket_server/representation/pull_request_comment_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe BitbucketServer::Representation::PullRequestComment do diff --git a/spec/lib/bitbucket_server/representation/pull_request_spec.rb b/spec/lib/bitbucket_server/representation/pull_request_spec.rb index 4b8afdb006b..e091890041e 100644 --- a/spec/lib/bitbucket_server/representation/pull_request_spec.rb +++ b/spec/lib/bitbucket_server/representation/pull_request_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe BitbucketServer::Representation::PullRequest do diff --git a/spec/lib/bitbucket_server/representation/repo_spec.rb b/spec/lib/bitbucket_server/representation/repo_spec.rb index 3ac1030fbb0..801de247d73 100644 --- a/spec/lib/bitbucket_server/representation/repo_spec.rb +++ b/spec/lib/bitbucket_server/representation/repo_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe BitbucketServer::Representation::Repo do diff --git a/spec/lib/constraints/feature_constrainer_spec.rb b/spec/lib/constraints/feature_constrainer_spec.rb index 42efc164f81..0739da801a7 100644 --- a/spec/lib/constraints/feature_constrainer_spec.rb +++ b/spec/lib/constraints/feature_constrainer_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Constraints::FeatureConstrainer do diff --git a/spec/lib/constraints/group_url_constrainer_spec.rb b/spec/lib/constraints/group_url_constrainer_spec.rb index ff295068ba9..573de331898 100644 --- a/spec/lib/constraints/group_url_constrainer_spec.rb +++ b/spec/lib/constraints/group_url_constrainer_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Constraints::GroupUrlConstrainer do diff --git a/spec/lib/constraints/project_url_constrainer_spec.rb b/spec/lib/constraints/project_url_constrainer_spec.rb index 3496b01ebcc..ac3221ecab7 100644 --- a/spec/lib/constraints/project_url_constrainer_spec.rb +++ b/spec/lib/constraints/project_url_constrainer_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Constraints::ProjectUrlConstrainer do diff --git a/spec/lib/constraints/user_url_constrainer_spec.rb b/spec/lib/constraints/user_url_constrainer_spec.rb index e2c85bb27bb..15ef930420c 100644 --- a/spec/lib/constraints/user_url_constrainer_spec.rb +++ b/spec/lib/constraints/user_url_constrainer_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Constraints::UserUrlConstrainer do diff --git a/spec/lib/container_registry/blob_spec.rb b/spec/lib/container_registry/blob_spec.rb index d3fff5bad42..be7be2f3719 100644 --- a/spec/lib/container_registry/blob_spec.rb +++ b/spec/lib/container_registry/blob_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe ContainerRegistry::Blob do @@ -110,11 +112,28 @@ describe ContainerRegistry::Blob do end end + context 'for a relative address' do + before do + stub_request(:get, 'http://registry.gitlab/relative') + .with { |request| !request.headers.include?('Authorization') } + .to_return( + status: 200, + headers: { 'Content-Type' => 'application/json' }, + body: '{"key":"value"}') + end + + let(:location) { '/relative' } + + it 'returns correct data' do + expect(blob.data).to eq '{"key":"value"}' + end + end + context 'for invalid file' do let(:location) { 'file:///etc/passwd' } it 'raises an error' do - expect { blob.data }.to raise_error(ArgumentError, 'invalid address') + expect { blob.data }.to raise_error(ArgumentError, 'Invalid scheme for file:///etc/passwd') end end end diff --git a/spec/lib/container_registry/client_spec.rb b/spec/lib/container_registry/client_spec.rb index 3df33f48adb..bc5fddd12ba 100644 --- a/spec/lib/container_registry/client_spec.rb +++ b/spec/lib/container_registry/client_spec.rb @@ -1,4 +1,6 @@ # coding: utf-8 +# frozen_string_literal: true + require 'spec_helper' describe ContainerRegistry::Client do @@ -6,6 +8,42 @@ describe ContainerRegistry::Client do let(:options) { { token: token } } let(:client) { described_class.new("http://container-registry", options) } + shared_examples '#repository_manifest' do |manifest_type| + let(:manifest) do + { + "schemaVersion" => 2, + "config" => { + "mediaType" => manifest_type, + "digest" => + "sha256:4a3ef0786dd241be6000311e1503869b320be433b9cba84cfafeb512d1720c95", + "size" => 6608 + }, + "layers" => [ + { + "mediaType" => manifest_type, + "digest" => + "sha256:83ef92b73cf4595aa7fe214ec6747228283d585f373d8f6bc08d66bebab531b7", + "size" => 2828661 + } + ] + } + end + + it 'GET /v2/:name/manifests/mytag' do + stub_request(:get, "http://container-registry/v2/group/test/manifests/mytag") + .with(headers: { + 'Accept' => described_class::ACCEPTED_TYPES.join(', '), + 'Authorization' => "bearer #{token}" + }) + .to_return(status: 200, body: manifest.to_json, headers: { content_type: manifest_type }) + + expect(client.repository_manifest('group/test', 'mytag')).to eq(manifest) + end + end + + it_behaves_like '#repository_manifest', described_class::DOCKER_DISTRIBUTION_MANIFEST_V2_TYPE + it_behaves_like '#repository_manifest', described_class::OCI_MANIFEST_V1_TYPE + describe '#blob' do it 'GET /v2/:name/blobs/:digest' do stub_request(:get, "http://container-registry/v2/group/test/blobs/sha256:0123456789012345") diff --git a/spec/lib/container_registry/path_spec.rb b/spec/lib/container_registry/path_spec.rb index 010deae822c..8c671b4d56d 100644 --- a/spec/lib/container_registry/path_spec.rb +++ b/spec/lib/container_registry/path_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe ContainerRegistry::Path do diff --git a/spec/lib/container_registry/registry_spec.rb b/spec/lib/container_registry/registry_spec.rb index 4d6eea94bf0..7cf70a1f562 100644 --- a/spec/lib/container_registry/registry_spec.rb +++ b/spec/lib/container_registry/registry_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe ContainerRegistry::Registry do diff --git a/spec/lib/container_registry/tag_spec.rb b/spec/lib/container_registry/tag_spec.rb index cb4ae3be525..110f006536b 100644 --- a/spec/lib/container_registry/tag_spec.rb +++ b/spec/lib/container_registry/tag_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe ContainerRegistry::Tag do @@ -9,7 +11,7 @@ describe ContainerRegistry::Tag do end let(:headers) do - { 'Accept' => 'application/vnd.docker.distribution.manifest.v2+json' } + { 'Accept' => ContainerRegistry::Client::ACCEPTED_TYPES.join(', ') } end let(:tag) { described_class.new(repository, 'tag') } diff --git a/spec/lib/event_filter_spec.rb b/spec/lib/event_filter_spec.rb index 6648e141b7a..d6eca8d85ff 100644 --- a/spec/lib/event_filter_spec.rb +++ b/spec/lib/event_filter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe EventFilter do diff --git a/spec/lib/expand_variables_spec.rb b/spec/lib/expand_variables_spec.rb index 7faa0f31b68..099d7b6b67c 100644 --- a/spec/lib/expand_variables_spec.rb +++ b/spec/lib/expand_variables_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe ExpandVariables do diff --git a/spec/lib/extracts_path_spec.rb b/spec/lib/extracts_path_spec.rb index 21ba72953fb..ffe7584a019 100644 --- a/spec/lib/extracts_path_spec.rb +++ b/spec/lib/extracts_path_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe ExtractsPath do diff --git a/spec/lib/feature/gitaly_spec.rb b/spec/lib/feature/gitaly_spec.rb index 0e24a927d4c..4e07acf9c1a 100644 --- a/spec/lib/feature/gitaly_spec.rb +++ b/spec/lib/feature/gitaly_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Feature::Gitaly do diff --git a/spec/lib/feature_spec.rb b/spec/lib/feature_spec.rb index 127463a57e8..185abacf8e7 100644 --- a/spec/lib/feature_spec.rb +++ b/spec/lib/feature_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Feature do diff --git a/spec/lib/file_size_validator_spec.rb b/spec/lib/file_size_validator_spec.rb index ebd907ecb7f..87376a98c60 100644 --- a/spec/lib/file_size_validator_spec.rb +++ b/spec/lib/file_size_validator_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe FileSizeValidator do diff --git a/spec/lib/forever_spec.rb b/spec/lib/forever_spec.rb index 800fa5a6ad6..9f17308241b 100644 --- a/spec/lib/forever_spec.rb +++ b/spec/lib/forever_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Forever do diff --git a/spec/lib/gitaly/server_spec.rb b/spec/lib/gitaly/server_spec.rb index 34bd43cb3ab..12dfad6698d 100644 --- a/spec/lib/gitaly/server_spec.rb +++ b/spec/lib/gitaly/server_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitaly::Server do diff --git a/spec/lib/gitlab/action_rate_limiter_spec.rb b/spec/lib/gitlab/action_rate_limiter_spec.rb index 542fc03e555..8dbad32dfb4 100644 --- a/spec/lib/gitlab/action_rate_limiter_spec.rb +++ b/spec/lib/gitlab/action_rate_limiter_spec.rb @@ -1,11 +1,11 @@ +# frozen_string_literal: true + require 'spec_helper' -describe Gitlab::ActionRateLimiter do +describe Gitlab::ActionRateLimiter, :clean_gitlab_redis_cache do let(:redis) { double('redis') } let(:user) { create(:user) } let(:project) { create(:project) } - let(:key) { [user, project] } - let(:cache_key) { "action_rate_limiter:test_action:user:#{user.id}:project:#{project.id}" } subject { described_class.new(action: :test_action, expiry_time: 100) } @@ -13,17 +13,98 @@ describe Gitlab::ActionRateLimiter do allow(Gitlab::Redis::Cache).to receive(:with).and_yield(redis) end - it 'increases the throttle count and sets the expire time' do - expect(redis).to receive(:incr).with(cache_key).and_return(1) - expect(redis).to receive(:expire).with(cache_key, 100) + shared_examples 'action rate limiter' do + it 'increases the throttle count and sets the expiration time' do + expect(redis).to receive(:incr).with(cache_key).and_return(1) + expect(redis).to receive(:expire).with(cache_key, 100) + + expect(subject.throttled?(key, 1)).to be_falsy + end + + it 'returns true if the key is throttled' do + expect(redis).to receive(:incr).with(cache_key).and_return(2) + expect(redis).not_to receive(:expire) - expect(subject.throttled?(key, 1)).to be false + expect(subject.throttled?(key, 1)).to be_truthy + end + + context 'when throttling is disabled' do + it 'returns false and does not set expiration time' do + expect(redis).not_to receive(:incr) + expect(redis).not_to receive(:expire) + + expect(subject.throttled?(key, 0)).to be_falsy + end + end end - it 'returns true if the key is throttled' do - expect(redis).to receive(:incr).with(cache_key).and_return(2) - expect(redis).not_to receive(:expire) + context 'when the key is an array of only ActiveRecord models' do + let(:key) { [user, project] } + + let(:cache_key) do + "action_rate_limiter:test_action:user:#{user.id}:project:#{project.id}" + end + + it_behaves_like 'action rate limiter' + end + + context 'when they key a combination of ActiveRecord models and strings' do + let(:project) { create(:project, :public, :repository) } + let(:commit) { project.repository.commit } + let(:path) { 'app/controllers/groups_controller.rb' } + let(:key) { [project, commit, path] } + + let(:cache_key) do + "action_rate_limiter:test_action:project:#{project.id}:commit:#{commit.sha}:#{path}" + end + + it_behaves_like 'action rate limiter' + end + + describe '#log_request' do + let(:file_path) { 'master/README.md' } + let(:type) { :raw_blob_request_limit } + let(:fullpath) { "/#{project.full_path}/raw/#{file_path}" } + + let(:request) do + double('request', ip: '127.0.0.1', request_method: 'GET', fullpath: fullpath) + end + + let(:base_attributes) do + { + message: 'Action_Rate_Limiter_Request', + env: type, + ip: '127.0.0.1', + request_method: 'GET', + fullpath: fullpath + } + end + + context 'without a current user' do + let(:current_user) { nil } + + it 'logs information to auth.log' do + expect(Gitlab::AuthLogger).to receive(:error).with(base_attributes).once + + subject.log_request(request, type, current_user) + end + end + + context 'with a current_user' do + let(:current_user) { create(:user) } + + let(:attributes) do + base_attributes.merge({ + user_id: current_user.id, + username: current_user.username + }) + end + + it 'logs information to auth.log' do + expect(Gitlab::AuthLogger).to receive(:error).with(attributes).once - expect(subject.throttled?(key, 1)).to be true + subject.log_request(request, type, current_user) + end + end end end diff --git a/spec/lib/gitlab/allowable_spec.rb b/spec/lib/gitlab/allowable_spec.rb index 9d80d480b52..4905cc4c3db 100644 --- a/spec/lib/gitlab/allowable_spec.rb +++ b/spec/lib/gitlab/allowable_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Allowable do diff --git a/spec/lib/gitlab/app_logger_spec.rb b/spec/lib/gitlab/app_logger_spec.rb index c86d30ce6df..3b21104b15d 100644 --- a/spec/lib/gitlab/app_logger_spec.rb +++ b/spec/lib/gitlab/app_logger_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::AppLogger, :request_store do diff --git a/spec/lib/gitlab/asciidoc_spec.rb b/spec/lib/gitlab/asciidoc_spec.rb index cbd4a509a55..7c65525b8dc 100644 --- a/spec/lib/gitlab/asciidoc_spec.rb +++ b/spec/lib/gitlab/asciidoc_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' require 'nokogiri' diff --git a/spec/lib/gitlab/auth/activity_spec.rb b/spec/lib/gitlab/auth/activity_spec.rb index 07854cb1eba..e03fafe3826 100644 --- a/spec/lib/gitlab/auth/activity_spec.rb +++ b/spec/lib/gitlab/auth/activity_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'fast_spec_helper' describe Gitlab::Auth::Activity do diff --git a/spec/lib/gitlab/auth/blocked_user_tracker_spec.rb b/spec/lib/gitlab/auth/blocked_user_tracker_spec.rb index f39863fdda1..52849f8c172 100644 --- a/spec/lib/gitlab/auth/blocked_user_tracker_spec.rb +++ b/spec/lib/gitlab/auth/blocked_user_tracker_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Auth::BlockedUserTracker do diff --git a/spec/lib/gitlab/auth/ldap/access_spec.rb b/spec/lib/gitlab/auth/ldap/access_spec.rb index 662f899180b..ecdd5b29986 100644 --- a/spec/lib/gitlab/auth/ldap/access_spec.rb +++ b/spec/lib/gitlab/auth/ldap/access_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Auth::LDAP::Access do diff --git a/spec/lib/gitlab/auth/ldap/adapter_spec.rb b/spec/lib/gitlab/auth/ldap/adapter_spec.rb index 3eeaf3862f6..54486913b72 100644 --- a/spec/lib/gitlab/auth/ldap/adapter_spec.rb +++ b/spec/lib/gitlab/auth/ldap/adapter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Auth::LDAP::Adapter do diff --git a/spec/lib/gitlab/auth/ldap/authentication_spec.rb b/spec/lib/gitlab/auth/ldap/authentication_spec.rb index 111572d043b..e68e83e4617 100644 --- a/spec/lib/gitlab/auth/ldap/authentication_spec.rb +++ b/spec/lib/gitlab/auth/ldap/authentication_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Auth::LDAP::Authentication do diff --git a/spec/lib/gitlab/auth/ldap/config_spec.rb b/spec/lib/gitlab/auth/ldap/config_spec.rb index b91a09e3137..577dfe51949 100644 --- a/spec/lib/gitlab/auth/ldap/config_spec.rb +++ b/spec/lib/gitlab/auth/ldap/config_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Auth::LDAP::Config do diff --git a/spec/lib/gitlab/auth/ldap/dn_spec.rb b/spec/lib/gitlab/auth/ldap/dn_spec.rb index f2983a02602..63656efba29 100644 --- a/spec/lib/gitlab/auth/ldap/dn_spec.rb +++ b/spec/lib/gitlab/auth/ldap/dn_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Auth::LDAP::DN do diff --git a/spec/lib/gitlab/auth/ldap/user_spec.rb b/spec/lib/gitlab/auth/ldap/user_spec.rb index 44bb9d20e47..bc09de7b525 100644 --- a/spec/lib/gitlab/auth/ldap/user_spec.rb +++ b/spec/lib/gitlab/auth/ldap/user_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Auth::LDAP::User do diff --git a/spec/lib/gitlab/auth/o_auth/auth_hash_spec.rb b/spec/lib/gitlab/auth/o_auth/auth_hash_spec.rb index 40001cea22e..a2d9e27ea5b 100644 --- a/spec/lib/gitlab/auth/o_auth/auth_hash_spec.rb +++ b/spec/lib/gitlab/auth/o_auth/auth_hash_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Auth::OAuth::AuthHash do @@ -13,13 +15,13 @@ describe Gitlab::Auth::OAuth::AuthHash do end let(:uid_raw) do - "CN=Onur K\xC3\xBC\xC3\xA7\xC3\xBCk,OU=Test,DC=example,DC=net" + +"CN=Onur K\xC3\xBC\xC3\xA7\xC3\xBCk,OU=Test,DC=example,DC=net" end - let(:email_raw) { "onur.k\xC3\xBC\xC3\xA7\xC3\xBCk_ABC-123@example.net" } - let(:nickname_raw) { "ok\xC3\xBC\xC3\xA7\xC3\xBCk" } - let(:first_name_raw) { 'Onur' } - let(:last_name_raw) { "K\xC3\xBC\xC3\xA7\xC3\xBCk" } - let(:name_raw) { "Onur K\xC3\xBC\xC3\xA7\xC3\xBCk" } + let(:email_raw) { +"onur.k\xC3\xBC\xC3\xA7\xC3\xBCk_ABC-123@example.net" } + let(:nickname_raw) { +"ok\xC3\xBC\xC3\xA7\xC3\xBCk" } + let(:first_name_raw) { +'Onur' } + let(:last_name_raw) { +"K\xC3\xBC\xC3\xA7\xC3\xBCk" } + let(:name_raw) { +"Onur K\xC3\xBC\xC3\xA7\xC3\xBCk" } let(:uid_ascii) { uid_raw.force_encoding(Encoding::ASCII_8BIT) } let(:email_ascii) { email_raw.force_encoding(Encoding::ASCII_8BIT) } @@ -40,7 +42,11 @@ describe Gitlab::Auth::OAuth::AuthHash do last_name: last_name_ascii, name: name_ascii, nickname: nickname_ascii, - uid: uid_ascii + uid: uid_ascii, + address: { + locality: 'some locality', + country: 'some country' + } } end @@ -51,6 +57,7 @@ describe Gitlab::Auth::OAuth::AuthHash do it { expect(auth_hash.username).to eql nickname_utf8 } it { expect(auth_hash.name).to eql name_utf8 } it { expect(auth_hash.password).not_to be_empty } + it { expect(auth_hash.location).to eq 'some locality, some country' } end context 'email not provided' do diff --git a/spec/lib/gitlab/auth/o_auth/identity_linker_spec.rb b/spec/lib/gitlab/auth/o_auth/identity_linker_spec.rb index bf810d72f0e..45c1baa4089 100644 --- a/spec/lib/gitlab/auth/o_auth/identity_linker_spec.rb +++ b/spec/lib/gitlab/auth/o_auth/identity_linker_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Auth::OAuth::IdentityLinker do diff --git a/spec/lib/gitlab/auth/o_auth/provider_spec.rb b/spec/lib/gitlab/auth/o_auth/provider_spec.rb index 80d702cf9dc..f46f9d76a1e 100644 --- a/spec/lib/gitlab/auth/o_auth/provider_spec.rb +++ b/spec/lib/gitlab/auth/o_auth/provider_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Auth::OAuth::Provider do diff --git a/spec/lib/gitlab/auth/o_auth/user_spec.rb b/spec/lib/gitlab/auth/o_auth/user_spec.rb index b765c265e69..a9b15c411dc 100644 --- a/spec/lib/gitlab/auth/o_auth/user_spec.rb +++ b/spec/lib/gitlab/auth/o_auth/user_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Auth::OAuth::User do diff --git a/spec/lib/gitlab/auth/request_authenticator_spec.rb b/spec/lib/gitlab/auth/request_authenticator_spec.rb index 3d979132880..f7fff389d88 100644 --- a/spec/lib/gitlab/auth/request_authenticator_spec.rb +++ b/spec/lib/gitlab/auth/request_authenticator_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Auth::RequestAuthenticator do diff --git a/spec/lib/gitlab/auth/saml/auth_hash_spec.rb b/spec/lib/gitlab/auth/saml/auth_hash_spec.rb index 3620e1afe25..13636a495d1 100644 --- a/spec/lib/gitlab/auth/saml/auth_hash_spec.rb +++ b/spec/lib/gitlab/auth/saml/auth_hash_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Auth::Saml::AuthHash do diff --git a/spec/lib/gitlab/auth/saml/identity_linker_spec.rb b/spec/lib/gitlab/auth/saml/identity_linker_spec.rb index f3305d574cc..89118ff05ba 100644 --- a/spec/lib/gitlab/auth/saml/identity_linker_spec.rb +++ b/spec/lib/gitlab/auth/saml/identity_linker_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Auth::Saml::IdentityLinker do diff --git a/spec/lib/gitlab/auth/saml/user_spec.rb b/spec/lib/gitlab/auth/saml/user_spec.rb index c523f5e177f..5546438b7ee 100644 --- a/spec/lib/gitlab/auth/saml/user_spec.rb +++ b/spec/lib/gitlab/auth/saml/user_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Auth::Saml::User do diff --git a/spec/lib/gitlab/auth/unique_ips_limiter_spec.rb b/spec/lib/gitlab/auth/unique_ips_limiter_spec.rb index 22708687a56..ebf7de9c701 100644 --- a/spec/lib/gitlab/auth/unique_ips_limiter_spec.rb +++ b/spec/lib/gitlab/auth/unique_ips_limiter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Auth::UniqueIpsLimiter, :clean_gitlab_redis_shared_state do diff --git a/spec/lib/gitlab/auth/user_access_denied_reason_spec.rb b/spec/lib/gitlab/auth/user_access_denied_reason_spec.rb index 002ce776be9..8ec19c454d8 100644 --- a/spec/lib/gitlab/auth/user_access_denied_reason_spec.rb +++ b/spec/lib/gitlab/auth/user_access_denied_reason_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Auth::UserAccessDeniedReason do diff --git a/spec/lib/gitlab/auth/user_auth_finders_spec.rb b/spec/lib/gitlab/auth/user_auth_finders_spec.rb index 4751f880cee..41265da97a4 100644 --- a/spec/lib/gitlab/auth/user_auth_finders_spec.rb +++ b/spec/lib/gitlab/auth/user_auth_finders_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Auth::UserAuthFinders do diff --git a/spec/lib/gitlab/auth_spec.rb b/spec/lib/gitlab/auth_spec.rb index 0403830f700..edff38f05ec 100644 --- a/spec/lib/gitlab/auth_spec.rb +++ b/spec/lib/gitlab/auth_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Auth do diff --git a/spec/lib/gitlab/background_migration/add_merge_request_diff_commits_count_spec.rb b/spec/lib/gitlab/background_migration/add_merge_request_diff_commits_count_spec.rb index c43ed72038e..e299e2a366f 100644 --- a/spec/lib/gitlab/background_migration/add_merge_request_diff_commits_count_spec.rb +++ b/spec/lib/gitlab/background_migration/add_merge_request_diff_commits_count_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::BackgroundMigration::AddMergeRequestDiffCommitsCount, :migration, schema: 20180105212544 do diff --git a/spec/lib/gitlab/background_migration/archive_legacy_traces_spec.rb b/spec/lib/gitlab/background_migration/archive_legacy_traces_spec.rb index 877c061d11b..2a7cffb2f3e 100644 --- a/spec/lib/gitlab/background_migration/archive_legacy_traces_spec.rb +++ b/spec/lib/gitlab/background_migration/archive_legacy_traces_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::BackgroundMigration::ArchiveLegacyTraces, :migration, schema: 20180529152628 do diff --git a/spec/lib/gitlab/background_migration/encrypt_columns_spec.rb b/spec/lib/gitlab/background_migration/encrypt_columns_spec.rb index 1d9bac79dcd..3c2ed6d3a6d 100644 --- a/spec/lib/gitlab/background_migration/encrypt_columns_spec.rb +++ b/spec/lib/gitlab/background_migration/encrypt_columns_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::BackgroundMigration::EncryptColumns, :migration, schema: 20180910115836 do diff --git a/spec/lib/gitlab/background_migration/encrypt_runners_tokens_spec.rb b/spec/lib/gitlab/background_migration/encrypt_runners_tokens_spec.rb index 9d4921968b3..54af9807e7b 100644 --- a/spec/lib/gitlab/background_migration/encrypt_runners_tokens_spec.rb +++ b/spec/lib/gitlab/background_migration/encrypt_runners_tokens_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::BackgroundMigration::EncryptRunnersTokens, :migration, schema: 20181121111200 do diff --git a/spec/lib/gitlab/background_migration/fix_cross_project_label_links_spec.rb b/spec/lib/gitlab/background_migration/fix_cross_project_label_links_spec.rb index 20af63bc6c8..f3127cbf5df 100644 --- a/spec/lib/gitlab/background_migration/fix_cross_project_label_links_spec.rb +++ b/spec/lib/gitlab/background_migration/fix_cross_project_label_links_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::BackgroundMigration::FixCrossProjectLabelLinks, :migration, schema: 20180702120647 do @@ -75,7 +77,7 @@ describe Gitlab::BackgroundMigration::FixCrossProjectLabelLinks, :migration, sch create_resource(target_type, 1, 2) end - it 'ignores label links referencing ancestor group labels', :nested_groups do + it 'ignores label links referencing ancestor group labels' do labels_table.create(id: 4, title: 'bug', color: 'red', project_id: 2, type: 'ProjectLabel') label_links_table.create(label_id: 4, target_type: target_type, target_id: 1) link = label_links_table.create(label_id: 1, target_type: target_type, target_id: 1) @@ -85,7 +87,7 @@ describe Gitlab::BackgroundMigration::FixCrossProjectLabelLinks, :migration, sch expect(link.reload.label_id).to eq(1) end - it 'checks also issues and MRs in subgroups', :nested_groups do + it 'checks also issues and MRs in subgroups' do link = label_links_table.create(label_id: 2, target_type: target_type, target_id: 1) subject.perform(1, 100) diff --git a/spec/lib/gitlab/background_migration/migrate_build_stage_spec.rb b/spec/lib/gitlab/background_migration/migrate_build_stage_spec.rb index 582396275ed..a496f8416bf 100644 --- a/spec/lib/gitlab/background_migration/migrate_build_stage_spec.rb +++ b/spec/lib/gitlab/background_migration/migrate_build_stage_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::BackgroundMigration::MigrateBuildStage, :migration, schema: 20180212101928 do diff --git a/spec/lib/gitlab/background_migration/migrate_legacy_artifacts_spec.rb b/spec/lib/gitlab/background_migration/migrate_legacy_artifacts_spec.rb index 2d1505dacfe..268626d58fd 100644 --- a/spec/lib/gitlab/background_migration/migrate_legacy_artifacts_spec.rb +++ b/spec/lib/gitlab/background_migration/migrate_legacy_artifacts_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::BackgroundMigration::MigrateLegacyArtifacts, :migration, schema: 20180816161409 do diff --git a/spec/lib/gitlab/background_migration/migrate_stage_index_spec.rb b/spec/lib/gitlab/background_migration/migrate_stage_index_spec.rb index 4db829b1e7b..1a8b0355fd9 100644 --- a/spec/lib/gitlab/background_migration/migrate_stage_index_spec.rb +++ b/spec/lib/gitlab/background_migration/migrate_stage_index_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::BackgroundMigration::MigrateStageIndex, :migration, schema: 20180420080616 do diff --git a/spec/lib/gitlab/background_migration/populate_untracked_uploads_dependencies/untracked_file_spec.rb b/spec/lib/gitlab/background_migration/populate_untracked_uploads_dependencies/untracked_file_spec.rb index c76adcbe2f5..ea1eaa6417d 100644 --- a/spec/lib/gitlab/background_migration/populate_untracked_uploads_dependencies/untracked_file_spec.rb +++ b/spec/lib/gitlab/background_migration/populate_untracked_uploads_dependencies/untracked_file_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' # Rollback DB to 10.5 (later than this was originally written for) because it still needs to work. diff --git a/spec/lib/gitlab/background_migration/populate_untracked_uploads_spec.rb b/spec/lib/gitlab/background_migration/populate_untracked_uploads_spec.rb index 0dee683350f..44f537ca8dd 100644 --- a/spec/lib/gitlab/background_migration/populate_untracked_uploads_spec.rb +++ b/spec/lib/gitlab/background_migration/populate_untracked_uploads_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' # Rollback DB to 10.5 (later than this was originally written for) because it still needs to work. @@ -114,7 +116,7 @@ describe Gitlab::BackgroundMigration::PopulateUntrackedUploads, :sidekiq, :migra it 'does not drop the temporary tracking table after processing the batch, if there are still untracked rows' do subject.perform(1, untracked_files_for_uploads.last.id - 1) - expect(ActiveRecord::Base.connection.data_source_exists?(:untracked_files_for_uploads)).to be_truthy + expect(ActiveRecord::Base.connection.table_exists?(:untracked_files_for_uploads)).to be_truthy end it 'drops the temporary tracking table after processing the batch, if there are no untracked rows left' do diff --git a/spec/lib/gitlab/background_migration/prepare_untracked_uploads_spec.rb b/spec/lib/gitlab/background_migration/prepare_untracked_uploads_spec.rb index 35750d89c35..591368ee98e 100644 --- a/spec/lib/gitlab/background_migration/prepare_untracked_uploads_spec.rb +++ b/spec/lib/gitlab/background_migration/prepare_untracked_uploads_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' # Rollback DB to 10.5 (later than this was originally written for) because it still needs to work. diff --git a/spec/lib/gitlab/background_migration/schedule_calculate_wiki_sizes_spec.rb b/spec/lib/gitlab/background_migration/schedule_calculate_wiki_sizes_spec.rb index d494ce68c5b..f877e8cc1b8 100644 --- a/spec/lib/gitlab/background_migration/schedule_calculate_wiki_sizes_spec.rb +++ b/spec/lib/gitlab/background_migration/schedule_calculate_wiki_sizes_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' require Rails.root.join('db', 'post_migrate', '20190527194900_schedule_calculate_wiki_sizes.rb') diff --git a/spec/lib/gitlab/background_migration/set_confidential_note_events_on_services_spec.rb b/spec/lib/gitlab/background_migration/set_confidential_note_events_on_services_spec.rb index 6f3fb994f17..3600755ada7 100644 --- a/spec/lib/gitlab/background_migration/set_confidential_note_events_on_services_spec.rb +++ b/spec/lib/gitlab/background_migration/set_confidential_note_events_on_services_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::BackgroundMigration::SetConfidentialNoteEventsOnServices, :migration, schema: 20180122154930 do diff --git a/spec/lib/gitlab/background_migration/set_confidential_note_events_on_webhooks_spec.rb b/spec/lib/gitlab/background_migration/set_confidential_note_events_on_webhooks_spec.rb index 82b484b7d5b..5cd9c02fd3f 100644 --- a/spec/lib/gitlab/background_migration/set_confidential_note_events_on_webhooks_spec.rb +++ b/spec/lib/gitlab/background_migration/set_confidential_note_events_on_webhooks_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::BackgroundMigration::SetConfidentialNoteEventsOnWebhooks, :migration, schema: 20180104131052 do diff --git a/spec/lib/gitlab/background_migration_spec.rb b/spec/lib/gitlab/background_migration_spec.rb index 1d0ffb5e9df..8960ac706e6 100644 --- a/spec/lib/gitlab/background_migration_spec.rb +++ b/spec/lib/gitlab/background_migration_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::BackgroundMigration do diff --git a/spec/lib/gitlab/badge/coverage/metadata_spec.rb b/spec/lib/gitlab/badge/coverage/metadata_spec.rb index 74eaf7eaf8b..2b87508bdef 100644 --- a/spec/lib/gitlab/badge/coverage/metadata_spec.rb +++ b/spec/lib/gitlab/badge/coverage/metadata_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' require 'lib/gitlab/badge/shared/metadata' diff --git a/spec/lib/gitlab/badge/coverage/report_spec.rb b/spec/lib/gitlab/badge/coverage/report_spec.rb index da789bf3705..eee3f96ab85 100644 --- a/spec/lib/gitlab/badge/coverage/report_spec.rb +++ b/spec/lib/gitlab/badge/coverage/report_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Badge::Coverage::Report do diff --git a/spec/lib/gitlab/badge/coverage/template_spec.rb b/spec/lib/gitlab/badge/coverage/template_spec.rb index d9c21a22590..b51d707a61d 100644 --- a/spec/lib/gitlab/badge/coverage/template_spec.rb +++ b/spec/lib/gitlab/badge/coverage/template_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Badge::Coverage::Template do diff --git a/spec/lib/gitlab/badge/pipeline/metadata_spec.rb b/spec/lib/gitlab/badge/pipeline/metadata_spec.rb index 9032a8e9016..b096803f921 100644 --- a/spec/lib/gitlab/badge/pipeline/metadata_spec.rb +++ b/spec/lib/gitlab/badge/pipeline/metadata_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' require 'lib/gitlab/badge/shared/metadata' diff --git a/spec/lib/gitlab/badge/pipeline/status_spec.rb b/spec/lib/gitlab/badge/pipeline/status_spec.rb index dc835375c66..684c6829879 100644 --- a/spec/lib/gitlab/badge/pipeline/status_spec.rb +++ b/spec/lib/gitlab/badge/pipeline/status_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Badge::Pipeline::Status do diff --git a/spec/lib/gitlab/badge/pipeline/template_spec.rb b/spec/lib/gitlab/badge/pipeline/template_spec.rb index bcef0b7e120..c0aaa3d73e1 100644 --- a/spec/lib/gitlab/badge/pipeline/template_spec.rb +++ b/spec/lib/gitlab/badge/pipeline/template_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Badge::Pipeline::Template do diff --git a/spec/lib/gitlab/badge/shared/metadata.rb b/spec/lib/gitlab/badge/shared/metadata.rb index 63c7ca5a915..809fa54db02 100644 --- a/spec/lib/gitlab/badge/shared/metadata.rb +++ b/spec/lib/gitlab/badge/shared/metadata.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples 'badge metadata' do describe '#to_html' do let(:html) { Nokogiri::HTML.parse(metadata.to_html) } diff --git a/spec/lib/gitlab/bare_repository_import/importer_spec.rb b/spec/lib/gitlab/bare_repository_import/importer_spec.rb index f4759b69538..0c1eedad7f4 100644 --- a/spec/lib/gitlab/bare_repository_import/importer_spec.rb +++ b/spec/lib/gitlab/bare_repository_import/importer_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::BareRepositoryImport::Importer, :seed_helper do @@ -103,7 +105,7 @@ describe Gitlab::BareRepositoryImport::Importer, :seed_helper do end end - context 'with subgroups', :nested_groups do + context 'with subgroups' do let(:project_path) { 'a-group/a-sub-group/a-project' } let(:existing_group) do @@ -188,20 +190,6 @@ describe Gitlab::BareRepositoryImport::Importer, :seed_helper do end end - context 'when subgroups are not available' do - let(:project_path) { 'a-group/a-sub-group/a-project' } - - before do - expect(Group).to receive(:supports_nested_objects?) { false } - end - - describe '#create_project_if_needed' do - it 'raises an error' do - expect { importer.create_project_if_needed }.to raise_error('Nested groups are not supported on MySQL') - end - end - end - def prepare_repository(project_path, source_project) repo_path = File.join(base_dir, project_path) diff --git a/spec/lib/gitlab/bare_repository_import/repository_spec.rb b/spec/lib/gitlab/bare_repository_import/repository_spec.rb index a07c5371134..0607e2232a1 100644 --- a/spec/lib/gitlab/bare_repository_import/repository_spec.rb +++ b/spec/lib/gitlab/bare_repository_import/repository_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe ::Gitlab::BareRepositoryImport::Repository do diff --git a/spec/lib/gitlab/bitbucket_import/importer_spec.rb b/spec/lib/gitlab/bitbucket_import/importer_spec.rb index 35700e0b588..62b688d4d3e 100644 --- a/spec/lib/gitlab/bitbucket_import/importer_spec.rb +++ b/spec/lib/gitlab/bitbucket_import/importer_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::BitbucketImport::Importer do diff --git a/spec/lib/gitlab/bitbucket_import/project_creator_spec.rb b/spec/lib/gitlab/bitbucket_import/project_creator_spec.rb index e2bee22cf1f..0dd8547a925 100644 --- a/spec/lib/gitlab/bitbucket_import/project_creator_spec.rb +++ b/spec/lib/gitlab/bitbucket_import/project_creator_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::BitbucketImport::ProjectCreator do diff --git a/spec/lib/gitlab/bitbucket_import/wiki_formatter_spec.rb b/spec/lib/gitlab/bitbucket_import/wiki_formatter_spec.rb index 795fd069ab2..7b5c7847f2d 100644 --- a/spec/lib/gitlab/bitbucket_import/wiki_formatter_spec.rb +++ b/spec/lib/gitlab/bitbucket_import/wiki_formatter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::BitbucketImport::WikiFormatter do diff --git a/spec/lib/gitlab/bitbucket_server_import/importer_spec.rb b/spec/lib/gitlab/bitbucket_server_import/importer_spec.rb index cc09804fd53..8ab7b2c5fa7 100644 --- a/spec/lib/gitlab/bitbucket_server_import/importer_spec.rb +++ b/spec/lib/gitlab/bitbucket_server_import/importer_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::BitbucketServerImport::Importer do diff --git a/spec/lib/gitlab/blame_spec.rb b/spec/lib/gitlab/blame_spec.rb index 7cab04e9fc9..e1afd5b25bb 100644 --- a/spec/lib/gitlab/blame_spec.rb +++ b/spec/lib/gitlab/blame_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Blame do diff --git a/spec/lib/gitlab/build_access_spec.rb b/spec/lib/gitlab/build_access_spec.rb index 08f50bf4fac..b7af8ace5b5 100644 --- a/spec/lib/gitlab/build_access_spec.rb +++ b/spec/lib/gitlab/build_access_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::BuildAccess do diff --git a/spec/lib/gitlab/cache/ci/project_pipeline_status_spec.rb b/spec/lib/gitlab/cache/ci/project_pipeline_status_spec.rb index 483c5ea9cff..91e7edaf704 100644 --- a/spec/lib/gitlab/cache/ci/project_pipeline_status_spec.rb +++ b/spec/lib/gitlab/cache/ci/project_pipeline_status_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Cache::Ci::ProjectPipelineStatus, :clean_gitlab_redis_cache do diff --git a/spec/lib/gitlab/cache/request_cache_spec.rb b/spec/lib/gitlab/cache/request_cache_spec.rb index 5b82c216a13..70a7f090d0a 100644 --- a/spec/lib/gitlab/cache/request_cache_spec.rb +++ b/spec/lib/gitlab/cache/request_cache_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Cache::RequestCache do diff --git a/spec/lib/gitlab/changes_list_spec.rb b/spec/lib/gitlab/changes_list_spec.rb index 464508fcd73..911450f3a8b 100644 --- a/spec/lib/gitlab/changes_list_spec.rb +++ b/spec/lib/gitlab/changes_list_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "spec_helper" describe Gitlab::ChangesList do diff --git a/spec/lib/gitlab/chat_name_token_spec.rb b/spec/lib/gitlab/chat_name_token_spec.rb index 1e9fb9077fc..b2d4a466021 100644 --- a/spec/lib/gitlab/chat_name_token_spec.rb +++ b/spec/lib/gitlab/chat_name_token_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::ChatNameToken do diff --git a/spec/lib/gitlab/chat_spec.rb b/spec/lib/gitlab/chat_spec.rb index d61c4b36668..08cc16314c5 100644 --- a/spec/lib/gitlab/chat_spec.rb +++ b/spec/lib/gitlab/chat_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Chat, :use_clean_rails_memory_store_caching do diff --git a/spec/lib/gitlab/checks/change_access_spec.rb b/spec/lib/gitlab/checks/change_access_spec.rb index 45fb33e9e4a..3a8e8f67e16 100644 --- a/spec/lib/gitlab/checks/change_access_spec.rb +++ b/spec/lib/gitlab/checks/change_access_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Checks::ChangeAccess do diff --git a/spec/lib/gitlab/checks/force_push_spec.rb b/spec/lib/gitlab/checks/force_push_spec.rb index 0e0788ce974..9432be083d3 100644 --- a/spec/lib/gitlab/checks/force_push_spec.rb +++ b/spec/lib/gitlab/checks/force_push_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Checks::ForcePush do diff --git a/spec/lib/gitlab/checks/lfs_integrity_spec.rb b/spec/lib/gitlab/checks/lfs_integrity_spec.rb index 887ea8fc1e0..88e8f5d74d1 100644 --- a/spec/lib/gitlab/checks/lfs_integrity_spec.rb +++ b/spec/lib/gitlab/checks/lfs_integrity_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Checks::LfsIntegrity do diff --git a/spec/lib/gitlab/checks/project_created_spec.rb b/spec/lib/gitlab/checks/project_created_spec.rb index ac02007e111..14cb5e6ec66 100644 --- a/spec/lib/gitlab/checks/project_created_spec.rb +++ b/spec/lib/gitlab/checks/project_created_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe Gitlab::Checks::ProjectCreated, :clean_gitlab_redis_shared_state do diff --git a/spec/lib/gitlab/checks/project_moved_spec.rb b/spec/lib/gitlab/checks/project_moved_spec.rb index 8e9386b1ba1..3ca977aa48d 100644 --- a/spec/lib/gitlab/checks/project_moved_spec.rb +++ b/spec/lib/gitlab/checks/project_moved_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe Gitlab::Checks::ProjectMoved, :clean_gitlab_redis_shared_state do diff --git a/spec/lib/gitlab/ci/ansi2html_spec.rb b/spec/lib/gitlab/ci/ansi2html_spec.rb index 3d57ce431ab..651fdaaabca 100644 --- a/spec/lib/gitlab/ci/ansi2html_spec.rb +++ b/spec/lib/gitlab/ci/ansi2html_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Ansi2html do diff --git a/spec/lib/gitlab/ci/build/artifacts/adapters/gzip_stream_spec.rb b/spec/lib/gitlab/ci/build/artifacts/adapters/gzip_stream_spec.rb index 987c6b37aaa..cec3e70bb9f 100644 --- a/spec/lib/gitlab/ci/build/artifacts/adapters/gzip_stream_spec.rb +++ b/spec/lib/gitlab/ci/build/artifacts/adapters/gzip_stream_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Build::Artifacts::Adapters::GzipStream do diff --git a/spec/lib/gitlab/ci/build/artifacts/adapters/raw_stream_spec.rb b/spec/lib/gitlab/ci/build/artifacts/adapters/raw_stream_spec.rb index ec2dd724b45..66a234232e1 100644 --- a/spec/lib/gitlab/ci/build/artifacts/adapters/raw_stream_spec.rb +++ b/spec/lib/gitlab/ci/build/artifacts/adapters/raw_stream_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Build::Artifacts::Adapters::RawStream do diff --git a/spec/lib/gitlab/ci/build/artifacts/metadata/entry_spec.rb b/spec/lib/gitlab/ci/build/artifacts/metadata/entry_spec.rb index 3b905611467..24d17eb0fb3 100644 --- a/spec/lib/gitlab/ci/build/artifacts/metadata/entry_spec.rb +++ b/spec/lib/gitlab/ci/build/artifacts/metadata/entry_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Build::Artifacts::Metadata::Entry do diff --git a/spec/lib/gitlab/ci/build/artifacts/metadata_spec.rb b/spec/lib/gitlab/ci/build/artifacts/metadata_spec.rb index a9a4af1f455..ff189c4701e 100644 --- a/spec/lib/gitlab/ci/build/artifacts/metadata_spec.rb +++ b/spec/lib/gitlab/ci/build/artifacts/metadata_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Build::Artifacts::Metadata do diff --git a/spec/lib/gitlab/ci/build/artifacts/path_spec.rb b/spec/lib/gitlab/ci/build/artifacts/path_spec.rb index 7bd6a2ead25..7bbef0f5197 100644 --- a/spec/lib/gitlab/ci/build/artifacts/path_spec.rb +++ b/spec/lib/gitlab/ci/build/artifacts/path_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Build::Artifacts::Path do diff --git a/spec/lib/gitlab/ci/build/credentials/factory_spec.rb b/spec/lib/gitlab/ci/build/credentials/factory_spec.rb index d53db05e5e6..9148c0d579e 100644 --- a/spec/lib/gitlab/ci/build/credentials/factory_spec.rb +++ b/spec/lib/gitlab/ci/build/credentials/factory_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Build::Credentials::Factory do diff --git a/spec/lib/gitlab/ci/build/credentials/registry_spec.rb b/spec/lib/gitlab/ci/build/credentials/registry_spec.rb index c6054138cde..552580dcbbe 100644 --- a/spec/lib/gitlab/ci/build/credentials/registry_spec.rb +++ b/spec/lib/gitlab/ci/build/credentials/registry_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Build::Credentials::Registry do diff --git a/spec/lib/gitlab/ci/build/image_spec.rb b/spec/lib/gitlab/ci/build/image_spec.rb index 6e20e0ef5c3..04bab9c58b8 100644 --- a/spec/lib/gitlab/ci/build/image_spec.rb +++ b/spec/lib/gitlab/ci/build/image_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Build::Image do diff --git a/spec/lib/gitlab/ci/build/policy/changes_spec.rb b/spec/lib/gitlab/ci/build/policy/changes_spec.rb index 92cf0376c02..48ac2e4e657 100644 --- a/spec/lib/gitlab/ci/build/policy/changes_spec.rb +++ b/spec/lib/gitlab/ci/build/policy/changes_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Build::Policy::Changes do diff --git a/spec/lib/gitlab/ci/build/policy/kubernetes_spec.rb b/spec/lib/gitlab/ci/build/policy/kubernetes_spec.rb index 4510b82ca9d..bc2e6fe6b8d 100644 --- a/spec/lib/gitlab/ci/build/policy/kubernetes_spec.rb +++ b/spec/lib/gitlab/ci/build/policy/kubernetes_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Build::Policy::Kubernetes do diff --git a/spec/lib/gitlab/ci/build/policy/refs_spec.rb b/spec/lib/gitlab/ci/build/policy/refs_spec.rb index 22ca681cfd3..43c5d3ec980 100644 --- a/spec/lib/gitlab/ci/build/policy/refs_spec.rb +++ b/spec/lib/gitlab/ci/build/policy/refs_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Build::Policy::Refs do diff --git a/spec/lib/gitlab/ci/build/policy/variables_spec.rb b/spec/lib/gitlab/ci/build/policy/variables_spec.rb index 9b016901a20..42a2a9fda2e 100644 --- a/spec/lib/gitlab/ci/build/policy/variables_spec.rb +++ b/spec/lib/gitlab/ci/build/policy/variables_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Build::Policy::Variables do diff --git a/spec/lib/gitlab/ci/build/policy_spec.rb b/spec/lib/gitlab/ci/build/policy_spec.rb index 20ee3dd3e89..80d7b2e9dc8 100644 --- a/spec/lib/gitlab/ci/build/policy_spec.rb +++ b/spec/lib/gitlab/ci/build/policy_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Build::Policy do diff --git a/spec/lib/gitlab/ci/build/step_spec.rb b/spec/lib/gitlab/ci/build/step_spec.rb index e3136fc925e..84e6e0e177f 100644 --- a/spec/lib/gitlab/ci/build/step_spec.rb +++ b/spec/lib/gitlab/ci/build/step_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Build::Step do diff --git a/spec/lib/gitlab/ci/charts_spec.rb b/spec/lib/gitlab/ci/charts_spec.rb index 1668d3bbaac..cfb7a3f72fa 100644 --- a/spec/lib/gitlab/ci/charts_spec.rb +++ b/spec/lib/gitlab/ci/charts_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Charts do diff --git a/spec/lib/gitlab/ci/config/entry/artifacts_spec.rb b/spec/lib/gitlab/ci/config/entry/artifacts_spec.rb index bd1f2c92844..a7f457e0f5e 100644 --- a/spec/lib/gitlab/ci/config/entry/artifacts_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/artifacts_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Config::Entry::Artifacts do diff --git a/spec/lib/gitlab/ci/config/entry/cache_spec.rb b/spec/lib/gitlab/ci/config/entry/cache_spec.rb index 8f711e02f9b..4cb63168ec7 100644 --- a/spec/lib/gitlab/ci/config/entry/cache_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/cache_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Config::Entry::Cache do diff --git a/spec/lib/gitlab/ci/config/entry/commands_spec.rb b/spec/lib/gitlab/ci/config/entry/commands_spec.rb index 8934aeb83db..269a3406913 100644 --- a/spec/lib/gitlab/ci/config/entry/commands_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/commands_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Config::Entry::Commands do diff --git a/spec/lib/gitlab/ci/config/entry/coverage_spec.rb b/spec/lib/gitlab/ci/config/entry/coverage_spec.rb index 4c6bd859552..48d0864cfca 100644 --- a/spec/lib/gitlab/ci/config/entry/coverage_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/coverage_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Config::Entry::Coverage do diff --git a/spec/lib/gitlab/ci/config/entry/default_spec.rb b/spec/lib/gitlab/ci/config/entry/default_spec.rb index a901dd80c2c..27d63dbd407 100644 --- a/spec/lib/gitlab/ci/config/entry/default_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/default_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Config::Entry::Default do diff --git a/spec/lib/gitlab/ci/config/entry/environment_spec.rb b/spec/lib/gitlab/ci/config/entry/environment_spec.rb index 0bc9e8bd3cd..7b72b45fd8d 100644 --- a/spec/lib/gitlab/ci/config/entry/environment_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/environment_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Config::Entry::Environment do diff --git a/spec/lib/gitlab/ci/config/entry/hidden_spec.rb b/spec/lib/gitlab/ci/config/entry/hidden_spec.rb index c88ee10550c..40b73352676 100644 --- a/spec/lib/gitlab/ci/config/entry/hidden_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/hidden_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Config::Entry::Hidden do diff --git a/spec/lib/gitlab/ci/config/entry/image_spec.rb b/spec/lib/gitlab/ci/config/entry/image_spec.rb index 1ebdda398b9..8de2e5de724 100644 --- a/spec/lib/gitlab/ci/config/entry/image_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/image_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Config::Entry::Image do diff --git a/spec/lib/gitlab/ci/config/entry/job_spec.rb b/spec/lib/gitlab/ci/config/entry/job_spec.rb index 25766d34c65..d5861d5dd07 100644 --- a/spec/lib/gitlab/ci/config/entry/job_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/job_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Config::Entry::Job do diff --git a/spec/lib/gitlab/ci/config/entry/jobs_spec.rb b/spec/lib/gitlab/ci/config/entry/jobs_spec.rb index 3e4137930dc..61c8956d41f 100644 --- a/spec/lib/gitlab/ci/config/entry/jobs_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/jobs_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Config::Entry::Jobs do diff --git a/spec/lib/gitlab/ci/config/entry/key_spec.rb b/spec/lib/gitlab/ci/config/entry/key_spec.rb index 3cbf19bea8b..a7874447725 100644 --- a/spec/lib/gitlab/ci/config/entry/key_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/key_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Config::Entry::Key do diff --git a/spec/lib/gitlab/ci/config/entry/paths_spec.rb b/spec/lib/gitlab/ci/config/entry/paths_spec.rb index 1d9c5ddee9b..221d5ae5863 100644 --- a/spec/lib/gitlab/ci/config/entry/paths_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/paths_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Config::Entry::Paths do diff --git a/spec/lib/gitlab/ci/config/entry/policy_spec.rb b/spec/lib/gitlab/ci/config/entry/policy_spec.rb index fba5671594d..266a27c1e47 100644 --- a/spec/lib/gitlab/ci/config/entry/policy_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/policy_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'fast_spec_helper' require 'support/helpers/stub_feature_flags' require_dependency 'active_model' diff --git a/spec/lib/gitlab/ci/config/entry/reports_spec.rb b/spec/lib/gitlab/ci/config/entry/reports_spec.rb index 38943138cbf..3c352c30e55 100644 --- a/spec/lib/gitlab/ci/config/entry/reports_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/reports_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Config::Entry::Reports do diff --git a/spec/lib/gitlab/ci/config/entry/retry_spec.rb b/spec/lib/gitlab/ci/config/entry/retry_spec.rb index 164a9ed4c3d..f9efd2e014d 100644 --- a/spec/lib/gitlab/ci/config/entry/retry_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/retry_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Config::Entry::Retry do diff --git a/spec/lib/gitlab/ci/config/entry/root_spec.rb b/spec/lib/gitlab/ci/config/entry/root_spec.rb index 7a252ed675a..968dbb9c7f2 100644 --- a/spec/lib/gitlab/ci/config/entry/root_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/root_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Config::Entry::Root do diff --git a/spec/lib/gitlab/ci/config/entry/script_spec.rb b/spec/lib/gitlab/ci/config/entry/script_spec.rb index 069eaa26422..d523243d3b6 100644 --- a/spec/lib/gitlab/ci/config/entry/script_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/script_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Config::Entry::Script do diff --git a/spec/lib/gitlab/ci/config/entry/service_spec.rb b/spec/lib/gitlab/ci/config/entry/service_spec.rb index d31866a1987..66cca100688 100644 --- a/spec/lib/gitlab/ci/config/entry/service_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/service_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Config::Entry::Service do diff --git a/spec/lib/gitlab/ci/config/entry/services_spec.rb b/spec/lib/gitlab/ci/config/entry/services_spec.rb index d5a1316f665..764f783b083 100644 --- a/spec/lib/gitlab/ci/config/entry/services_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/services_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Config::Entry::Services do diff --git a/spec/lib/gitlab/ci/config/entry/stage_spec.rb b/spec/lib/gitlab/ci/config/entry/stage_spec.rb index 70c8a0a355a..574fa00575a 100644 --- a/spec/lib/gitlab/ci/config/entry/stage_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/stage_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Config::Entry::Stage do diff --git a/spec/lib/gitlab/ci/config/entry/stages_spec.rb b/spec/lib/gitlab/ci/config/entry/stages_spec.rb index 182c8d867c7..97970522104 100644 --- a/spec/lib/gitlab/ci/config/entry/stages_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/stages_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Config::Entry::Stages do diff --git a/spec/lib/gitlab/ci/config/entry/variables_spec.rb b/spec/lib/gitlab/ci/config/entry/variables_spec.rb index 84bfef9e8ad..1320b366367 100644 --- a/spec/lib/gitlab/ci/config/entry/variables_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/variables_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Config::Entry::Variables do diff --git a/spec/lib/gitlab/ci/config/extendable/entry_spec.rb b/spec/lib/gitlab/ci/config/extendable/entry_spec.rb index d63612053b6..e00104e3c68 100644 --- a/spec/lib/gitlab/ci/config/extendable/entry_spec.rb +++ b/spec/lib/gitlab/ci/config/extendable/entry_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'fast_spec_helper' describe Gitlab::Ci::Config::Extendable::Entry do diff --git a/spec/lib/gitlab/ci/config/extendable_spec.rb b/spec/lib/gitlab/ci/config/extendable_spec.rb index 90213f6603d..874b224067b 100644 --- a/spec/lib/gitlab/ci/config/extendable_spec.rb +++ b/spec/lib/gitlab/ci/config/extendable_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'fast_spec_helper' describe Gitlab::Ci::Config::Extendable do diff --git a/spec/lib/gitlab/ci/config_spec.rb b/spec/lib/gitlab/ci/config_spec.rb index 4e8bff3d738..986cde3540a 100644 --- a/spec/lib/gitlab/ci/config_spec.rb +++ b/spec/lib/gitlab/ci/config_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Config do diff --git a/spec/lib/gitlab/ci/cron_parser_spec.rb b/spec/lib/gitlab/ci/cron_parser_spec.rb index 491e3fba9d9..af4e9d687c4 100644 --- a/spec/lib/gitlab/ci/cron_parser_spec.rb +++ b/spec/lib/gitlab/ci/cron_parser_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::CronParser do diff --git a/spec/lib/gitlab/ci/mask_secret_spec.rb b/spec/lib/gitlab/ci/mask_secret_spec.rb index 3789a142248..6607aaae399 100644 --- a/spec/lib/gitlab/ci/mask_secret_spec.rb +++ b/spec/lib/gitlab/ci/mask_secret_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::MaskSecret do diff --git a/spec/lib/gitlab/ci/parsers/test/junit_spec.rb b/spec/lib/gitlab/ci/parsers/test/junit_spec.rb index a49402c7398..8ff60710f67 100644 --- a/spec/lib/gitlab/ci/parsers/test/junit_spec.rb +++ b/spec/lib/gitlab/ci/parsers/test/junit_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'fast_spec_helper' describe Gitlab::Ci::Parsers::Test::Junit do diff --git a/spec/lib/gitlab/ci/pipeline/chain/build_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/build_spec.rb index 50cb45c39d1..bf9ff922c05 100644 --- a/spec/lib/gitlab/ci/pipeline/chain/build_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/chain/build_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Pipeline::Chain::Build do diff --git a/spec/lib/gitlab/ci/pipeline/chain/command_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/command_spec.rb index 5181e9c1583..5775e934cfd 100644 --- a/spec/lib/gitlab/ci/pipeline/chain/command_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/chain/command_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Pipeline::Chain::Command do diff --git a/spec/lib/gitlab/ci/pipeline/chain/create_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/create_spec.rb index 0edc3f315bb..650ab193997 100644 --- a/spec/lib/gitlab/ci/pipeline/chain/create_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/chain/create_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Pipeline::Chain::Create do diff --git a/spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb index 0302e4090cf..417a2d119ff 100644 --- a/spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Pipeline::Chain::Populate do diff --git a/spec/lib/gitlab/ci/pipeline/chain/sequence_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/sequence_spec.rb index eca23694a2b..9cb59442dfd 100644 --- a/spec/lib/gitlab/ci/pipeline/chain/sequence_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/chain/sequence_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Pipeline::Chain::Sequence do diff --git a/spec/lib/gitlab/ci/pipeline/chain/skip_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/skip_spec.rb index c7f4fc98ca3..fe46633ed1b 100644 --- a/spec/lib/gitlab/ci/pipeline/chain/skip_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/chain/skip_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Pipeline::Chain::Skip do diff --git a/spec/lib/gitlab/ci/pipeline/chain/validate/abilities_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/validate/abilities_spec.rb index b3e58c3dfdb..ac370433955 100644 --- a/spec/lib/gitlab/ci/pipeline/chain/validate/abilities_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/chain/validate/abilities_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Pipeline::Chain::Validate::Abilities do diff --git a/spec/lib/gitlab/ci/pipeline/chain/validate/config_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/validate/config_spec.rb index 00bbc4c817a..79acd3e4f54 100644 --- a/spec/lib/gitlab/ci/pipeline/chain/validate/config_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/chain/validate/config_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Pipeline::Chain::Validate::Config do diff --git a/spec/lib/gitlab/ci/pipeline/chain/validate/repository_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/validate/repository_spec.rb index 2e8c9d70098..b866355906e 100644 --- a/spec/lib/gitlab/ci/pipeline/chain/validate/repository_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/chain/validate/repository_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Pipeline::Chain::Validate::Repository do diff --git a/spec/lib/gitlab/ci/pipeline/duration_spec.rb b/spec/lib/gitlab/ci/pipeline/duration_spec.rb index 7c9836e2da6..a4984092f35 100644 --- a/spec/lib/gitlab/ci/pipeline/duration_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/duration_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Pipeline::Duration do diff --git a/spec/lib/gitlab/ci/pipeline/expression/lexeme/and_spec.rb b/spec/lib/gitlab/ci/pipeline/expression/lexeme/and_spec.rb index 006ce4d8078..847d613dba3 100644 --- a/spec/lib/gitlab/ci/pipeline/expression/lexeme/and_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/expression/lexeme/and_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'fast_spec_helper' require 'rspec-parameterized' diff --git a/spec/lib/gitlab/ci/pipeline/expression/lexeme/equals_spec.rb b/spec/lib/gitlab/ci/pipeline/expression/lexeme/equals_spec.rb index fcbd2863289..0e13681a4cf 100644 --- a/spec/lib/gitlab/ci/pipeline/expression/lexeme/equals_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/expression/lexeme/equals_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Pipeline::Expression::Lexeme::Equals do diff --git a/spec/lib/gitlab/ci/pipeline/expression/lexeme/matches_spec.rb b/spec/lib/gitlab/ci/pipeline/expression/lexeme/matches_spec.rb index a6fdec832a3..4e4f1bf6ad3 100644 --- a/spec/lib/gitlab/ci/pipeline/expression/lexeme/matches_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/expression/lexeme/matches_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'fast_spec_helper' require_dependency 're2' diff --git a/spec/lib/gitlab/ci/pipeline/expression/lexeme/not_equals_spec.rb b/spec/lib/gitlab/ci/pipeline/expression/lexeme/not_equals_spec.rb index 38d30c9035a..a3a48f83b27 100644 --- a/spec/lib/gitlab/ci/pipeline/expression/lexeme/not_equals_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/expression/lexeme/not_equals_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Pipeline::Expression::Lexeme::NotEquals do diff --git a/spec/lib/gitlab/ci/pipeline/expression/lexeme/not_matches_spec.rb b/spec/lib/gitlab/ci/pipeline/expression/lexeme/not_matches_spec.rb index 99110ff8d88..6b81008ffb1 100644 --- a/spec/lib/gitlab/ci/pipeline/expression/lexeme/not_matches_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/expression/lexeme/not_matches_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'fast_spec_helper' require_dependency 're2' diff --git a/spec/lib/gitlab/ci/pipeline/expression/lexeme/null_spec.rb b/spec/lib/gitlab/ci/pipeline/expression/lexeme/null_spec.rb index b5a59929e11..7013c6bacbb 100644 --- a/spec/lib/gitlab/ci/pipeline/expression/lexeme/null_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/expression/lexeme/null_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Pipeline::Expression::Lexeme::Null do diff --git a/spec/lib/gitlab/ci/pipeline/expression/lexeme/or_spec.rb b/spec/lib/gitlab/ci/pipeline/expression/lexeme/or_spec.rb index d542eebc613..15505ebc82b 100644 --- a/spec/lib/gitlab/ci/pipeline/expression/lexeme/or_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/expression/lexeme/or_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'fast_spec_helper' require 'rspec-parameterized' diff --git a/spec/lib/gitlab/ci/pipeline/expression/lexeme/pattern_spec.rb b/spec/lib/gitlab/ci/pipeline/expression/lexeme/pattern_spec.rb index 6ce4b321397..2cc25a07417 100644 --- a/spec/lib/gitlab/ci/pipeline/expression/lexeme/pattern_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/expression/lexeme/pattern_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Pipeline::Expression::Lexeme::Pattern do diff --git a/spec/lib/gitlab/ci/pipeline/expression/lexeme/string_spec.rb b/spec/lib/gitlab/ci/pipeline/expression/lexeme/string_spec.rb index f54ef492e6d..2a6b90d127f 100644 --- a/spec/lib/gitlab/ci/pipeline/expression/lexeme/string_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/expression/lexeme/string_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Pipeline::Expression::Lexeme::String do diff --git a/spec/lib/gitlab/ci/pipeline/expression/lexeme/variable_spec.rb b/spec/lib/gitlab/ci/pipeline/expression/lexeme/variable_spec.rb index 599a5411881..29e26930249 100644 --- a/spec/lib/gitlab/ci/pipeline/expression/lexeme/variable_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/expression/lexeme/variable_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Pipeline::Expression::Lexeme::Variable do diff --git a/spec/lib/gitlab/ci/pipeline/expression/lexer_spec.rb b/spec/lib/gitlab/ci/pipeline/expression/lexer_spec.rb index 7c98e729b0b..2b0cee2d6f2 100644 --- a/spec/lib/gitlab/ci/pipeline/expression/lexer_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/expression/lexer_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Pipeline::Expression::Lexer do diff --git a/spec/lib/gitlab/ci/pipeline/expression/parser_spec.rb b/spec/lib/gitlab/ci/pipeline/expression/parser_spec.rb index e88ec5561b6..10adfa18af6 100644 --- a/spec/lib/gitlab/ci/pipeline/expression/parser_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/expression/parser_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'fast_spec_helper' describe Gitlab::Ci::Pipeline::Expression::Parser do diff --git a/spec/lib/gitlab/ci/pipeline/expression/statement_spec.rb b/spec/lib/gitlab/ci/pipeline/expression/statement_spec.rb index b259ef711aa..79ee4d07e3a 100644 --- a/spec/lib/gitlab/ci/pipeline/expression/statement_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/expression/statement_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'fast_spec_helper' require 'rspec-parameterized' diff --git a/spec/lib/gitlab/ci/pipeline/expression/token_spec.rb b/spec/lib/gitlab/ci/pipeline/expression/token_spec.rb index cedfe270f9d..aa807cecb72 100644 --- a/spec/lib/gitlab/ci/pipeline/expression/token_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/expression/token_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'fast_spec_helper' describe Gitlab::Ci::Pipeline::Expression::Token do diff --git a/spec/lib/gitlab/ci/pipeline/seed/stage_spec.rb b/spec/lib/gitlab/ci/pipeline/seed/stage_spec.rb index 493ca3cd7b5..ad864d0d56e 100644 --- a/spec/lib/gitlab/ci/pipeline/seed/stage_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/seed/stage_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Pipeline::Seed::Stage do diff --git a/spec/lib/gitlab/ci/reports/test_case_spec.rb b/spec/lib/gitlab/ci/reports/test_case_spec.rb index 6932f79f0ce..20c489ee94c 100644 --- a/spec/lib/gitlab/ci/reports/test_case_spec.rb +++ b/spec/lib/gitlab/ci/reports/test_case_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Reports::TestCase do diff --git a/spec/lib/gitlab/ci/reports/test_reports_comparer_spec.rb b/spec/lib/gitlab/ci/reports/test_reports_comparer_spec.rb index 36582204cc1..48eef0643b2 100644 --- a/spec/lib/gitlab/ci/reports/test_reports_comparer_spec.rb +++ b/spec/lib/gitlab/ci/reports/test_reports_comparer_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Reports::TestReportsComparer do diff --git a/spec/lib/gitlab/ci/reports/test_reports_spec.rb b/spec/lib/gitlab/ci/reports/test_reports_spec.rb index 74ff134b239..0b5d05bada3 100644 --- a/spec/lib/gitlab/ci/reports/test_reports_spec.rb +++ b/spec/lib/gitlab/ci/reports/test_reports_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Reports::TestReports do diff --git a/spec/lib/gitlab/ci/reports/test_suite_comparer_spec.rb b/spec/lib/gitlab/ci/reports/test_suite_comparer_spec.rb index 579b3e6fd24..cf4690bb334 100644 --- a/spec/lib/gitlab/ci/reports/test_suite_comparer_spec.rb +++ b/spec/lib/gitlab/ci/reports/test_suite_comparer_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Reports::TestSuiteComparer do diff --git a/spec/lib/gitlab/ci/reports/test_suite_spec.rb b/spec/lib/gitlab/ci/reports/test_suite_spec.rb index cd34dbaf62f..8646db43bc8 100644 --- a/spec/lib/gitlab/ci/reports/test_suite_spec.rb +++ b/spec/lib/gitlab/ci/reports/test_suite_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Reports::TestSuite do diff --git a/spec/lib/gitlab/ci/status/build/action_spec.rb b/spec/lib/gitlab/ci/status/build/action_spec.rb index bdec582b57b..3aae7e18d6d 100644 --- a/spec/lib/gitlab/ci/status/build/action_spec.rb +++ b/spec/lib/gitlab/ci/status/build/action_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Status::Build::Action do diff --git a/spec/lib/gitlab/ci/status/build/cancelable_spec.rb b/spec/lib/gitlab/ci/status/build/cancelable_spec.rb index 78d6fa65b5a..3841dae91c7 100644 --- a/spec/lib/gitlab/ci/status/build/cancelable_spec.rb +++ b/spec/lib/gitlab/ci/status/build/cancelable_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Status::Build::Cancelable do diff --git a/spec/lib/gitlab/ci/status/build/canceled_spec.rb b/spec/lib/gitlab/ci/status/build/canceled_spec.rb index c6b5cc68770..4b43c78f1a7 100644 --- a/spec/lib/gitlab/ci/status/build/canceled_spec.rb +++ b/spec/lib/gitlab/ci/status/build/canceled_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Status::Build::Canceled do diff --git a/spec/lib/gitlab/ci/status/build/common_spec.rb b/spec/lib/gitlab/ci/status/build/common_spec.rb index ca3c66f0152..5114540708f 100644 --- a/spec/lib/gitlab/ci/status/build/common_spec.rb +++ b/spec/lib/gitlab/ci/status/build/common_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Status::Build::Common do diff --git a/spec/lib/gitlab/ci/status/build/created_spec.rb b/spec/lib/gitlab/ci/status/build/created_spec.rb index 8bdfe6ef7a2..6e3aa442810 100644 --- a/spec/lib/gitlab/ci/status/build/created_spec.rb +++ b/spec/lib/gitlab/ci/status/build/created_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Status::Build::Created do diff --git a/spec/lib/gitlab/ci/status/build/erased_spec.rb b/spec/lib/gitlab/ci/status/build/erased_spec.rb index 0acd271e375..af9c296da0c 100644 --- a/spec/lib/gitlab/ci/status/build/erased_spec.rb +++ b/spec/lib/gitlab/ci/status/build/erased_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Status::Build::Erased do diff --git a/spec/lib/gitlab/ci/status/build/factory_spec.rb b/spec/lib/gitlab/ci/status/build/factory_spec.rb index b6231510b91..de489fa4664 100644 --- a/spec/lib/gitlab/ci/status/build/factory_spec.rb +++ b/spec/lib/gitlab/ci/status/build/factory_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Status::Build::Factory do diff --git a/spec/lib/gitlab/ci/status/build/failed_allowed_spec.rb b/spec/lib/gitlab/ci/status/build/failed_allowed_spec.rb index 2a5915d75d0..01500689619 100644 --- a/spec/lib/gitlab/ci/status/build/failed_allowed_spec.rb +++ b/spec/lib/gitlab/ci/status/build/failed_allowed_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Status::Build::FailedAllowed do diff --git a/spec/lib/gitlab/ci/status/build/failed_spec.rb b/spec/lib/gitlab/ci/status/build/failed_spec.rb index e424270f7c5..78f5214ca81 100644 --- a/spec/lib/gitlab/ci/status/build/failed_spec.rb +++ b/spec/lib/gitlab/ci/status/build/failed_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Status::Build::Failed do diff --git a/spec/lib/gitlab/ci/status/build/failed_unmet_prerequisites_spec.rb b/spec/lib/gitlab/ci/status/build/failed_unmet_prerequisites_spec.rb index a4854bdc6b9..19a3c82eac7 100644 --- a/spec/lib/gitlab/ci/status/build/failed_unmet_prerequisites_spec.rb +++ b/spec/lib/gitlab/ci/status/build/failed_unmet_prerequisites_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' RSpec.describe Gitlab::Ci::Status::Build::FailedUnmetPrerequisites do diff --git a/spec/lib/gitlab/ci/status/build/manual_spec.rb b/spec/lib/gitlab/ci/status/build/manual_spec.rb index 6386296f992..bffe2c10d12 100644 --- a/spec/lib/gitlab/ci/status/build/manual_spec.rb +++ b/spec/lib/gitlab/ci/status/build/manual_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Status::Build::Manual do diff --git a/spec/lib/gitlab/ci/status/build/pending_spec.rb b/spec/lib/gitlab/ci/status/build/pending_spec.rb index 4cf70828e53..64d57954c15 100644 --- a/spec/lib/gitlab/ci/status/build/pending_spec.rb +++ b/spec/lib/gitlab/ci/status/build/pending_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Status::Build::Pending do diff --git a/spec/lib/gitlab/ci/status/build/play_spec.rb b/spec/lib/gitlab/ci/status/build/play_spec.rb index 02f8c4c114b..bb12a900b55 100644 --- a/spec/lib/gitlab/ci/status/build/play_spec.rb +++ b/spec/lib/gitlab/ci/status/build/play_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Status::Build::Play do diff --git a/spec/lib/gitlab/ci/status/build/retried_spec.rb b/spec/lib/gitlab/ci/status/build/retried_spec.rb index 76c2fb01e3f..fce497d40a1 100644 --- a/spec/lib/gitlab/ci/status/build/retried_spec.rb +++ b/spec/lib/gitlab/ci/status/build/retried_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Status::Build::Retried do diff --git a/spec/lib/gitlab/ci/status/build/retryable_spec.rb b/spec/lib/gitlab/ci/status/build/retryable_spec.rb index 84d98588f2d..5b0ae315927 100644 --- a/spec/lib/gitlab/ci/status/build/retryable_spec.rb +++ b/spec/lib/gitlab/ci/status/build/retryable_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Status::Build::Retryable do diff --git a/spec/lib/gitlab/ci/status/build/scheduled_spec.rb b/spec/lib/gitlab/ci/status/build/scheduled_spec.rb index 68b87fea75d..8f87da10815 100644 --- a/spec/lib/gitlab/ci/status/build/scheduled_spec.rb +++ b/spec/lib/gitlab/ci/status/build/scheduled_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Status::Build::Scheduled do diff --git a/spec/lib/gitlab/ci/status/build/skipped_spec.rb b/spec/lib/gitlab/ci/status/build/skipped_spec.rb index 46f6933025a..7ce5142da78 100644 --- a/spec/lib/gitlab/ci/status/build/skipped_spec.rb +++ b/spec/lib/gitlab/ci/status/build/skipped_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Status::Build::Skipped do diff --git a/spec/lib/gitlab/ci/status/build/stop_spec.rb b/spec/lib/gitlab/ci/status/build/stop_spec.rb index 5b7534c96c1..d3e98400a53 100644 --- a/spec/lib/gitlab/ci/status/build/stop_spec.rb +++ b/spec/lib/gitlab/ci/status/build/stop_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Status::Build::Stop do diff --git a/spec/lib/gitlab/ci/status/build/unschedule_spec.rb b/spec/lib/gitlab/ci/status/build/unschedule_spec.rb index ed046d66ca5..c18fc3252b4 100644 --- a/spec/lib/gitlab/ci/status/build/unschedule_spec.rb +++ b/spec/lib/gitlab/ci/status/build/unschedule_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Status::Build::Unschedule do diff --git a/spec/lib/gitlab/ci/status/canceled_spec.rb b/spec/lib/gitlab/ci/status/canceled_spec.rb index dc74d7e28c5..6cfcea4fdde 100644 --- a/spec/lib/gitlab/ci/status/canceled_spec.rb +++ b/spec/lib/gitlab/ci/status/canceled_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Status::Canceled do diff --git a/spec/lib/gitlab/ci/status/created_spec.rb b/spec/lib/gitlab/ci/status/created_spec.rb index ce4333f2aca..aeb41e9cfc3 100644 --- a/spec/lib/gitlab/ci/status/created_spec.rb +++ b/spec/lib/gitlab/ci/status/created_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Status::Created do diff --git a/spec/lib/gitlab/ci/status/extended_spec.rb b/spec/lib/gitlab/ci/status/extended_spec.rb index 6eacb07078b..8accfc4a2f9 100644 --- a/spec/lib/gitlab/ci/status/extended_spec.rb +++ b/spec/lib/gitlab/ci/status/extended_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Status::Extended do diff --git a/spec/lib/gitlab/ci/status/external/common_spec.rb b/spec/lib/gitlab/ci/status/external/common_spec.rb index 0d02c371a92..983522fa2d6 100644 --- a/spec/lib/gitlab/ci/status/external/common_spec.rb +++ b/spec/lib/gitlab/ci/status/external/common_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Status::External::Common do diff --git a/spec/lib/gitlab/ci/status/external/factory_spec.rb b/spec/lib/gitlab/ci/status/external/factory_spec.rb index 529d02a3e39..3b90fb60cca 100644 --- a/spec/lib/gitlab/ci/status/external/factory_spec.rb +++ b/spec/lib/gitlab/ci/status/external/factory_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Status::External::Factory do diff --git a/spec/lib/gitlab/ci/status/factory_spec.rb b/spec/lib/gitlab/ci/status/factory_spec.rb index bbf9c7c83a3..b51c0bec47e 100644 --- a/spec/lib/gitlab/ci/status/factory_spec.rb +++ b/spec/lib/gitlab/ci/status/factory_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Status::Factory do diff --git a/spec/lib/gitlab/ci/status/failed_spec.rb b/spec/lib/gitlab/ci/status/failed_spec.rb index a4a92117c7f..5c7393fc8cf 100644 --- a/spec/lib/gitlab/ci/status/failed_spec.rb +++ b/spec/lib/gitlab/ci/status/failed_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Status::Failed do diff --git a/spec/lib/gitlab/ci/status/group/common_spec.rb b/spec/lib/gitlab/ci/status/group/common_spec.rb index c0ca05881f5..35fff30ea9d 100644 --- a/spec/lib/gitlab/ci/status/group/common_spec.rb +++ b/spec/lib/gitlab/ci/status/group/common_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Status::Group::Common do diff --git a/spec/lib/gitlab/ci/status/group/factory_spec.rb b/spec/lib/gitlab/ci/status/group/factory_spec.rb index 0cd83123938..be76a1d5a65 100644 --- a/spec/lib/gitlab/ci/status/group/factory_spec.rb +++ b/spec/lib/gitlab/ci/status/group/factory_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Status::Group::Factory do diff --git a/spec/lib/gitlab/ci/status/manual_spec.rb b/spec/lib/gitlab/ci/status/manual_spec.rb index 0463f2e1aff..0839452ec22 100644 --- a/spec/lib/gitlab/ci/status/manual_spec.rb +++ b/spec/lib/gitlab/ci/status/manual_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Status::Manual do diff --git a/spec/lib/gitlab/ci/status/pending_spec.rb b/spec/lib/gitlab/ci/status/pending_spec.rb index 0e25358dd8a..5f830e5bb56 100644 --- a/spec/lib/gitlab/ci/status/pending_spec.rb +++ b/spec/lib/gitlab/ci/status/pending_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Status::Pending do diff --git a/spec/lib/gitlab/ci/status/pipeline/blocked_spec.rb b/spec/lib/gitlab/ci/status/pipeline/blocked_spec.rb index 1a2b952d374..876ba712d05 100644 --- a/spec/lib/gitlab/ci/status/pipeline/blocked_spec.rb +++ b/spec/lib/gitlab/ci/status/pipeline/blocked_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Status::Pipeline::Blocked do diff --git a/spec/lib/gitlab/ci/status/pipeline/common_spec.rb b/spec/lib/gitlab/ci/status/pipeline/common_spec.rb index 57df8325635..d3251d138b8 100644 --- a/spec/lib/gitlab/ci/status/pipeline/common_spec.rb +++ b/spec/lib/gitlab/ci/status/pipeline/common_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Status::Pipeline::Common do diff --git a/spec/lib/gitlab/ci/status/pipeline/delayed_spec.rb b/spec/lib/gitlab/ci/status/pipeline/delayed_spec.rb index f89712d2b03..90b797965b3 100644 --- a/spec/lib/gitlab/ci/status/pipeline/delayed_spec.rb +++ b/spec/lib/gitlab/ci/status/pipeline/delayed_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Status::Pipeline::Delayed do diff --git a/spec/lib/gitlab/ci/status/pipeline/factory_spec.rb b/spec/lib/gitlab/ci/status/pipeline/factory_spec.rb index 466087a0e31..8a36cd1b658 100644 --- a/spec/lib/gitlab/ci/status/pipeline/factory_spec.rb +++ b/spec/lib/gitlab/ci/status/pipeline/factory_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Status::Pipeline::Factory do diff --git a/spec/lib/gitlab/ci/status/running_spec.rb b/spec/lib/gitlab/ci/status/running_spec.rb index 9c9d431bb5d..75ff58c5c98 100644 --- a/spec/lib/gitlab/ci/status/running_spec.rb +++ b/spec/lib/gitlab/ci/status/running_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Status::Running do diff --git a/spec/lib/gitlab/ci/status/scheduled_spec.rb b/spec/lib/gitlab/ci/status/scheduled_spec.rb index b8ca3caa1f7..a0374e1a87b 100644 --- a/spec/lib/gitlab/ci/status/scheduled_spec.rb +++ b/spec/lib/gitlab/ci/status/scheduled_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Status::Scheduled do diff --git a/spec/lib/gitlab/ci/status/skipped_spec.rb b/spec/lib/gitlab/ci/status/skipped_spec.rb index 63694ca0ea6..7f68d4a2fa9 100644 --- a/spec/lib/gitlab/ci/status/skipped_spec.rb +++ b/spec/lib/gitlab/ci/status/skipped_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Status::Skipped do diff --git a/spec/lib/gitlab/ci/status/stage/common_spec.rb b/spec/lib/gitlab/ci/status/stage/common_spec.rb index bb2d0a2c75c..26ff0e901fd 100644 --- a/spec/lib/gitlab/ci/status/stage/common_spec.rb +++ b/spec/lib/gitlab/ci/status/stage/common_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Status::Stage::Common do diff --git a/spec/lib/gitlab/ci/status/stage/factory_spec.rb b/spec/lib/gitlab/ci/status/stage/factory_spec.rb index 4b299170c87..8f5b1ff62a5 100644 --- a/spec/lib/gitlab/ci/status/stage/factory_spec.rb +++ b/spec/lib/gitlab/ci/status/stage/factory_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Status::Stage::Factory do diff --git a/spec/lib/gitlab/ci/status/success_spec.rb b/spec/lib/gitlab/ci/status/success_spec.rb index 2f67df71c4f..d4b3a9f12cc 100644 --- a/spec/lib/gitlab/ci/status/success_spec.rb +++ b/spec/lib/gitlab/ci/status/success_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Status::Success do diff --git a/spec/lib/gitlab/ci/status/success_warning_spec.rb b/spec/lib/gitlab/ci/status/success_warning_spec.rb index 9493b1d89f2..af952011e21 100644 --- a/spec/lib/gitlab/ci/status/success_warning_spec.rb +++ b/spec/lib/gitlab/ci/status/success_warning_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Status::SuccessWarning do diff --git a/spec/lib/gitlab/ci/trace/chunked_io_spec.rb b/spec/lib/gitlab/ci/trace/chunked_io_spec.rb index 3e5cd81f929..e0077a5280a 100644 --- a/spec/lib/gitlab/ci/trace/chunked_io_spec.rb +++ b/spec/lib/gitlab/ci/trace/chunked_io_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Trace::ChunkedIO, :clean_gitlab_redis_cache do @@ -312,7 +314,7 @@ describe Gitlab::Ci::Trace::ChunkedIO, :clean_gitlab_redis_cache do end context 'when utf-8 is being used' do - let(:sample_trace_raw) { sample_trace_raw_utf8.force_encoding(Encoding::BINARY) } + let(:sample_trace_raw) { sample_trace_raw_utf8.dup.force_encoding(Encoding::BINARY) } let(:sample_trace_raw_utf8) { "😺\n😺\n😺\n😺" } before do diff --git a/spec/lib/gitlab/ci/trace/section_parser_spec.rb b/spec/lib/gitlab/ci/trace/section_parser_spec.rb index ca53ff87c6f..5e2efe083be 100644 --- a/spec/lib/gitlab/ci/trace/section_parser_spec.rb +++ b/spec/lib/gitlab/ci/trace/section_parser_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Trace::SectionParser do diff --git a/spec/lib/gitlab/ci/trace_spec.rb b/spec/lib/gitlab/ci/trace_spec.rb index d6510649dba..f7bc5686b68 100644 --- a/spec/lib/gitlab/ci/trace_spec.rb +++ b/spec/lib/gitlab/ci/trace_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Trace, :clean_gitlab_redis_shared_state do diff --git a/spec/lib/gitlab/ci/variables/collection/item_spec.rb b/spec/lib/gitlab/ci/variables/collection/item_spec.rb index 613814df23f..1bdca753cd3 100644 --- a/spec/lib/gitlab/ci/variables/collection/item_spec.rb +++ b/spec/lib/gitlab/ci/variables/collection/item_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Variables::Collection::Item do diff --git a/spec/lib/gitlab/ci/variables/collection_spec.rb b/spec/lib/gitlab/ci/variables/collection_spec.rb index 8e732d44d5d..59b9f7d4fb9 100644 --- a/spec/lib/gitlab/ci/variables/collection_spec.rb +++ b/spec/lib/gitlab/ci/variables/collection_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Variables::Collection do diff --git a/spec/lib/gitlab/ci/yaml_processor_spec.rb b/spec/lib/gitlab/ci/yaml_processor_spec.rb index 789d6813d5b..fc9d4f97bda 100644 --- a/spec/lib/gitlab/ci/yaml_processor_spec.rb +++ b/spec/lib/gitlab/ci/yaml_processor_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' module Gitlab diff --git a/spec/lib/gitlab/ci_access_spec.rb b/spec/lib/gitlab/ci_access_spec.rb index 75b90e76083..3c68d209eb6 100644 --- a/spec/lib/gitlab/ci_access_spec.rb +++ b/spec/lib/gitlab/ci_access_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::CiAccess do diff --git a/spec/lib/gitlab/closing_issue_extractor_spec.rb b/spec/lib/gitlab/closing_issue_extractor_spec.rb index 44568f2a653..fdd01f58c9d 100644 --- a/spec/lib/gitlab/closing_issue_extractor_spec.rb +++ b/spec/lib/gitlab/closing_issue_extractor_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::ClosingIssueExtractor do diff --git a/spec/lib/gitlab/color_schemes_spec.rb b/spec/lib/gitlab/color_schemes_spec.rb index c7be45dbcd3..ba5573f6901 100644 --- a/spec/lib/gitlab/color_schemes_spec.rb +++ b/spec/lib/gitlab/color_schemes_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::ColorSchemes do diff --git a/spec/lib/gitlab/config/entry/attributable_spec.rb b/spec/lib/gitlab/config/entry/attributable_spec.rb index abb4fff3ad7..82614bb8238 100644 --- a/spec/lib/gitlab/config/entry/attributable_spec.rb +++ b/spec/lib/gitlab/config/entry/attributable_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Config::Entry::Attributable do diff --git a/spec/lib/gitlab/config/entry/boolean_spec.rb b/spec/lib/gitlab/config/entry/boolean_spec.rb index 1b7a3f850ec..0b8b720dd80 100644 --- a/spec/lib/gitlab/config/entry/boolean_spec.rb +++ b/spec/lib/gitlab/config/entry/boolean_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Config::Entry::Boolean do diff --git a/spec/lib/gitlab/config/entry/configurable_spec.rb b/spec/lib/gitlab/config/entry/configurable_spec.rb index 62dbf20ddf8..8c3a4490d08 100644 --- a/spec/lib/gitlab/config/entry/configurable_spec.rb +++ b/spec/lib/gitlab/config/entry/configurable_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Config::Entry::Configurable do diff --git a/spec/lib/gitlab/config/entry/factory_spec.rb b/spec/lib/gitlab/config/entry/factory_spec.rb index 42f8be8e141..a614ef56a78 100644 --- a/spec/lib/gitlab/config/entry/factory_spec.rb +++ b/spec/lib/gitlab/config/entry/factory_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Config::Entry::Factory do diff --git a/spec/lib/gitlab/config/entry/simplifiable_spec.rb b/spec/lib/gitlab/config/entry/simplifiable_spec.rb index bc8387ada67..65e18fe3f10 100644 --- a/spec/lib/gitlab/config/entry/simplifiable_spec.rb +++ b/spec/lib/gitlab/config/entry/simplifiable_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Config::Entry::Simplifiable do diff --git a/spec/lib/gitlab/config/entry/undefined_spec.rb b/spec/lib/gitlab/config/entry/undefined_spec.rb index 48f9d276c95..83c3a6aec72 100644 --- a/spec/lib/gitlab/config/entry/undefined_spec.rb +++ b/spec/lib/gitlab/config/entry/undefined_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Config::Entry::Undefined do diff --git a/spec/lib/gitlab/config/entry/unspecified_spec.rb b/spec/lib/gitlab/config/entry/unspecified_spec.rb index 64421824a12..32c52594ecf 100644 --- a/spec/lib/gitlab/config/entry/unspecified_spec.rb +++ b/spec/lib/gitlab/config/entry/unspecified_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Config::Entry::Unspecified do diff --git a/spec/lib/gitlab/config/entry/validatable_spec.rb b/spec/lib/gitlab/config/entry/validatable_spec.rb index 5a8f9766d23..925db3594ba 100644 --- a/spec/lib/gitlab/config/entry/validatable_spec.rb +++ b/spec/lib/gitlab/config/entry/validatable_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Config::Entry::Validatable do diff --git a/spec/lib/gitlab/config/entry/validator_spec.rb b/spec/lib/gitlab/config/entry/validator_spec.rb index efa16c4265c..7bf350912df 100644 --- a/spec/lib/gitlab/config/entry/validator_spec.rb +++ b/spec/lib/gitlab/config/entry/validator_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Config::Entry::Validator do diff --git a/spec/lib/gitlab/config/loader/yaml_spec.rb b/spec/lib/gitlab/config/loader/yaml_spec.rb index 0affeb01f6a..ccddf340c3d 100644 --- a/spec/lib/gitlab/config/loader/yaml_spec.rb +++ b/spec/lib/gitlab/config/loader/yaml_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Config::Loader::Yaml do diff --git a/spec/lib/gitlab/conflict/file_collection_spec.rb b/spec/lib/gitlab/conflict/file_collection_spec.rb index c93912db411..f3cdb1a9e59 100644 --- a/spec/lib/gitlab/conflict/file_collection_spec.rb +++ b/spec/lib/gitlab/conflict/file_collection_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Conflict::FileCollection do diff --git a/spec/lib/gitlab/conflict/file_spec.rb b/spec/lib/gitlab/conflict/file_spec.rb index a955ce54e85..adf5a232a75 100644 --- a/spec/lib/gitlab/conflict/file_spec.rb +++ b/spec/lib/gitlab/conflict/file_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Conflict::File do diff --git a/spec/lib/gitlab/contributions_calendar_spec.rb b/spec/lib/gitlab/contributions_calendar_spec.rb index 51e5bdc6307..1154f029a8d 100644 --- a/spec/lib/gitlab/contributions_calendar_spec.rb +++ b/spec/lib/gitlab/contributions_calendar_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::ContributionsCalendar do diff --git a/spec/lib/gitlab/cross_project_access/check_collection_spec.rb b/spec/lib/gitlab/cross_project_access/check_collection_spec.rb index a9e7575240e..1aa5480b670 100644 --- a/spec/lib/gitlab/cross_project_access/check_collection_spec.rb +++ b/spec/lib/gitlab/cross_project_access/check_collection_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::CrossProjectAccess::CheckCollection do diff --git a/spec/lib/gitlab/cross_project_access/check_info_spec.rb b/spec/lib/gitlab/cross_project_access/check_info_spec.rb index ea7393a7006..7d2471b6327 100644 --- a/spec/lib/gitlab/cross_project_access/check_info_spec.rb +++ b/spec/lib/gitlab/cross_project_access/check_info_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::CrossProjectAccess::CheckInfo do diff --git a/spec/lib/gitlab/cross_project_access/class_methods_spec.rb b/spec/lib/gitlab/cross_project_access/class_methods_spec.rb index 5349685e633..17d265542dd 100644 --- a/spec/lib/gitlab/cross_project_access/class_methods_spec.rb +++ b/spec/lib/gitlab/cross_project_access/class_methods_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::CrossProjectAccess::ClassMethods do diff --git a/spec/lib/gitlab/cross_project_access_spec.rb b/spec/lib/gitlab/cross_project_access_spec.rb index 614b0473c7e..ce18d207413 100644 --- a/spec/lib/gitlab/cross_project_access_spec.rb +++ b/spec/lib/gitlab/cross_project_access_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::CrossProjectAccess do diff --git a/spec/lib/gitlab/crypto_helper_spec.rb b/spec/lib/gitlab/crypto_helper_spec.rb index 05cc6cf15de..71bbeccb17b 100644 --- a/spec/lib/gitlab/crypto_helper_spec.rb +++ b/spec/lib/gitlab/crypto_helper_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::CryptoHelper do diff --git a/spec/lib/gitlab/current_settings_spec.rb b/spec/lib/gitlab/current_settings_spec.rb index db31e5280a3..2759412add8 100644 --- a/spec/lib/gitlab/current_settings_spec.rb +++ b/spec/lib/gitlab/current_settings_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::CurrentSettings do diff --git a/spec/lib/gitlab/cycle_analytics/base_event_fetcher_spec.rb b/spec/lib/gitlab/cycle_analytics/base_event_fetcher_spec.rb index b7a64adc2ff..3eea791d61a 100644 --- a/spec/lib/gitlab/cycle_analytics/base_event_fetcher_spec.rb +++ b/spec/lib/gitlab/cycle_analytics/base_event_fetcher_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::CycleAnalytics::BaseEventFetcher do diff --git a/spec/lib/gitlab/cycle_analytics/code_event_fetcher_spec.rb b/spec/lib/gitlab/cycle_analytics/code_event_fetcher_spec.rb index 0267e8c2f69..b521ad0c6ea 100644 --- a/spec/lib/gitlab/cycle_analytics/code_event_fetcher_spec.rb +++ b/spec/lib/gitlab/cycle_analytics/code_event_fetcher_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' require 'lib/gitlab/cycle_analytics/shared_event_spec' diff --git a/spec/lib/gitlab/cycle_analytics/code_stage_spec.rb b/spec/lib/gitlab/cycle_analytics/code_stage_spec.rb index 933f3c7896e..dd1d9ac0f16 100644 --- a/spec/lib/gitlab/cycle_analytics/code_stage_spec.rb +++ b/spec/lib/gitlab/cycle_analytics/code_stage_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' require 'lib/gitlab/cycle_analytics/shared_stage_spec' diff --git a/spec/lib/gitlab/cycle_analytics/events_spec.rb b/spec/lib/gitlab/cycle_analytics/events_spec.rb index 5ee02650e49..a163de07967 100644 --- a/spec/lib/gitlab/cycle_analytics/events_spec.rb +++ b/spec/lib/gitlab/cycle_analytics/events_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'cycle analytics events' do diff --git a/spec/lib/gitlab/cycle_analytics/issue_event_fetcher_spec.rb b/spec/lib/gitlab/cycle_analytics/issue_event_fetcher_spec.rb index fd9fa2fee49..afb7b6a13b0 100644 --- a/spec/lib/gitlab/cycle_analytics/issue_event_fetcher_spec.rb +++ b/spec/lib/gitlab/cycle_analytics/issue_event_fetcher_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' require 'lib/gitlab/cycle_analytics/shared_event_spec' diff --git a/spec/lib/gitlab/cycle_analytics/issue_stage_spec.rb b/spec/lib/gitlab/cycle_analytics/issue_stage_spec.rb index dea17e4f3dc..4dd21239cde 100644 --- a/spec/lib/gitlab/cycle_analytics/issue_stage_spec.rb +++ b/spec/lib/gitlab/cycle_analytics/issue_stage_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' require 'lib/gitlab/cycle_analytics/shared_stage_spec' diff --git a/spec/lib/gitlab/cycle_analytics/permissions_spec.rb b/spec/lib/gitlab/cycle_analytics/permissions_spec.rb index f670c7f6c75..2896e973a43 100644 --- a/spec/lib/gitlab/cycle_analytics/permissions_spec.rb +++ b/spec/lib/gitlab/cycle_analytics/permissions_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::CycleAnalytics::Permissions do diff --git a/spec/lib/gitlab/cycle_analytics/plan_event_fetcher_spec.rb b/spec/lib/gitlab/cycle_analytics/plan_event_fetcher_spec.rb index 2e5dc5b5547..17786cd02c6 100644 --- a/spec/lib/gitlab/cycle_analytics/plan_event_fetcher_spec.rb +++ b/spec/lib/gitlab/cycle_analytics/plan_event_fetcher_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' require 'lib/gitlab/cycle_analytics/shared_event_spec' diff --git a/spec/lib/gitlab/cycle_analytics/plan_stage_spec.rb b/spec/lib/gitlab/cycle_analytics/plan_stage_spec.rb index 3cd1320ca9c..98d2593de66 100644 --- a/spec/lib/gitlab/cycle_analytics/plan_stage_spec.rb +++ b/spec/lib/gitlab/cycle_analytics/plan_stage_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' require 'lib/gitlab/cycle_analytics/shared_stage_spec' diff --git a/spec/lib/gitlab/cycle_analytics/production_event_fetcher_spec.rb b/spec/lib/gitlab/cycle_analytics/production_event_fetcher_spec.rb index 74001181305..3ecfad49acd 100644 --- a/spec/lib/gitlab/cycle_analytics/production_event_fetcher_spec.rb +++ b/spec/lib/gitlab/cycle_analytics/production_event_fetcher_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' require 'lib/gitlab/cycle_analytics/shared_event_spec' diff --git a/spec/lib/gitlab/cycle_analytics/production_stage_spec.rb b/spec/lib/gitlab/cycle_analytics/production_stage_spec.rb index 916684b81eb..4d0cc91a318 100644 --- a/spec/lib/gitlab/cycle_analytics/production_stage_spec.rb +++ b/spec/lib/gitlab/cycle_analytics/production_stage_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' require 'lib/gitlab/cycle_analytics/shared_stage_spec' diff --git a/spec/lib/gitlab/cycle_analytics/review_event_fetcher_spec.rb b/spec/lib/gitlab/cycle_analytics/review_event_fetcher_spec.rb index 4f67c95ed4c..2c2169be58c 100644 --- a/spec/lib/gitlab/cycle_analytics/review_event_fetcher_spec.rb +++ b/spec/lib/gitlab/cycle_analytics/review_event_fetcher_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' require 'lib/gitlab/cycle_analytics/shared_event_spec' diff --git a/spec/lib/gitlab/cycle_analytics/review_stage_spec.rb b/spec/lib/gitlab/cycle_analytics/review_stage_spec.rb index 6d14973c711..0f36a8c5c36 100644 --- a/spec/lib/gitlab/cycle_analytics/review_stage_spec.rb +++ b/spec/lib/gitlab/cycle_analytics/review_stage_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' require 'lib/gitlab/cycle_analytics/shared_stage_spec' diff --git a/spec/lib/gitlab/cycle_analytics/shared_event_spec.rb b/spec/lib/gitlab/cycle_analytics/shared_event_spec.rb index b001a46001e..c053af010b3 100644 --- a/spec/lib/gitlab/cycle_analytics/shared_event_spec.rb +++ b/spec/lib/gitlab/cycle_analytics/shared_event_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' shared_examples 'default query config' do diff --git a/spec/lib/gitlab/cycle_analytics/shared_stage_spec.rb b/spec/lib/gitlab/cycle_analytics/shared_stage_spec.rb index c146146723f..cf95741908f 100644 --- a/spec/lib/gitlab/cycle_analytics/shared_stage_spec.rb +++ b/spec/lib/gitlab/cycle_analytics/shared_stage_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' shared_examples 'base stage' do diff --git a/spec/lib/gitlab/cycle_analytics/stage_summary_spec.rb b/spec/lib/gitlab/cycle_analytics/stage_summary_spec.rb index f8009709ce2..778c2f479b5 100644 --- a/spec/lib/gitlab/cycle_analytics/stage_summary_spec.rb +++ b/spec/lib/gitlab/cycle_analytics/stage_summary_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::CycleAnalytics::StageSummary do diff --git a/spec/lib/gitlab/cycle_analytics/staging_event_fetcher_spec.rb b/spec/lib/gitlab/cycle_analytics/staging_event_fetcher_spec.rb index bbc82496340..016d2e8da5b 100644 --- a/spec/lib/gitlab/cycle_analytics/staging_event_fetcher_spec.rb +++ b/spec/lib/gitlab/cycle_analytics/staging_event_fetcher_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' require 'lib/gitlab/cycle_analytics/shared_event_spec' diff --git a/spec/lib/gitlab/cycle_analytics/staging_stage_spec.rb b/spec/lib/gitlab/cycle_analytics/staging_stage_spec.rb index 9ca12cc448c..bd64c4aca42 100644 --- a/spec/lib/gitlab/cycle_analytics/staging_stage_spec.rb +++ b/spec/lib/gitlab/cycle_analytics/staging_stage_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' require 'lib/gitlab/cycle_analytics/shared_stage_spec' diff --git a/spec/lib/gitlab/cycle_analytics/test_event_fetcher_spec.rb b/spec/lib/gitlab/cycle_analytics/test_event_fetcher_spec.rb index 6639fa54e0e..be7c0e9dd59 100644 --- a/spec/lib/gitlab/cycle_analytics/test_event_fetcher_spec.rb +++ b/spec/lib/gitlab/cycle_analytics/test_event_fetcher_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' require 'lib/gitlab/cycle_analytics/shared_event_spec' diff --git a/spec/lib/gitlab/cycle_analytics/test_stage_spec.rb b/spec/lib/gitlab/cycle_analytics/test_stage_spec.rb index 41028c44a00..9162686d17d 100644 --- a/spec/lib/gitlab/cycle_analytics/test_stage_spec.rb +++ b/spec/lib/gitlab/cycle_analytics/test_stage_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' require 'lib/gitlab/cycle_analytics/shared_stage_spec' diff --git a/spec/lib/gitlab/cycle_analytics/updater_spec.rb b/spec/lib/gitlab/cycle_analytics/updater_spec.rb index eff54cd3692..67f386f9144 100644 --- a/spec/lib/gitlab/cycle_analytics/updater_spec.rb +++ b/spec/lib/gitlab/cycle_analytics/updater_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::CycleAnalytics::Updater do diff --git a/spec/lib/gitlab/cycle_analytics/usage_data_spec.rb b/spec/lib/gitlab/cycle_analytics/usage_data_spec.rb index 258ab049c0b..e568ea633db 100644 --- a/spec/lib/gitlab/cycle_analytics/usage_data_spec.rb +++ b/spec/lib/gitlab/cycle_analytics/usage_data_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::CycleAnalytics::UsageData do diff --git a/spec/lib/gitlab/daemon_spec.rb b/spec/lib/gitlab/daemon_spec.rb index 2bdb0dfc736..d3e73314b87 100644 --- a/spec/lib/gitlab/daemon_spec.rb +++ b/spec/lib/gitlab/daemon_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Daemon do diff --git a/spec/lib/gitlab/data_builder/build_spec.rb b/spec/lib/gitlab/data_builder/build_spec.rb index 14fe196a986..b170ef788d9 100644 --- a/spec/lib/gitlab/data_builder/build_spec.rb +++ b/spec/lib/gitlab/data_builder/build_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::DataBuilder::Build do diff --git a/spec/lib/gitlab/data_builder/note_spec.rb b/spec/lib/gitlab/data_builder/note_spec.rb index 1b5dd2538e0..3c26daba5a5 100644 --- a/spec/lib/gitlab/data_builder/note_spec.rb +++ b/spec/lib/gitlab/data_builder/note_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::DataBuilder::Note do diff --git a/spec/lib/gitlab/data_builder/pipeline_spec.rb b/spec/lib/gitlab/data_builder/pipeline_spec.rb index 1f36fd5c6ef..4afb7195b7b 100644 --- a/spec/lib/gitlab/data_builder/pipeline_spec.rb +++ b/spec/lib/gitlab/data_builder/pipeline_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::DataBuilder::Pipeline do diff --git a/spec/lib/gitlab/data_builder/push_spec.rb b/spec/lib/gitlab/data_builder/push_spec.rb index 46ad674a1eb..cc31f88d365 100644 --- a/spec/lib/gitlab/data_builder/push_spec.rb +++ b/spec/lib/gitlab/data_builder/push_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::DataBuilder::Push do diff --git a/spec/lib/gitlab/data_builder/wiki_page_spec.rb b/spec/lib/gitlab/data_builder/wiki_page_spec.rb index 9c8bdf4b032..404d54bf2da 100644 --- a/spec/lib/gitlab/data_builder/wiki_page_spec.rb +++ b/spec/lib/gitlab/data_builder/wiki_page_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::DataBuilder::WikiPage do diff --git a/spec/lib/gitlab/database/count/exact_count_strategy_spec.rb b/spec/lib/gitlab/database/count/exact_count_strategy_spec.rb index 3991c737a26..111833a506a 100644 --- a/spec/lib/gitlab/database/count/exact_count_strategy_spec.rb +++ b/spec/lib/gitlab/database/count/exact_count_strategy_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Database::Count::ExactCountStrategy do @@ -23,18 +25,4 @@ describe Gitlab::Database::Count::ExactCountStrategy do expect(subject).to eq({}) end end - - describe '.enabled?' do - it 'is enabled for PostgreSQL' do - allow(Gitlab::Database).to receive(:postgresql?).and_return(true) - - expect(described_class.enabled?).to be_truthy - end - - it 'is enabled for MySQL' do - allow(Gitlab::Database).to receive(:postgresql?).and_return(false) - - expect(described_class.enabled?).to be_truthy - end - end end diff --git a/spec/lib/gitlab/database/count/reltuples_count_strategy_spec.rb b/spec/lib/gitlab/database/count/reltuples_count_strategy_spec.rb index bd3c66d0548..08032d19d14 100644 --- a/spec/lib/gitlab/database/count/reltuples_count_strategy_spec.rb +++ b/spec/lib/gitlab/database/count/reltuples_count_strategy_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Database::Count::ReltuplesCountStrategy do @@ -8,7 +10,7 @@ describe Gitlab::Database::Count::ReltuplesCountStrategy do subject { described_class.new(models).count } - describe '#count', :postgresql do + describe '#count' do let(:models) { [Project, Identity] } context 'when reltuples is up to date' do @@ -48,18 +50,4 @@ describe Gitlab::Database::Count::ReltuplesCountStrategy do end end end - - describe '.enabled?' do - it 'is enabled for PostgreSQL' do - allow(Gitlab::Database).to receive(:postgresql?).and_return(true) - - expect(described_class.enabled?).to be_truthy - end - - it 'is disabled for MySQL' do - allow(Gitlab::Database).to receive(:postgresql?).and_return(false) - - expect(described_class.enabled?).to be_falsey - end - end end diff --git a/spec/lib/gitlab/database/count/tablesample_count_strategy_spec.rb b/spec/lib/gitlab/database/count/tablesample_count_strategy_spec.rb index 40d810b195b..0c480709c22 100644 --- a/spec/lib/gitlab/database/count/tablesample_count_strategy_spec.rb +++ b/spec/lib/gitlab/database/count/tablesample_count_strategy_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Database::Count::TablesampleCountStrategy do @@ -12,7 +14,7 @@ describe Gitlab::Database::Count::TablesampleCountStrategy do subject { strategy.count } - describe '#count', :postgresql do + describe '#count' do let(:estimates) do { Project => threshold + 1, @@ -56,22 +58,4 @@ describe Gitlab::Database::Count::TablesampleCountStrategy do end end end - - describe '.enabled?' do - before do - stub_feature_flags(tablesample_counts: true) - end - - it 'is enabled for PostgreSQL' do - allow(Gitlab::Database).to receive(:postgresql?).and_return(true) - - expect(described_class.enabled?).to be_truthy - end - - it 'is disabled for MySQL' do - allow(Gitlab::Database).to receive(:postgresql?).and_return(false) - - expect(described_class.enabled?).to be_falsey - end - end end diff --git a/spec/lib/gitlab/database/count_spec.rb b/spec/lib/gitlab/database/count_spec.rb index 1d096b8fa7c..71c25f23b6b 100644 --- a/spec/lib/gitlab/database/count_spec.rb +++ b/spec/lib/gitlab/database/count_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Database::Count do @@ -9,24 +11,13 @@ describe Gitlab::Database::Count do let(:models) { [Project, Identity] } context '.approximate_counts' do - context 'selecting strategies' do - let(:strategies) { [double('s1', enabled?: true), double('s2', enabled?: false)] } - - it 'uses only enabled strategies' do - expect(strategies[0]).to receive(:new).and_return(double('strategy1', count: {})) - expect(strategies[1]).not_to receive(:new) - - described_class.approximate_counts(models, strategies: strategies) - end - end - context 'fallbacks' do subject { described_class.approximate_counts(models, strategies: strategies) } let(:strategies) do [ - double('s1', enabled?: true, new: first_strategy), - double('s2', enabled?: true, new: second_strategy) + double('s1', new: first_strategy), + double('s2', new: second_strategy) ] end diff --git a/spec/lib/gitlab/database/grant_spec.rb b/spec/lib/gitlab/database/grant_spec.rb index 5ebf3f399b6..02697eb2a16 100644 --- a/spec/lib/gitlab/database/grant_spec.rb +++ b/spec/lib/gitlab/database/grant_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Database::Grant do @@ -8,7 +10,7 @@ describe Gitlab::Database::Grant do expect(described_class.create_and_execute_trigger?('users')).to eq(true) end - it 'returns false when the user can not create and/or execute a trigger', :postgresql do + it 'returns false when the user can not create and/or execute a trigger' do # In case of MySQL the user may have SUPER permissions, making it # impossible to have `false` returned when running tests; hence we only # run these tests on PostgreSQL. diff --git a/spec/lib/gitlab/database/migration_helpers_spec.rb b/spec/lib/gitlab/database/migration_helpers_spec.rb index b73828b9554..2731fc8573f 100644 --- a/spec/lib/gitlab/database/migration_helpers_spec.rb +++ b/spec/lib/gitlab/database/migration_helpers_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Database::MigrationHelpers do diff --git a/spec/lib/gitlab/database/multi_threaded_migration_spec.rb b/spec/lib/gitlab/database/multi_threaded_migration_spec.rb index 6c45f13bb5a..53c001fbc1b 100644 --- a/spec/lib/gitlab/database/multi_threaded_migration_spec.rb +++ b/spec/lib/gitlab/database/multi_threaded_migration_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Database::MultiThreadedMigration do diff --git a/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_base_spec.rb b/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_base_spec.rb index 81419e51635..612c418e8bb 100644 --- a/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_base_spec.rb +++ b/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_base_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameBase, :delete do diff --git a/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_namespaces_spec.rb b/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_namespaces_spec.rb index b6096d4faf6..8c4d7e323fa 100644 --- a/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_namespaces_spec.rb +++ b/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_namespaces_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameNamespaces, :delete do diff --git a/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_projects_spec.rb b/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_projects_spec.rb index d4d7a83921c..1ccdb1d9447 100644 --- a/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_projects_spec.rb +++ b/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_projects_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameProjects, :delete do diff --git a/spec/lib/gitlab/database/rename_reserved_paths_migration/v1_spec.rb b/spec/lib/gitlab/database/rename_reserved_paths_migration/v1_spec.rb index ddd54a669a3..b09258ae227 100644 --- a/spec/lib/gitlab/database/rename_reserved_paths_migration/v1_spec.rb +++ b/spec/lib/gitlab/database/rename_reserved_paths_migration/v1_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' shared_examples 'renames child namespaces' do |type| diff --git a/spec/lib/gitlab/database/sha_attribute_spec.rb b/spec/lib/gitlab/database/sha_attribute_spec.rb index 778bfa2cc47..c6fc55291f5 100644 --- a/spec/lib/gitlab/database/sha_attribute_spec.rb +++ b/spec/lib/gitlab/database/sha_attribute_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Database::ShaAttribute do @@ -10,11 +12,7 @@ describe Gitlab::Database::ShaAttribute do end let(:binary_from_db) do - if Gitlab::Database.postgresql? - "\\x#{sha}" - else - binary_sha - end + "\\x#{sha}" end let(:attribute) { described_class.new } diff --git a/spec/lib/gitlab/database_importers/common_metrics/importer_spec.rb b/spec/lib/gitlab/database_importers/common_metrics/importer_spec.rb index 57c8bafd488..eed2a1b7b48 100644 --- a/spec/lib/gitlab/database_importers/common_metrics/importer_spec.rb +++ b/spec/lib/gitlab/database_importers/common_metrics/importer_spec.rb @@ -7,8 +7,8 @@ describe Gitlab::DatabaseImporters::CommonMetrics::Importer do context "does import common_metrics.yml" do let(:groups) { subject.content['panel_groups'] } - let(:panels) { groups.map { |group| group['panels'] }.flatten } - let(:metrics) { panels.map { |group| group['metrics'] }.flatten } + let(:panels) { groups.flat_map { |group| group['panels'] } } + let(:metrics) { panels.flat_map { |group| group['metrics'] } } let(:metric_ids) { metrics.map { |metric| metric['id'] } } before do diff --git a/spec/lib/gitlab/database_spec.rb b/spec/lib/gitlab/database_spec.rb index 9e8712266e8..77e58b6d5c7 100644 --- a/spec/lib/gitlab/database_spec.rb +++ b/spec/lib/gitlab/database_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Database do @@ -15,14 +17,6 @@ describe Gitlab::Database do it 'returns the name of the adapter' do expect(described_class.adapter_name).to be_an_instance_of(String) end - end - - describe '.human_adapter_name' do - it 'returns PostgreSQL when using PostgreSQL' do - allow(described_class).to receive(:postgresql?).and_return(true) - - expect(described_class.human_adapter_name).to eq('PostgreSQL') - end it 'returns Unknown when using anything else' do allow(described_class).to receive(:postgresql?).and_return(false) @@ -31,6 +25,12 @@ describe Gitlab::Database do end end + describe '.human_adapter_name' do + it 'returns PostgreSQL when using PostgreSQL' do + expect(described_class.human_adapter_name).to eq('PostgreSQL') + end + end + describe '.postgresql?' do subject { described_class.postgresql? } @@ -63,21 +63,18 @@ describe Gitlab::Database do end describe '.postgresql_9_or_less?' do - it 'returns false when not using postgresql' do - allow(described_class).to receive(:postgresql?).and_return(false) - - expect(described_class.postgresql_9_or_less?).to eq(false) + it 'returns true when using postgresql 8.4' do + allow(described_class).to receive(:version).and_return('8.4') + expect(described_class.postgresql_9_or_less?).to eq(true) end it 'returns true when using PostgreSQL 9.6' do - allow(described_class).to receive(:postgresql?).and_return(true) allow(described_class).to receive(:version).and_return('9.6') expect(described_class.postgresql_9_or_less?).to eq(true) end it 'returns false when using PostgreSQL 10 or newer' do - allow(described_class).to receive(:postgresql?).and_return(true) allow(described_class).to receive(:version).and_return('10') expect(described_class.postgresql_9_or_less?).to eq(false) @@ -85,53 +82,33 @@ describe Gitlab::Database do end describe '.postgresql_minimum_supported_version?' do - it 'returns false when not using PostgreSQL' do - allow(described_class).to receive(:postgresql?).and_return(false) + it 'returns false when using PostgreSQL 9.5' do + allow(described_class).to receive(:version).and_return('9.5') expect(described_class.postgresql_minimum_supported_version?).to eq(false) end - context 'when using PostgreSQL' do - before do - allow(described_class).to receive(:postgresql?).and_return(true) - end - - it 'returns false when using PostgreSQL 9.5' do - allow(described_class).to receive(:version).and_return('9.5') - - expect(described_class.postgresql_minimum_supported_version?).to eq(false) - end - - it 'returns true when using PostgreSQL 9.6' do - allow(described_class).to receive(:version).and_return('9.6') + it 'returns true when using PostgreSQL 9.6' do + allow(described_class).to receive(:version).and_return('9.6') - expect(described_class.postgresql_minimum_supported_version?).to eq(true) - end + expect(described_class.postgresql_minimum_supported_version?).to eq(true) + end - it 'returns true when using PostgreSQL 10 or newer' do - allow(described_class).to receive(:version).and_return('10') + it 'returns true when using PostgreSQL 10 or newer' do + allow(described_class).to receive(:version).and_return('10') - expect(described_class.postgresql_minimum_supported_version?).to eq(true) - end + expect(described_class.postgresql_minimum_supported_version?).to eq(true) end end describe '.join_lateral_supported?' do - it 'returns false when not using postgresql' do - allow(described_class).to receive(:postgresql?).and_return(false) - - expect(described_class.join_lateral_supported?).to eq(false) - end - it 'returns false when using PostgreSQL 9.2' do - allow(described_class).to receive(:postgresql?).and_return(true) allow(described_class).to receive(:version).and_return('9.2.1') expect(described_class.join_lateral_supported?).to eq(false) end it 'returns true when using PostgreSQL 9.3.0 or newer' do - allow(described_class).to receive(:postgresql?).and_return(true) allow(described_class).to receive(:version).and_return('9.3.0') expect(described_class.join_lateral_supported?).to eq(true) @@ -139,21 +116,13 @@ describe Gitlab::Database do end describe '.replication_slots_supported?' do - it 'returns false when not using postgresql' do - allow(described_class).to receive(:postgresql?).and_return(false) - - expect(described_class.replication_slots_supported?).to eq(false) - end - it 'returns false when using PostgreSQL 9.3' do - allow(described_class).to receive(:postgresql?).and_return(true) allow(described_class).to receive(:version).and_return('9.3.1') expect(described_class.replication_slots_supported?).to eq(false) end it 'returns true when using PostgreSQL 9.4.0 or newer' do - allow(described_class).to receive(:postgresql?).and_return(true) allow(described_class).to receive(:version).and_return('9.4.0') expect(described_class.replication_slots_supported?).to eq(true) @@ -162,14 +131,12 @@ describe Gitlab::Database do describe '.pg_wal_lsn_diff' do it 'returns old name when using PostgreSQL 9.6' do - allow(described_class).to receive(:postgresql?).and_return(true) allow(described_class).to receive(:version).and_return('9.6') expect(described_class.pg_wal_lsn_diff).to eq('pg_xlog_location_diff') end it 'returns new name when using PostgreSQL 10 or newer' do - allow(described_class).to receive(:postgresql?).and_return(true) allow(described_class).to receive(:version).and_return('10') expect(described_class.pg_wal_lsn_diff).to eq('pg_wal_lsn_diff') @@ -178,14 +145,12 @@ describe Gitlab::Database do describe '.pg_current_wal_insert_lsn' do it 'returns old name when using PostgreSQL 9.6' do - allow(described_class).to receive(:postgresql?).and_return(true) allow(described_class).to receive(:version).and_return('9.6') expect(described_class.pg_current_wal_insert_lsn).to eq('pg_current_xlog_insert_location') end it 'returns new name when using PostgreSQL 10 or newer' do - allow(described_class).to receive(:postgresql?).and_return(true) allow(described_class).to receive(:version).and_return('10') expect(described_class.pg_current_wal_insert_lsn).to eq('pg_current_wal_insert_lsn') @@ -194,14 +159,12 @@ describe Gitlab::Database do describe '.pg_last_wal_receive_lsn' do it 'returns old name when using PostgreSQL 9.6' do - allow(described_class).to receive(:postgresql?).and_return(true) allow(described_class).to receive(:version).and_return('9.6') expect(described_class.pg_last_wal_receive_lsn).to eq('pg_last_xlog_receive_location') end it 'returns new name when using PostgreSQL 10 or newer' do - allow(described_class).to receive(:postgresql?).and_return(true) allow(described_class).to receive(:version).and_return('10') expect(described_class.pg_last_wal_receive_lsn).to eq('pg_last_wal_receive_lsn') @@ -210,14 +173,12 @@ describe Gitlab::Database do describe '.pg_last_wal_replay_lsn' do it 'returns old name when using PostgreSQL 9.6' do - allow(described_class).to receive(:postgresql?).and_return(true) allow(described_class).to receive(:version).and_return('9.6') expect(described_class.pg_last_wal_replay_lsn).to eq('pg_last_xlog_replay_location') end it 'returns new name when using PostgreSQL 10 or newer' do - allow(described_class).to receive(:postgresql?).and_return(true) allow(described_class).to receive(:version).and_return('10') expect(described_class.pg_last_wal_replay_lsn).to eq('pg_last_wal_replay_lsn') @@ -432,7 +393,6 @@ describe Gitlab::Database do describe '.db_read_only?' do before do allow(ActiveRecord::Base.connection).to receive(:execute).and_call_original - allow(described_class).to receive(:postgresql?).and_return(true) end it 'detects a read only database' do diff --git a/spec/lib/gitlab/dependency_linker/cartfile_linker_spec.rb b/spec/lib/gitlab/dependency_linker/cartfile_linker_spec.rb index 3a93d5e1e97..3eb5db51224 100644 --- a/spec/lib/gitlab/dependency_linker/cartfile_linker_spec.rb +++ b/spec/lib/gitlab/dependency_linker/cartfile_linker_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe Gitlab::DependencyLinker::CartfileLinker do diff --git a/spec/lib/gitlab/dependency_linker/composer_json_linker_spec.rb b/spec/lib/gitlab/dependency_linker/composer_json_linker_spec.rb index 0ebd8994636..6bef6f57e64 100644 --- a/spec/lib/gitlab/dependency_linker/composer_json_linker_spec.rb +++ b/spec/lib/gitlab/dependency_linker/composer_json_linker_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe Gitlab::DependencyLinker::ComposerJsonLinker do diff --git a/spec/lib/gitlab/dependency_linker/gemfile_linker_spec.rb b/spec/lib/gitlab/dependency_linker/gemfile_linker_spec.rb index f00f6b47b94..6ecdb0d1247 100644 --- a/spec/lib/gitlab/dependency_linker/gemfile_linker_spec.rb +++ b/spec/lib/gitlab/dependency_linker/gemfile_linker_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe Gitlab::DependencyLinker::GemfileLinker do diff --git a/spec/lib/gitlab/dependency_linker/gemspec_linker_spec.rb b/spec/lib/gitlab/dependency_linker/gemspec_linker_spec.rb index 6c6a5d70576..256fe58925c 100644 --- a/spec/lib/gitlab/dependency_linker/gemspec_linker_spec.rb +++ b/spec/lib/gitlab/dependency_linker/gemspec_linker_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe Gitlab::DependencyLinker::GemspecLinker do diff --git a/spec/lib/gitlab/dependency_linker/godeps_json_linker_spec.rb b/spec/lib/gitlab/dependency_linker/godeps_json_linker_spec.rb index ae5ad39ad11..f620d1b590c 100644 --- a/spec/lib/gitlab/dependency_linker/godeps_json_linker_spec.rb +++ b/spec/lib/gitlab/dependency_linker/godeps_json_linker_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe Gitlab::DependencyLinker::GodepsJsonLinker do diff --git a/spec/lib/gitlab/dependency_linker/package_json_linker_spec.rb b/spec/lib/gitlab/dependency_linker/package_json_linker_spec.rb index 9050127af7f..71e9381eaad 100644 --- a/spec/lib/gitlab/dependency_linker/package_json_linker_spec.rb +++ b/spec/lib/gitlab/dependency_linker/package_json_linker_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe Gitlab::DependencyLinker::PackageJsonLinker do diff --git a/spec/lib/gitlab/dependency_linker/podfile_linker_spec.rb b/spec/lib/gitlab/dependency_linker/podfile_linker_spec.rb index 8f1b523653e..eb81bc07760 100644 --- a/spec/lib/gitlab/dependency_linker/podfile_linker_spec.rb +++ b/spec/lib/gitlab/dependency_linker/podfile_linker_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe Gitlab::DependencyLinker::PodfileLinker do diff --git a/spec/lib/gitlab/dependency_linker/podspec_json_linker_spec.rb b/spec/lib/gitlab/dependency_linker/podspec_json_linker_spec.rb index d4a398c5948..938726dd434 100644 --- a/spec/lib/gitlab/dependency_linker/podspec_json_linker_spec.rb +++ b/spec/lib/gitlab/dependency_linker/podspec_json_linker_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe Gitlab::DependencyLinker::PodspecJsonLinker do diff --git a/spec/lib/gitlab/dependency_linker/podspec_linker_spec.rb b/spec/lib/gitlab/dependency_linker/podspec_linker_spec.rb index bacec830103..540eb2fadfe 100644 --- a/spec/lib/gitlab/dependency_linker/podspec_linker_spec.rb +++ b/spec/lib/gitlab/dependency_linker/podspec_linker_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe Gitlab::DependencyLinker::PodspecLinker do diff --git a/spec/lib/gitlab/dependency_linker/requirements_txt_linker_spec.rb b/spec/lib/gitlab/dependency_linker/requirements_txt_linker_spec.rb index ef952b3abd5..957a87985a2 100644 --- a/spec/lib/gitlab/dependency_linker/requirements_txt_linker_spec.rb +++ b/spec/lib/gitlab/dependency_linker/requirements_txt_linker_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe Gitlab::DependencyLinker::RequirementsTxtLinker do diff --git a/spec/lib/gitlab/dependency_linker_spec.rb b/spec/lib/gitlab/dependency_linker_spec.rb index 10d2f701298..98e46d62ca0 100644 --- a/spec/lib/gitlab/dependency_linker_spec.rb +++ b/spec/lib/gitlab/dependency_linker_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe Gitlab::DependencyLinker do diff --git a/spec/lib/gitlab/diff/diff_refs_spec.rb b/spec/lib/gitlab/diff/diff_refs_spec.rb index f9bfb4c469e..e12b46c15ad 100644 --- a/spec/lib/gitlab/diff/diff_refs_spec.rb +++ b/spec/lib/gitlab/diff/diff_refs_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Diff::DiffRefs do diff --git a/spec/lib/gitlab/diff/file_collection/merge_request_diff_spec.rb b/spec/lib/gitlab/diff/file_collection/merge_request_diff_spec.rb index 0697594c725..d89be6fef4e 100644 --- a/spec/lib/gitlab/diff/file_collection/merge_request_diff_spec.rb +++ b/spec/lib/gitlab/diff/file_collection/merge_request_diff_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Diff::FileCollection::MergeRequestDiff do diff --git a/spec/lib/gitlab/diff/file_spec.rb b/spec/lib/gitlab/diff/file_spec.rb index cc36060f864..716fc8ae987 100644 --- a/spec/lib/gitlab/diff/file_spec.rb +++ b/spec/lib/gitlab/diff/file_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Diff::File do diff --git a/spec/lib/gitlab/diff/formatters/image_formatter_spec.rb b/spec/lib/gitlab/diff/formatters/image_formatter_spec.rb index 2f99febe04e..2e6eb71d37d 100644 --- a/spec/lib/gitlab/diff/formatters/image_formatter_spec.rb +++ b/spec/lib/gitlab/diff/formatters/image_formatter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Diff::Formatters::ImageFormatter do diff --git a/spec/lib/gitlab/diff/formatters/text_formatter_spec.rb b/spec/lib/gitlab/diff/formatters/text_formatter_spec.rb index 897dc917f6a..33d4994f5db 100644 --- a/spec/lib/gitlab/diff/formatters/text_formatter_spec.rb +++ b/spec/lib/gitlab/diff/formatters/text_formatter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Diff::Formatters::TextFormatter do diff --git a/spec/lib/gitlab/diff/highlight_spec.rb b/spec/lib/gitlab/diff/highlight_spec.rb index 5d0a603d11d..f5d3d14ccc5 100644 --- a/spec/lib/gitlab/diff/highlight_spec.rb +++ b/spec/lib/gitlab/diff/highlight_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Diff::Highlight do diff --git a/spec/lib/gitlab/diff/inline_diff_markdown_marker_spec.rb b/spec/lib/gitlab/diff/inline_diff_markdown_marker_spec.rb index 7e17437fa2a..a668bb464a4 100644 --- a/spec/lib/gitlab/diff/inline_diff_markdown_marker_spec.rb +++ b/spec/lib/gitlab/diff/inline_diff_markdown_marker_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Diff::InlineDiffMarkdownMarker do diff --git a/spec/lib/gitlab/diff/inline_diff_marker_spec.rb b/spec/lib/gitlab/diff/inline_diff_marker_spec.rb index 97e65318059..26b99870b31 100644 --- a/spec/lib/gitlab/diff/inline_diff_marker_spec.rb +++ b/spec/lib/gitlab/diff/inline_diff_marker_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Diff::InlineDiffMarker do diff --git a/spec/lib/gitlab/diff/inline_diff_spec.rb b/spec/lib/gitlab/diff/inline_diff_spec.rb index 0a41362f606..fdbee3b4230 100644 --- a/spec/lib/gitlab/diff/inline_diff_spec.rb +++ b/spec/lib/gitlab/diff/inline_diff_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Diff::InlineDiff do diff --git a/spec/lib/gitlab/diff/line_mapper_spec.rb b/spec/lib/gitlab/diff/line_mapper_spec.rb index 42750bf9ea1..1739bcd14a8 100644 --- a/spec/lib/gitlab/diff/line_mapper_spec.rb +++ b/spec/lib/gitlab/diff/line_mapper_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Diff::LineMapper do diff --git a/spec/lib/gitlab/diff/line_spec.rb b/spec/lib/gitlab/diff/line_spec.rb index 76d411973c7..29b9951ba4c 100644 --- a/spec/lib/gitlab/diff/line_spec.rb +++ b/spec/lib/gitlab/diff/line_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + describe Gitlab::Diff::Line do describe '.init_from_hash' do it 'round-trips correctly with to_hash' do diff --git a/spec/lib/gitlab/diff/parallel_diff_spec.rb b/spec/lib/gitlab/diff/parallel_diff_spec.rb index e9fc7be366a..7540da71086 100644 --- a/spec/lib/gitlab/diff/parallel_diff_spec.rb +++ b/spec/lib/gitlab/diff/parallel_diff_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Diff::ParallelDiff do diff --git a/spec/lib/gitlab/diff/parser_spec.rb b/spec/lib/gitlab/diff/parser_spec.rb index 80c8c189665..00a446c4e20 100644 --- a/spec/lib/gitlab/diff/parser_spec.rb +++ b/spec/lib/gitlab/diff/parser_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Diff::Parser do diff --git a/spec/lib/gitlab/diff/position_spec.rb b/spec/lib/gitlab/diff/position_spec.rb index b755cd1aff0..399787635c0 100644 --- a/spec/lib/gitlab/diff/position_spec.rb +++ b/spec/lib/gitlab/diff/position_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Diff::Position do diff --git a/spec/lib/gitlab/diff/position_tracer_spec.rb b/spec/lib/gitlab/diff/position_tracer_spec.rb index 79b33d4d276..47d78e0b18c 100644 --- a/spec/lib/gitlab/diff/position_tracer_spec.rb +++ b/spec/lib/gitlab/diff/position_tracer_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Diff::PositionTracer do diff --git a/spec/lib/gitlab/downtime_check/message_spec.rb b/spec/lib/gitlab/downtime_check/message_spec.rb index a5a398abf78..2beb5a19a32 100644 --- a/spec/lib/gitlab/downtime_check/message_spec.rb +++ b/spec/lib/gitlab/downtime_check/message_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::DowntimeCheck::Message do diff --git a/spec/lib/gitlab/downtime_check_spec.rb b/spec/lib/gitlab/downtime_check_spec.rb index 1f1e4e0216c..56ad49d528f 100644 --- a/spec/lib/gitlab/downtime_check_spec.rb +++ b/spec/lib/gitlab/downtime_check_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::DowntimeCheck do diff --git a/spec/lib/gitlab/email/attachment_uploader_spec.rb b/spec/lib/gitlab/email/attachment_uploader_spec.rb index 45c690842bc..d66a746284d 100644 --- a/spec/lib/gitlab/email/attachment_uploader_spec.rb +++ b/spec/lib/gitlab/email/attachment_uploader_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "spec_helper" describe Gitlab::Email::AttachmentUploader do diff --git a/spec/lib/gitlab/email/hook/additional_headers_interceptor_spec.rb b/spec/lib/gitlab/email/hook/additional_headers_interceptor_spec.rb index ae61ece8029..65e4e27d56f 100644 --- a/spec/lib/gitlab/email/hook/additional_headers_interceptor_spec.rb +++ b/spec/lib/gitlab/email/hook/additional_headers_interceptor_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Email::Hook::AdditionalHeadersInterceptor do diff --git a/spec/lib/gitlab/email/hook/delivery_metrics_observer_spec.rb b/spec/lib/gitlab/email/hook/delivery_metrics_observer_spec.rb index 4497d4002da..24da47c42ac 100644 --- a/spec/lib/gitlab/email/hook/delivery_metrics_observer_spec.rb +++ b/spec/lib/gitlab/email/hook/delivery_metrics_observer_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Email::Hook::DeliveryMetricsObserver do diff --git a/spec/lib/gitlab/email/hook/disable_email_interceptor_spec.rb b/spec/lib/gitlab/email/hook/disable_email_interceptor_spec.rb index 91aa3bc7c2e..0c58cf088cc 100644 --- a/spec/lib/gitlab/email/hook/disable_email_interceptor_spec.rb +++ b/spec/lib/gitlab/email/hook/disable_email_interceptor_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Email::Hook::DisableEmailInterceptor do diff --git a/spec/lib/gitlab/email/message/repository_push_spec.rb b/spec/lib/gitlab/email/message/repository_push_spec.rb index 0ec1f931037..84c5b38127e 100644 --- a/spec/lib/gitlab/email/message/repository_push_spec.rb +++ b/spec/lib/gitlab/email/message/repository_push_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Email::Message::RepositoryPush do diff --git a/spec/lib/gitlab/email/receiver_spec.rb b/spec/lib/gitlab/email/receiver_spec.rb index 0af978eced3..c9fde06cbae 100644 --- a/spec/lib/gitlab/email/receiver_spec.rb +++ b/spec/lib/gitlab/email/receiver_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Email::Receiver do diff --git a/spec/lib/gitlab/email/reply_parser_spec.rb b/spec/lib/gitlab/email/reply_parser_spec.rb index 376d3accd55..646575b2edd 100644 --- a/spec/lib/gitlab/email/reply_parser_spec.rb +++ b/spec/lib/gitlab/email/reply_parser_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "spec_helper" # Inspired in great part by Discourse's Email::Receiver diff --git a/spec/lib/gitlab/encoding_helper_spec.rb b/spec/lib/gitlab/encoding_helper_spec.rb index 88ea98eb1e1..b24b71522ec 100644 --- a/spec/lib/gitlab/encoding_helper_spec.rb +++ b/spec/lib/gitlab/encoding_helper_spec.rb @@ -1,4 +1,6 @@ # coding: utf-8 +# frozen_string_literal: true + require "spec_helper" describe Gitlab::EncodingHelper do @@ -9,8 +11,8 @@ describe Gitlab::EncodingHelper do [ ["nil", nil, nil], ["empty string", "".encode("ASCII-8BIT"), "".encode("UTF-8")], - ["invalid utf-8 encoded string", "my bad string\xE5".force_encoding("UTF-8"), "my bad string"], - ["frozen non-ascii string", "é".force_encoding("ASCII-8BIT").freeze, "é".encode("UTF-8")], + ["invalid utf-8 encoded string", (+"my bad string\xE5").force_encoding("UTF-8"), "my bad string"], + ["frozen non-ascii string", (+"é").force_encoding("ASCII-8BIT").freeze, "é".encode("UTF-8")], [ 'leaves ascii only string as is', 'ascii only string', @@ -23,7 +25,7 @@ describe Gitlab::EncodingHelper do ], [ 'removes invalid bytes from ASCII-8bit encoded multibyte string. This can occur when a git diff match line truncates in the middle of a multibyte character. This occurs after the second word in this example. The test string is as short as we can get while still triggering the error condition when not looking at `detect[:confidence]`.', - "mu ns\xC3\n Lorem ipsum dolor sit amet, consectetur adipisicing ut\xC3\xA0y\xC3\xB9abcd\xC3\xB9efg kia elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non p\n {: .normal_pn}\n \n-Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in\n# *Lorem ipsum\xC3\xB9l\xC3\xB9l\xC3\xA0 dolor\xC3\xB9k\xC3\xB9 sit\xC3\xA8b\xC3\xA8 N\xC3\xA8 amet b\xC3\xA0d\xC3\xAC*\n+# *consectetur\xC3\xB9l\xC3\xB9l\xC3\xA0 adipisicing\xC3\xB9k\xC3\xB9 elit\xC3\xA8b\xC3\xA8 N\xC3\xA8 sed do\xC3\xA0d\xC3\xAC*{: .italic .smcaps}\n \n \xEF\x9B\xA1 eiusmod tempor incididunt, ut\xC3\xAAn\xC3\xB9 labore et dolore. Tw\xC4\x83nj\xC3\xAC magna aliqua. Ut enim ad minim veniam\n {: .normal}\n@@ -9,5 +9,5 @@ quis nostrud\xC3\xAAt\xC3\xB9 exercitiation ullamco laboris m\xC3\xB9s\xC3\xB9k\xC3\xB9abc\xC3\xB9 nisi ".force_encoding('ASCII-8BIT'), + (+"mu ns\xC3\n Lorem ipsum dolor sit amet, consectetur adipisicing ut\xC3\xA0y\xC3\xB9abcd\xC3\xB9efg kia elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non p\n {: .normal_pn}\n \n-Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in\n# *Lorem ipsum\xC3\xB9l\xC3\xB9l\xC3\xA0 dolor\xC3\xB9k\xC3\xB9 sit\xC3\xA8b\xC3\xA8 N\xC3\xA8 amet b\xC3\xA0d\xC3\xAC*\n+# *consectetur\xC3\xB9l\xC3\xB9l\xC3\xA0 adipisicing\xC3\xB9k\xC3\xB9 elit\xC3\xA8b\xC3\xA8 N\xC3\xA8 sed do\xC3\xA0d\xC3\xAC*{: .italic .smcaps}\n \n \xEF\x9B\xA1 eiusmod tempor incididunt, ut\xC3\xAAn\xC3\xB9 labore et dolore. Tw\xC4\x83nj\xC3\xAC magna aliqua. Ut enim ad minim veniam\n {: .normal}\n@@ -9,5 +9,5 @@ quis nostrud\xC3\xAAt\xC3\xB9 exercitiation ullamco laboris m\xC3\xB9s\xC3\xB9k\xC3\xB9abc\xC3\xB9 nisi ").force_encoding('ASCII-8BIT'), "mu ns\n Lorem ipsum dolor sit amet, consectetur adipisicing ut\xC3\xA0y\xC3\xB9abcd\xC3\xB9efg kia elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non p\n {: .normal_pn}\n \n-Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in\n# *Lorem ipsum\xC3\xB9l\xC3\xB9l\xC3\xA0 dolor\xC3\xB9k\xC3\xB9 sit\xC3\xA8b\xC3\xA8 N\xC3\xA8 amet b\xC3\xA0d\xC3\xAC*\n+# *consectetur\xC3\xB9l\xC3\xB9l\xC3\xA0 adipisicing\xC3\xB9k\xC3\xB9 elit\xC3\xA8b\xC3\xA8 N\xC3\xA8 sed do\xC3\xA0d\xC3\xAC*{: .italic .smcaps}\n \n \xEF\x9B\xA1 eiusmod tempor incididunt, ut\xC3\xAAn\xC3\xB9 labore et dolore. Tw\xC4\x83nj\xC3\xAC magna aliqua. Ut enim ad minim veniam\n {: .normal}\n@@ -9,5 +9,5 @@ quis nostrud\xC3\xAAt\xC3\xB9 exercitiation ullamco laboris m\xC3\xB9s\xC3\xB9k\xC3\xB9abc\xC3\xB9 nisi " ], [ @@ -93,7 +95,7 @@ describe Gitlab::EncodingHelper do [ ["nil", nil, nil], ["empty string", "".encode("ASCII-8BIT"), "".encode("UTF-8")], - ["invalid utf-8 encoded string", "my bad string\xE5".force_encoding("UTF-8"), "my bad stringå"], + ["invalid utf-8 encoded string", (+"my bad string\xE5").force_encoding("UTF-8"), "my bad stringå"], [ "encodes valid utf8 encoded string to utf8", "λ, λ, λ".encode("UTF-8"), @@ -160,12 +162,12 @@ describe Gitlab::EncodingHelper do ], [ 'removes invalid bytes from ASCII-8bit encoded multibyte string.', - "Lorem ipsum\xC3\n dolor sit amet, xy\xC3\xA0y\xC3\xB9abcd\xC3\xB9efg".force_encoding('ASCII-8BIT'), + (+"Lorem ipsum\xC3\n dolor sit amet, xy\xC3\xA0y\xC3\xB9abcd\xC3\xB9efg").force_encoding('ASCII-8BIT'), "Lorem ipsum\n dolor sit amet, xyàyùabcdùefg" ], [ 'handles UTF-16BE encoded strings', - "\xFE\xFF\x00\x41".force_encoding('ASCII-8BIT'), # An "A" prepended with UTF-16 BOM + (+"\xFE\xFF\x00\x41").force_encoding('ASCII-8BIT'), # An "A" prepended with UTF-16 BOM "\xEF\xBB\xBFA" # An "A" prepended with UTF-8 BOM ] ].each do |description, test_string, xpect| diff --git a/spec/lib/gitlab/etag_caching/middleware_spec.rb b/spec/lib/gitlab/etag_caching/middleware_spec.rb index 4a54d641b4e..9ead55075fa 100644 --- a/spec/lib/gitlab/etag_caching/middleware_spec.rb +++ b/spec/lib/gitlab/etag_caching/middleware_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::EtagCaching::Middleware do diff --git a/spec/lib/gitlab/etag_caching/router_spec.rb b/spec/lib/gitlab/etag_caching/router_spec.rb index a7cb0bb2a87..fbc49d894a6 100644 --- a/spec/lib/gitlab/etag_caching/router_spec.rb +++ b/spec/lib/gitlab/etag_caching/router_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::EtagCaching::Router do diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb index 41b898df112..dccd50bc472 100644 --- a/spec/lib/gitlab/git/repository_spec.rb +++ b/spec/lib/gitlab/git/repository_spec.rb @@ -186,6 +186,12 @@ describe Gitlab::Git::Repository, :seed_helper do it { is_expected.to be < 2 } end + describe '#to_s' do + subject { repository.to_s } + + it { is_expected.to eq("<Gitlab::Git::Repository: group/project>") } + end + describe '#object_directory_size' do before do allow(repository.gitaly_repository_client) diff --git a/spec/lib/gitlab/git/rugged_impl/use_rugged_spec.rb b/spec/lib/gitlab/git/rugged_impl/use_rugged_spec.rb index e437647c258..1a4168f7317 100644 --- a/spec/lib/gitlab/git/rugged_impl/use_rugged_spec.rb +++ b/spec/lib/gitlab/git/rugged_impl/use_rugged_spec.rb @@ -16,7 +16,13 @@ describe Gitlab::Git::RuggedImpl::UseRugged, :seed_helper do end subject(:wrapper) do - klazz = Class.new { include Gitlab::Git::RuggedImpl::UseRugged } + klazz = Class.new do + include Gitlab::Git::RuggedImpl::UseRugged + + def rugged_test(ref, test_number) + end + end + klazz.new end @@ -25,6 +31,23 @@ describe Gitlab::Git::RuggedImpl::UseRugged, :seed_helper do Gitlab::GitalyClient.instance_variable_set(:@can_use_disk, {}) end + context '#execute_rugged_call', :request_store do + let(:args) { ['refs/heads/master', 1] } + + before do + allow(Gitlab::RuggedInstrumentation).to receive(:peek_enabled?).and_return(true) + end + + it 'instruments Rugged call' do + expect(subject).to receive(:rugged_test).with(args) + + subject.execute_rugged_call(:rugged_test, args) + + expect(Gitlab::RuggedInstrumentation.query_count).to eq(1) + expect(Gitlab::RuggedInstrumentation.list_call_details.count).to eq(1) + end + end + context 'when feature flag is not persisted' do before do allow(Feature).to receive(:persisted?).with(feature_flag).and_return(false) diff --git a/spec/lib/gitlab/gitaly_client_spec.rb b/spec/lib/gitlab/gitaly_client_spec.rb index e1d24ae8977..e9fb6c0125c 100644 --- a/spec/lib/gitlab/gitaly_client_spec.rb +++ b/spec/lib/gitlab/gitaly_client_spec.rb @@ -17,6 +17,16 @@ describe Gitlab::GitalyClient do }) end + describe '.filesystem_id_from_disk' do + it 'catches errors' do + [Errno::ENOENT, Errno::EACCES, JSON::ParserError].each do |error| + allow(File).to receive(:read).with(described_class.storage_metadata_file_path('default')).and_raise(error) + + expect(described_class.filesystem_id_from_disk('default')).to be_nil + end + end + end + describe '.stub_class' do it 'returns the gRPC health check stub' do expect(described_class.stub_class(:health_check)).to eq(::Grpc::Health::V1::Health::Stub) diff --git a/spec/lib/gitlab/group_search_results_spec.rb b/spec/lib/gitlab/group_search_results_spec.rb index 2734fcef0a0..53a91a35ec9 100644 --- a/spec/lib/gitlab/group_search_results_spec.rb +++ b/spec/lib/gitlab/group_search_results_spec.rb @@ -20,7 +20,7 @@ describe Gitlab::GroupSearchResults do expect(result).to eq [user1] end - it 'returns the user belonging to the subgroup matching the search query', :nested_groups do + it 'returns the user belonging to the subgroup matching the search query' do user1 = create(:user, username: 'gob_bluth') subgroup = create(:group, parent: group) create(:group_member, :developer, user: user1, group: subgroup) @@ -32,7 +32,7 @@ describe Gitlab::GroupSearchResults do expect(result).to eq [user1] end - it 'returns the user belonging to the parent group matching the search query', :nested_groups do + it 'returns the user belonging to the parent group matching the search query' do user1 = create(:user, username: 'gob_bluth') parent_group = create(:group, children: [group]) create(:group_member, :developer, user: user1, group: parent_group) @@ -44,7 +44,7 @@ describe Gitlab::GroupSearchResults do expect(result).to eq [user1] end - it 'does not return the user belonging to the private subgroup', :nested_groups do + it 'does not return the user belonging to the private subgroup' do user1 = create(:user, username: 'gob_bluth') subgroup = create(:group, :private, parent: group) create(:group_member, :developer, user: user1, group: subgroup) diff --git a/spec/lib/gitlab/http_connection_adapter_spec.rb b/spec/lib/gitlab/http_connection_adapter_spec.rb index 930d1f62272..1532fd1103e 100644 --- a/spec/lib/gitlab/http_connection_adapter_spec.rb +++ b/spec/lib/gitlab/http_connection_adapter_spec.rb @@ -3,7 +3,13 @@ require 'spec_helper' describe Gitlab::HTTPConnectionAdapter do + include StubRequests + describe '#connection' do + before do + stub_all_dns('https://example.org', ip_address: '93.184.216.34') + end + context 'when local requests are not allowed' do it 'sets up the connection' do uri = URI('https://example.org') diff --git a/spec/lib/gitlab/import_export/lfs_restorer_spec.rb b/spec/lib/gitlab/import_export/lfs_restorer_spec.rb index 70eeb9ee66b..2b0bdb909ae 100644 --- a/spec/lib/gitlab/import_export/lfs_restorer_spec.rb +++ b/spec/lib/gitlab/import_export/lfs_restorer_spec.rb @@ -6,6 +6,7 @@ describe Gitlab::ImportExport::LfsRestorer do let(:export_path) { "#{Dir.tmpdir}/lfs_object_restorer_spec" } let(:project) { create(:project) } let(:shared) { project.import_export_shared } + let(:saver) { Gitlab::ImportExport::LfsSaver.new(project: project, shared: shared) } subject(:restorer) { described_class.new(project: project, shared: shared) } before do @@ -19,49 +20,98 @@ describe Gitlab::ImportExport::LfsRestorer do describe '#restore' do context 'when the archive contains lfs files' do - let(:dummy_lfs_file_path) { File.join(shared.export_path, 'lfs-objects', 'dummy') } - - def create_lfs_object_with_content(content) - dummy_lfs_file = Tempfile.new('existing') - File.write(dummy_lfs_file.path, content) - size = dummy_lfs_file.size - oid = LfsObject.calculate_oid(dummy_lfs_file.path) - LfsObject.create!(oid: oid, size: size, file: dummy_lfs_file) + let(:lfs_object) { create(:lfs_object, :correct_oid, :with_file) } + + # Use the LfsSaver to save data to be restored + def save_lfs_data + %w(project wiki).each do |repository_type| + create( + :lfs_objects_project, + project: project, + repository_type: repository_type, + lfs_object: lfs_object + ) + end + + saver.save + + project.lfs_objects.delete_all end before do - FileUtils.mkdir_p(File.dirname(dummy_lfs_file_path)) - File.write(dummy_lfs_file_path, 'not very large') - allow(restorer).to receive(:lfs_file_paths).and_return([dummy_lfs_file_path]) + save_lfs_data + project.reload end - it 'creates an lfs object for the project' do - expect { restorer.restore }.to change { project.reload.lfs_objects.size }.by(1) + it 'succeeds' do + expect(restorer.restore).to eq(true) + expect(shared.errors).to be_empty end - it 'assigns the file correctly' do + it 'does not create a new `LfsObject` records, as one already exists' do + expect { restorer.restore }.not_to change { LfsObject.count } + end + + it 'creates new `LfsObjectsProject` records in order to link the project to the existing `LfsObject`' do + expect { restorer.restore }.to change { LfsObjectsProject.count }.by(2) + end + + it 'restores the correct `LfsObject` records' do restorer.restore - expect(project.lfs_objects.first.file.read).to eq('not very large') + expect(project.lfs_objects).to contain_exactly(lfs_object) end - it 'links an existing LFS object if it existed' do - lfs_object = create_lfs_object_with_content('not very large') + it 'restores the correct `LfsObjectsProject` records for the project' do + restorer.restore + expect( + project.lfs_objects_projects.pluck(:repository_type) + ).to contain_exactly('project', 'wiki') + end + + it 'assigns the file correctly' do restorer.restore - expect(project.lfs_objects).to include(lfs_object) + expect(project.lfs_objects.first.file.read).to eq(lfs_object.file.read) end - it 'succeeds' do - expect(restorer.restore).to be_truthy - expect(shared.errors).to be_empty + context 'when there is not an existing `LfsObject`' do + before do + lfs_object.destroy + end + + it 'creates a new lfs object' do + expect { restorer.restore }.to change { LfsObject.count }.by(1) + end + + it 'stores the upload' do + expect_any_instance_of(LfsObjectUploader).to receive(:store!) + + restorer.restore + end end - it 'stores the upload' do - expect_any_instance_of(LfsObjectUploader).to receive(:store!) + context 'when there is no lfs-objects.json file' do + before do + json_file = File.join(shared.export_path, ::Gitlab::ImportExport.lfs_objects_filename) - restorer.restore + FileUtils.rm_rf(json_file) + end + + it 'restores the correct `LfsObject` records' do + restorer.restore + + expect(project.lfs_objects).to contain_exactly(lfs_object) + end + + it 'restores a single `LfsObjectsProject` record for the project with "project" for the `repository_type`' do + restorer.restore + + expect( + project.lfs_objects_projects.pluck(:repository_type) + ).to contain_exactly('project') + end end end diff --git a/spec/lib/gitlab/import_export/lfs_saver_spec.rb b/spec/lib/gitlab/import_export/lfs_saver_spec.rb index 9b0e21deb2e..c3c88486e16 100644 --- a/spec/lib/gitlab/import_export/lfs_saver_spec.rb +++ b/spec/lib/gitlab/import_export/lfs_saver_spec.rb @@ -19,6 +19,11 @@ describe Gitlab::ImportExport::LfsSaver do describe '#save' do context 'when the project has LFS objects locally stored' do let(:lfs_object) { create(:lfs_object, :with_file) } + let(:lfs_json_file) { File.join(shared.export_path, Gitlab::ImportExport.lfs_objects_filename) } + + def lfs_json + JSON.parse(IO.read(lfs_json_file)) + end before do project.lfs_objects << lfs_object @@ -35,6 +40,45 @@ describe Gitlab::ImportExport::LfsSaver do expect(File).to exist("#{shared.export_path}/lfs-objects/#{lfs_object.oid}") end + + describe 'saving a json file' do + before do + # Create two more LfsObjectProject records with different `repository_type`s + %w(wiki design).each do |repository_type| + create( + :lfs_objects_project, + project: project, + repository_type: repository_type, + lfs_object: lfs_object + ) + end + + FileUtils.rm_rf(lfs_json_file) + end + + it 'saves a json file correctly' do + saver.save + + expect(File.exist?(lfs_json_file)).to eq(true) + expect(lfs_json).to eq( + { + lfs_object.oid => [ + LfsObjectsProject.repository_types['wiki'], + LfsObjectsProject.repository_types['design'], + nil + ] + } + ) + end + + it 'does not save a json file if feature is disabled' do + stub_feature_flags(export_lfs_objects_projects: false) + + saver.save + + expect(File.exist?(lfs_json_file)).to eq(false) + end + end end context 'when the LFS objects are stored in object storage' do @@ -42,8 +86,11 @@ describe Gitlab::ImportExport::LfsSaver do before do allow(LfsObjectUploader).to receive(:object_store_enabled?).and_return(true) - allow(lfs_object.file).to receive(:url).and_return('http://my-object-storage.local') project.lfs_objects << lfs_object + + expect_next_instance_of(LfsObjectUploader) do |instance| + expect(instance).to receive(:url).and_return('http://my-object-storage.local') + end end it 'downloads the file to include in an archive' do diff --git a/spec/lib/gitlab/import_export/project.group.json b/spec/lib/gitlab/import_export/project.group.json index 1a561e81e4a..66f5bb4c87b 100644 --- a/spec/lib/gitlab/import_export/project.group.json +++ b/spec/lib/gitlab/import_export/project.group.json @@ -19,7 +19,7 @@ "labels": [ { "id": 2, - "title": "project label", + "title": "A project label", "color": "#428bca", "project_id": 8, "created_at": "2016-07-22T08:55:44.161Z", @@ -105,7 +105,7 @@ "updated_at": "2017-08-15T18:37:40.795Z", "label": { "id": 6, - "title": "project label", + "title": "A project label", "color": "#A8D695", "project_id": null, "created_at": "2017-08-15T18:37:19.698Z", @@ -162,7 +162,7 @@ "updated_at": "2017-08-15T18:37:40.795Z", "label": { "id": 2, - "title": "project label", + "title": "A project label", "color": "#A8D695", "project_id": null, "created_at": "2017-08-15T18:37:19.698Z", diff --git a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb index 3b7de185cf1..b9f6595762b 100644 --- a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb +++ b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb @@ -272,7 +272,7 @@ describe Gitlab::ImportExport::ProjectTreeRestorer do end it 'has label priorities' do - expect(project.labels.first.priorities).not_to be_empty + expect(project.labels.find_by(title: 'A project label').priorities).not_to be_empty end it 'has milestones' do @@ -325,7 +325,7 @@ describe Gitlab::ImportExport::ProjectTreeRestorer do it_behaves_like 'restores project correctly', issues: 1, - labels: 1, + labels: 2, milestones: 1, first_issue_labels: 1, services: 1 @@ -402,7 +402,7 @@ describe Gitlab::ImportExport::ProjectTreeRestorer do it_behaves_like 'restores project successfully' it_behaves_like 'restores project correctly', issues: 2, - labels: 1, + labels: 2, milestones: 2, first_issue_labels: 1 diff --git a/spec/lib/gitlab/import_export/project_tree_saver_spec.rb b/spec/lib/gitlab/import_export/project_tree_saver_spec.rb index 5f56c30c7e0..1ff2eb9210f 100644 --- a/spec/lib/gitlab/import_export/project_tree_saver_spec.rb +++ b/spec/lib/gitlab/import_export/project_tree_saver_spec.rb @@ -179,9 +179,9 @@ describe Gitlab::ImportExport::ProjectTreeSaver do end it 'has priorities associated to labels' do - priorities = saved_project_json['issues'].first['label_links'].map { |link| link['label']['priorities'] } + priorities = saved_project_json['issues'].first['label_links'].flat_map { |link| link['label']['priorities'] } - expect(priorities.flatten).not_to be_empty + expect(priorities).not_to be_empty end it 'has issue resource label events' do diff --git a/spec/lib/gitlab/manifest_import/manifest_spec.rb b/spec/lib/gitlab/manifest_import/manifest_spec.rb index ab305fb2316..ded93e23c08 100644 --- a/spec/lib/gitlab/manifest_import/manifest_spec.rb +++ b/spec/lib/gitlab/manifest_import/manifest_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::ManifestImport::Manifest, :postgresql do +describe Gitlab::ManifestImport::Manifest do let(:file) { File.open(Rails.root.join('spec/fixtures/aosp_manifest.xml')) } let(:manifest) { described_class.new(file) } diff --git a/spec/lib/gitlab/manifest_import/project_creator_spec.rb b/spec/lib/gitlab/manifest_import/project_creator_spec.rb index 1d01d437535..a7487972f51 100644 --- a/spec/lib/gitlab/manifest_import/project_creator_spec.rb +++ b/spec/lib/gitlab/manifest_import/project_creator_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::ManifestImport::ProjectCreator, :postgresql do +describe Gitlab::ManifestImport::ProjectCreator do let(:group) { create(:group) } let(:user) { create(:user) } let(:repository) do diff --git a/spec/lib/gitlab/metrics/dashboard/finder_spec.rb b/spec/lib/gitlab/metrics/dashboard/finder_spec.rb index d8ed54c0248..e57c7326320 100644 --- a/spec/lib/gitlab/metrics/dashboard/finder_spec.rb +++ b/spec/lib/gitlab/metrics/dashboard/finder_spec.rb @@ -8,7 +8,7 @@ describe Gitlab::Metrics::Dashboard::Finder, :use_clean_rails_memory_store_cachi set(:project) { build(:project) } set(:user) { create(:user) } set(:environment) { create(:environment, project: project) } - let(:system_dashboard_path) { Gitlab::Metrics::Dashboard::SystemDashboardService::SYSTEM_DASHBOARD_PATH} + let(:system_dashboard_path) { ::Metrics::Dashboard::SystemDashboardService::SYSTEM_DASHBOARD_PATH} before do project.add_maintainer(user) diff --git a/spec/lib/gitlab/metrics/dashboard/processor_spec.rb b/spec/lib/gitlab/metrics/dashboard/processor_spec.rb index 797d4daabe3..d7891e69dd0 100644 --- a/spec/lib/gitlab/metrics/dashboard/processor_spec.rb +++ b/spec/lib/gitlab/metrics/dashboard/processor_spec.rb @@ -101,9 +101,9 @@ describe Gitlab::Metrics::Dashboard::Processor do private def all_metrics - dashboard[:panel_groups].map do |group| - group[:panels].map { |panel| panel[:metrics] } - end.flatten + dashboard[:panel_groups].flat_map do |group| + group[:panels].flat_map { |panel| panel[:metrics] } + end end def get_metric_details(metric) diff --git a/spec/lib/gitlab/object_hierarchy_spec.rb b/spec/lib/gitlab/object_hierarchy_spec.rb index e6e9ae3223e..bfd456cdd7e 100644 --- a/spec/lib/gitlab/object_hierarchy_spec.rb +++ b/spec/lib/gitlab/object_hierarchy_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::ObjectHierarchy, :postgresql do +describe Gitlab::ObjectHierarchy do let!(:parent) { create(:group) } let!(:child1) { create(:group, parent: parent) } let!(:child2) { create(:group, parent: child1) } diff --git a/spec/lib/gitlab/octokit/middleware_spec.rb b/spec/lib/gitlab/octokit/middleware_spec.rb new file mode 100644 index 00000000000..7f2b523f5b7 --- /dev/null +++ b/spec/lib/gitlab/octokit/middleware_spec.rb @@ -0,0 +1,68 @@ +require 'spec_helper' + +describe Gitlab::Octokit::Middleware do + let(:app) { double(:app) } + let(:middleware) { described_class.new(app) } + + shared_examples 'Public URL' do + it 'does not raise an error' do + expect(app).to receive(:call).with(env) + + expect { middleware.call(env) }.not_to raise_error + end + end + + shared_examples 'Local URL' do + it 'raises an error' do + expect { middleware.call(env) }.to raise_error(Gitlab::UrlBlocker::BlockedUrlError) + end + end + + describe '#call' do + context 'when the URL is a public URL' do + let(:env) { { url: 'https://public-url.com' } } + + it_behaves_like 'Public URL' + end + + context 'when the URL is a localhost adresss' do + let(:env) { { url: 'http://127.0.0.1' } } + + context 'when localhost requests are not allowed' do + before do + stub_application_setting(allow_local_requests_from_hooks_and_services: false) + end + + it_behaves_like 'Local URL' + end + + context 'when localhost requests are allowed' do + before do + stub_application_setting(allow_local_requests_from_hooks_and_services: true) + end + + it_behaves_like 'Public URL' + end + end + + context 'when the URL is a local network address' do + let(:env) { { url: 'http://172.16.0.0' } } + + context 'when local network requests are not allowed' do + before do + stub_application_setting(allow_local_requests_from_hooks_and_services: false) + end + + it_behaves_like 'Local URL' + end + + context 'when local network requests are allowed' do + before do + stub_application_setting(allow_local_requests_from_hooks_and_services: true) + end + + it_behaves_like 'Public URL' + end + end + end +end diff --git a/spec/lib/gitlab/performance_bar_spec.rb b/spec/lib/gitlab/performance_bar_spec.rb index ee3c571c9c0..71c109db1f1 100644 --- a/spec/lib/gitlab/performance_bar_spec.rb +++ b/spec/lib/gitlab/performance_bar_spec.rb @@ -96,7 +96,7 @@ describe Gitlab::PerformanceBar do end end - context 'when allowed group is nested', :nested_groups do + context 'when allowed group is nested' do let!(:nested_my_group) { create(:group, parent: create(:group, path: 'my-org'), path: 'my-group') } before do @@ -110,7 +110,7 @@ describe Gitlab::PerformanceBar do end end - context 'when a nested group has the same path', :nested_groups do + context 'when a nested group has the same path' do before do create(:group, :nested, path: 'my-group').add_developer(user) end diff --git a/spec/lib/gitlab/project_authorizations_spec.rb b/spec/lib/gitlab/project_authorizations_spec.rb index bd0bc2c9044..75e2d5e1319 100644 --- a/spec/lib/gitlab/project_authorizations_spec.rb +++ b/spec/lib/gitlab/project_authorizations_spec.rb @@ -20,13 +20,7 @@ describe Gitlab::ProjectAuthorizations do end let(:authorizations) do - klass = if Group.supports_nested_objects? - Gitlab::ProjectAuthorizations::WithNestedGroups - else - Gitlab::ProjectAuthorizations::WithoutNestedGroups - end - - klass.new(user).calculate + described_class.new(user).calculate end it 'returns the correct number of authorizations' do @@ -46,28 +40,26 @@ describe Gitlab::ProjectAuthorizations do expect(mapping[group_project.id]).to eq(Gitlab::Access::DEVELOPER) end - if Group.supports_nested_objects? - context 'with nested groups' do - let!(:nested_group) { create(:group, parent: group) } - let!(:nested_project) { create(:project, namespace: nested_group) } + context 'with nested groups' do + let!(:nested_group) { create(:group, parent: group) } + let!(:nested_project) { create(:project, namespace: nested_group) } - it 'includes nested groups' do - expect(authorizations.pluck(:project_id)).to include(nested_project.id) - end + it 'includes nested groups' do + expect(authorizations.pluck(:project_id)).to include(nested_project.id) + end - it 'inherits access levels when the user is not a member of a nested group' do - mapping = map_access_levels(authorizations) + it 'inherits access levels when the user is not a member of a nested group' do + mapping = map_access_levels(authorizations) - expect(mapping[nested_project.id]).to eq(Gitlab::Access::DEVELOPER) - end + expect(mapping[nested_project.id]).to eq(Gitlab::Access::DEVELOPER) + end - it 'uses the greatest access level when a user is a member of a nested group' do - nested_group.add_maintainer(user) + it 'uses the greatest access level when a user is a member of a nested group' do + nested_group.add_maintainer(user) - mapping = map_access_levels(authorizations) + mapping = map_access_levels(authorizations) - expect(mapping[nested_project.id]).to eq(Gitlab::Access::MAINTAINER) - end + expect(mapping[nested_project.id]).to eq(Gitlab::Access::MAINTAINER) end end end diff --git a/spec/lib/gitlab/project_template_spec.rb b/spec/lib/gitlab/project_template_spec.rb index 8c2fc048a54..8b82ea7faa5 100644 --- a/spec/lib/gitlab/project_template_spec.rb +++ b/spec/lib/gitlab/project_template_spec.rb @@ -44,6 +44,12 @@ describe Gitlab::ProjectTemplate do end end + describe '.archive_directory' do + subject { described_class.archive_directory } + + it { is_expected.to be_a Pathname } + end + describe 'instance methods' do subject { described_class.new('phoenix', 'Phoenix Framework', 'Phoenix description', 'link-to-template') } diff --git a/spec/lib/gitlab/prometheus/metric_group_spec.rb b/spec/lib/gitlab/prometheus/metric_group_spec.rb index 5cc6827488b..a45dd0af91e 100644 --- a/spec/lib/gitlab/prometheus/metric_group_spec.rb +++ b/spec/lib/gitlab/prometheus/metric_group_spec.rb @@ -17,7 +17,7 @@ describe Gitlab::Prometheus::MetricGroup do end it 'returns exactly three metric queries' do - expect(subject.map(&:metrics).flatten.map(&:id)).to contain_exactly( + expect(subject.flat_map(&:metrics).map(&:id)).to contain_exactly( common_metric_group_a.id, common_metric_group_b_q1.id, common_metric_group_b_q2.id) end @@ -37,7 +37,7 @@ describe Gitlab::Prometheus::MetricGroup do subject do described_class.for_project(other_project) - .map(&:metrics).flatten + .flat_map(&:metrics) .map(&:id) end diff --git a/spec/lib/gitlab/quick_actions/command_definition_spec.rb b/spec/lib/gitlab/quick_actions/command_definition_spec.rb index b6e0adbc1c2..21f2c87a755 100644 --- a/spec/lib/gitlab/quick_actions/command_definition_spec.rb +++ b/spec/lib/gitlab/quick_actions/command_definition_spec.rb @@ -219,6 +219,52 @@ describe Gitlab::QuickActions::CommandDefinition do end end + describe "#execute_message" do + context "when the command is a noop" do + it 'returns nil' do + expect(subject.execute_message({}, nil)).to be_nil + end + end + + context "when the command is not a noop" do + before do + subject.action_block = proc { self.run = true } + end + + context "when the command is not available" do + before do + subject.condition_block = proc { false } + end + + it 'returns nil' do + expect(subject.execute_message({}, nil)).to be_nil + end + end + + context "when the command is available" do + context 'when the execution_message is a static string' do + before do + subject.execution_message = 'Assigned jacopo' + end + + it 'returns this static string' do + expect(subject.execute_message({}, nil)).to eq('Assigned jacopo') + end + end + + context 'when the explanation is dynamic' do + before do + subject.execution_message = proc { |arg| "Assigned #{arg}" } + end + + it 'invokes the proc' do + expect(subject.execute_message({}, 'Jacopo')).to eq('Assigned Jacopo') + end + end + end + end + end + describe '#explain' do context 'when the command is not available' do before do diff --git a/spec/lib/gitlab/quick_actions/dsl_spec.rb b/spec/lib/gitlab/quick_actions/dsl_spec.rb index 185adab1ff6..78b9b3804c3 100644 --- a/spec/lib/gitlab/quick_actions/dsl_spec.rb +++ b/spec/lib/gitlab/quick_actions/dsl_spec.rb @@ -20,6 +20,9 @@ describe Gitlab::QuickActions::Dsl do desc do "A dynamic description for #{noteable.upcase}" end + execution_message do |arg| + "A dynamic execution message for #{noteable.upcase} passing #{arg}" + end params 'The first argument', 'The second argument' command :dynamic_description do |args| args.split @@ -30,6 +33,7 @@ describe Gitlab::QuickActions::Dsl do explanation do |arg| "Action does something with #{arg}" end + execution_message 'Command applied correctly' condition do project == 'foo' end @@ -67,6 +71,7 @@ describe Gitlab::QuickActions::Dsl do expect(no_args_def.aliases).to eq([:none]) expect(no_args_def.description).to eq('A command with no args') expect(no_args_def.explanation).to eq('') + expect(no_args_def.execution_message).to eq('') expect(no_args_def.params).to eq([]) expect(no_args_def.condition_block).to be_nil expect(no_args_def.types).to eq([]) @@ -78,6 +83,8 @@ describe Gitlab::QuickActions::Dsl do expect(explanation_with_aliases_def.aliases).to eq([:once, :first]) expect(explanation_with_aliases_def.description).to eq('') expect(explanation_with_aliases_def.explanation).to eq('Static explanation') + expect(explanation_with_aliases_def.execution_message).to eq('') + expect(no_args_def.params).to eq([]) expect(explanation_with_aliases_def.params).to eq(['The first argument']) expect(explanation_with_aliases_def.condition_block).to be_nil expect(explanation_with_aliases_def.types).to eq([]) @@ -88,7 +95,7 @@ describe Gitlab::QuickActions::Dsl do expect(dynamic_description_def.name).to eq(:dynamic_description) expect(dynamic_description_def.aliases).to eq([]) expect(dynamic_description_def.to_h(OpenStruct.new(noteable: 'issue'))[:description]).to eq('A dynamic description for ISSUE') - expect(dynamic_description_def.explanation).to eq('') + expect(dynamic_description_def.execute_message(OpenStruct.new(noteable: 'issue'), 'arg')).to eq('A dynamic execution message for ISSUE passing arg') expect(dynamic_description_def.params).to eq(['The first argument', 'The second argument']) expect(dynamic_description_def.condition_block).to be_nil expect(dynamic_description_def.types).to eq([]) @@ -100,6 +107,7 @@ describe Gitlab::QuickActions::Dsl do expect(cc_def.aliases).to eq([]) expect(cc_def.description).to eq('') expect(cc_def.explanation).to eq('') + expect(cc_def.execution_message).to eq('') expect(cc_def.params).to eq([]) expect(cc_def.condition_block).to be_nil expect(cc_def.types).to eq([]) @@ -111,6 +119,7 @@ describe Gitlab::QuickActions::Dsl do expect(cond_action_def.aliases).to eq([]) expect(cond_action_def.description).to eq('') expect(cond_action_def.explanation).to be_a_kind_of(Proc) + expect(cond_action_def.execution_message).to eq('Command applied correctly') expect(cond_action_def.params).to eq([]) expect(cond_action_def.condition_block).to be_a_kind_of(Proc) expect(cond_action_def.types).to eq([]) @@ -122,6 +131,7 @@ describe Gitlab::QuickActions::Dsl do expect(with_params_parsing_def.aliases).to eq([]) expect(with_params_parsing_def.description).to eq('') expect(with_params_parsing_def.explanation).to eq('') + expect(with_params_parsing_def.execution_message).to eq('') expect(with_params_parsing_def.params).to eq([]) expect(with_params_parsing_def.condition_block).to be_nil expect(with_params_parsing_def.types).to eq([]) @@ -133,6 +143,7 @@ describe Gitlab::QuickActions::Dsl do expect(substitution_def.aliases).to eq([]) expect(substitution_def.description).to eq('') expect(substitution_def.explanation).to eq('') + expect(substitution_def.execution_message).to eq('') expect(substitution_def.params).to eq(['<Comment>']) expect(substitution_def.condition_block).to be_nil expect(substitution_def.types).to eq([]) @@ -144,6 +155,7 @@ describe Gitlab::QuickActions::Dsl do expect(has_types.aliases).to eq([]) expect(has_types.description).to eq('A command with types') expect(has_types.explanation).to eq('') + expect(has_types.execution_message).to eq('') expect(has_types.params).to eq([]) expect(has_types.condition_block).to be_nil expect(has_types.types).to eq([Issue, Commit]) diff --git a/spec/lib/gitlab/sidekiq_middleware/memory_killer_spec.rb b/spec/lib/gitlab/sidekiq_middleware/memory_killer_spec.rb index 1a5a38b5d99..b451844f06c 100644 --- a/spec/lib/gitlab/sidekiq_middleware/memory_killer_spec.rb +++ b/spec/lib/gitlab/sidekiq_middleware/memory_killer_spec.rb @@ -45,6 +45,9 @@ describe Gitlab::SidekiqMiddleware::MemoryKiller do expect(subject).to receive(:sleep).with(10).ordered expect(Process).to receive(:kill).with('SIGKILL', pid).ordered + expect(Sidekiq.logger) + .to receive(:warn).with(class: 'TestWorker', message: anything, pid: pid, signal: anything).at_least(:once) + run end diff --git a/spec/lib/gitlab/sidekiq_middleware/metrics_spec.rb b/spec/lib/gitlab/sidekiq_middleware/metrics_spec.rb new file mode 100644 index 00000000000..c6df1c6a0d8 --- /dev/null +++ b/spec/lib/gitlab/sidekiq_middleware/metrics_spec.rb @@ -0,0 +1,57 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::SidekiqMiddleware::Metrics do + describe '#call' do + let(:middleware) { described_class.new } + let(:worker) { double(:worker) } + + let(:completion_seconds_metric) { double('completion seconds metric') } + let(:failed_total_metric) { double('failed total metric') } + let(:retried_total_metric) { double('retried total metric') } + let(:running_jobs_metric) { double('running jobs metric') } + + before do + allow(Gitlab::Metrics).to receive(:histogram).with(:sidekiq_jobs_completion_seconds, anything).and_return(completion_seconds_metric) + allow(Gitlab::Metrics).to receive(:counter).with(:sidekiq_jobs_failed_total, anything).and_return(failed_total_metric) + allow(Gitlab::Metrics).to receive(:counter).with(:sidekiq_jobs_retried_total, anything).and_return(retried_total_metric) + allow(Gitlab::Metrics).to receive(:gauge).with(:sidekiq_running_jobs, anything, {}, :livesum).and_return(running_jobs_metric) + + allow(running_jobs_metric).to receive(:increment) + end + + it 'yields block' do + allow(completion_seconds_metric).to receive(:observe) + + expect { |b| middleware.call(worker, {}, :test, &b) }.to yield_control.once + end + + it 'sets metrics' do + labels = { queue: :test } + + expect(running_jobs_metric).to receive(:increment).with(labels, 1) + expect(running_jobs_metric).to receive(:increment).with(labels, -1) + expect(completion_seconds_metric).to receive(:observe).with(labels, kind_of(Numeric)) + + middleware.call(worker, {}, :test) { nil } + end + + context 'when job is retried' do + it 'sets sidekiq_jobs_retried_total metric' do + allow(completion_seconds_metric).to receive(:observe) + + expect(retried_total_metric).to receive(:increment) + + middleware.call(worker, { 'retry_count' => 1 }, :test) { nil } + end + end + + context 'when error is raised' do + it 'sets sidekiq_jobs_failed_total and reraises' do + expect(failed_total_metric).to receive(:increment) + expect { middleware.call(worker, {}, :test) { raise } }.to raise_error + end + end + end +end diff --git a/spec/lib/gitlab/sql/cte_spec.rb b/spec/lib/gitlab/sql/cte_spec.rb index d6763c7b2e1..5d2164491b5 100644 --- a/spec/lib/gitlab/sql/cte_spec.rb +++ b/spec/lib/gitlab/sql/cte_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::SQL::CTE, :postgresql do +describe Gitlab::SQL::CTE do describe '#to_arel' do it 'generates an Arel relation for the CTE body' do relation = User.where(id: 1) diff --git a/spec/lib/gitlab/sql/recursive_cte_spec.rb b/spec/lib/gitlab/sql/recursive_cte_spec.rb index 7fe39dd5a96..407a4d8a247 100644 --- a/spec/lib/gitlab/sql/recursive_cte_spec.rb +++ b/spec/lib/gitlab/sql/recursive_cte_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::SQL::RecursiveCTE, :postgresql do +describe Gitlab::SQL::RecursiveCTE do let(:cte) { described_class.new(:cte_name) } describe '#to_arel' do diff --git a/spec/lib/gitlab/submodule_links_spec.rb b/spec/lib/gitlab/submodule_links_spec.rb new file mode 100644 index 00000000000..a84602cd07d --- /dev/null +++ b/spec/lib/gitlab/submodule_links_spec.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::SubmoduleLinks do + let(:submodule_item) { double(id: 'hash', path: 'gitlab-ce') } + let(:repo) { double } + let(:links) { described_class.new(repo) } + + describe '#for' do + subject { links.for(submodule_item, 'ref') } + + context 'when there is no .gitmodules file' do + before do + stub_urls(nil) + end + + it 'returns no links' do + expect(subject).to eq([nil, nil]) + end + end + + context 'when the submodule is unknown' do + before do + stub_urls({ 'path' => 'url' }) + end + + it 'returns no links' do + expect(subject).to eq([nil, nil]) + end + end + + context 'when the submodule is known' do + before do + stub_urls({ 'gitlab-ce' => 'git@gitlab.com:gitlab-org/gitlab-ce.git' }) + end + + it 'returns links' do + expect(subject).to eq(['https://gitlab.com/gitlab-org/gitlab-ce', 'https://gitlab.com/gitlab-org/gitlab-ce/tree/hash']) + end + end + end + + def stub_urls(urls) + allow(repo).to receive(:submodule_urls_for).and_return(urls) + end +end diff --git a/spec/lib/gitlab/url_blocker_spec.rb b/spec/lib/gitlab/url_blocker_spec.rb index f8b0cbfb6f6..45d9022abeb 100644 --- a/spec/lib/gitlab/url_blocker_spec.rb +++ b/spec/lib/gitlab/url_blocker_spec.rb @@ -68,6 +68,16 @@ describe Gitlab::UrlBlocker do expect(uri).to eq(Addressable::URI.parse('https://example.org')) expect(hostname).to eq(nil) end + + context 'when it cannot be resolved' do + let(:import_url) { 'http://foobar.x' } + + it 'raises error' do + stub_env('RSPEC_ALLOW_INVALID_URLS', 'false') + + expect { described_class.validate!(import_url) }.to raise_error(described_class::BlockedUrlError) + end + end end context 'when the URL hostname is an IP address' do @@ -79,6 +89,16 @@ describe Gitlab::UrlBlocker do expect(uri).to eq(Addressable::URI.parse('https://93.184.216.34')) expect(hostname).to be(nil) end + + context 'when it is invalid' do + let(:import_url) { 'http://1.1.1.1.1' } + + it 'raises an error' do + stub_env('RSPEC_ALLOW_INVALID_URLS', 'false') + + expect { described_class.validate!(import_url) }.to raise_error(described_class::BlockedUrlError) + end + end end end end @@ -180,8 +200,6 @@ describe Gitlab::UrlBlocker do end it 'returns true for a non-alphanumeric hostname' do - stub_resolv - aggregate_failures do expect(described_class).to be_blocked_url('ssh://-oProxyCommand=whoami/a') @@ -220,53 +238,53 @@ describe Gitlab::UrlBlocker do end let(:fake_domain) { 'www.fakedomain.fake' } - context 'true (default)' do + shared_examples 'allows local requests' do |url_blocker_attributes| it 'does not block urls from private networks' do local_ips.each do |ip| - stub_domain_resolv(fake_domain, ip) - - expect(described_class).not_to be_blocked_url("http://#{fake_domain}") - - unstub_domain_resolv + stub_domain_resolv(fake_domain, ip) do + expect(described_class).not_to be_blocked_url("http://#{fake_domain}", url_blocker_attributes) + end - expect(described_class).not_to be_blocked_url("http://#{ip}") + expect(described_class).not_to be_blocked_url("http://#{ip}", url_blocker_attributes) end end it 'allows localhost endpoints' do - expect(described_class).not_to be_blocked_url('http://0.0.0.0', allow_localhost: true) - expect(described_class).not_to be_blocked_url('http://localhost', allow_localhost: true) - expect(described_class).not_to be_blocked_url('http://127.0.0.1', allow_localhost: true) + expect(described_class).not_to be_blocked_url('http://0.0.0.0', url_blocker_attributes) + expect(described_class).not_to be_blocked_url('http://localhost', url_blocker_attributes) + expect(described_class).not_to be_blocked_url('http://127.0.0.1', url_blocker_attributes) end it 'allows loopback endpoints' do - expect(described_class).not_to be_blocked_url('http://127.0.0.2', allow_localhost: true) + expect(described_class).not_to be_blocked_url('http://127.0.0.2', url_blocker_attributes) end it 'allows IPv4 link-local endpoints' do - expect(described_class).not_to be_blocked_url('http://169.254.169.254') - expect(described_class).not_to be_blocked_url('http://169.254.168.100') + expect(described_class).not_to be_blocked_url('http://169.254.169.254', url_blocker_attributes) + expect(described_class).not_to be_blocked_url('http://169.254.168.100', url_blocker_attributes) end it 'allows IPv6 link-local endpoints' do - expect(described_class).not_to be_blocked_url('http://[0:0:0:0:0:ffff:169.254.169.254]') - expect(described_class).not_to be_blocked_url('http://[::ffff:169.254.169.254]') - expect(described_class).not_to be_blocked_url('http://[::ffff:a9fe:a9fe]') - expect(described_class).not_to be_blocked_url('http://[0:0:0:0:0:ffff:169.254.168.100]') - expect(described_class).not_to be_blocked_url('http://[::ffff:169.254.168.100]') - expect(described_class).not_to be_blocked_url('http://[::ffff:a9fe:a864]') - expect(described_class).not_to be_blocked_url('http://[fe80::c800:eff:fe74:8]') + expect(described_class).not_to be_blocked_url('http://[0:0:0:0:0:ffff:169.254.169.254]', url_blocker_attributes) + expect(described_class).not_to be_blocked_url('http://[::ffff:169.254.169.254]', url_blocker_attributes) + expect(described_class).not_to be_blocked_url('http://[::ffff:a9fe:a9fe]', url_blocker_attributes) + expect(described_class).not_to be_blocked_url('http://[0:0:0:0:0:ffff:169.254.168.100]', url_blocker_attributes) + expect(described_class).not_to be_blocked_url('http://[::ffff:169.254.168.100]', url_blocker_attributes) + expect(described_class).not_to be_blocked_url('http://[::ffff:a9fe:a864]', url_blocker_attributes) + expect(described_class).not_to be_blocked_url('http://[fe80::c800:eff:fe74:8]', url_blocker_attributes) end end + context 'true (default)' do + it_behaves_like 'allows local requests', { allow_localhost: true, allow_local_network: true } + end + context 'false' do it 'blocks urls from private networks' do local_ips.each do |ip| - stub_domain_resolv(fake_domain, ip) - - expect(described_class).to be_blocked_url("http://#{fake_domain}", allow_local_network: false) - - unstub_domain_resolv + stub_domain_resolv(fake_domain, ip) do + expect(described_class).to be_blocked_url("http://#{fake_domain}", allow_local_network: false) + end expect(described_class).to be_blocked_url("http://#{ip}", allow_local_network: false) end @@ -286,24 +304,174 @@ describe Gitlab::UrlBlocker do expect(described_class).to be_blocked_url('http://[::ffff:a9fe:a864]', allow_local_network: false) expect(described_class).to be_blocked_url('http://[fe80::c800:eff:fe74:8]', allow_local_network: false) end + + context 'when local domain/IP is whitelisted' do + let(:url_blocker_attributes) do + { + allow_localhost: false, + allow_local_network: false + } + end + + before do + stub_application_setting(outbound_local_requests_whitelist: whitelist) + end + + context 'with IPs in whitelist' do + let(:whitelist) do + [ + '0.0.0.0', + '127.0.0.1', + '127.0.0.2', + '192.168.1.1', + '192.168.1.2', + '0:0:0:0:0:ffff:192.168.1.2', + '::ffff:c0a8:102', + '10.0.0.2', + '0:0:0:0:0:ffff:10.0.0.2', + '::ffff:a00:2', + '172.16.0.2', + '0:0:0:0:0:ffff:172.16.0.2', + '::ffff:ac10:20', + 'feef::1', + 'fee2::', + 'fc00:bf8b:e62c:abcd:abcd:aaaa:aaaa:aaaa', + '0:0:0:0:0:ffff:169.254.169.254', + '::ffff:a9fe:a9fe', + '::ffff:169.254.168.100', + '::ffff:a9fe:a864', + 'fe80::c800:eff:fe74:8', + + # garbage IPs + '45645632345', + 'garbage456:more345gar:bage' + ] + end + + it_behaves_like 'allows local requests', { allow_localhost: false, allow_local_network: false } + + it 'whitelists IP when dns_rebind_protection is disabled' do + stub_domain_resolv('example.com', '192.168.1.1') do + expect(described_class).not_to be_blocked_url("http://example.com", + url_blocker_attributes.merge(dns_rebind_protection: false)) + end + end + end + + context 'with domains in whitelist' do + let(:whitelist) do + [ + 'www.example.com', + 'example.com', + 'xn--itlab-j1a.com', + 'garbage$^$%#$^&$' + ] + end + + it 'allows domains present in whitelist' do + domain = 'example.com' + subdomain1 = 'www.example.com' + subdomain2 = 'subdomain.example.com' + + stub_domain_resolv(domain, '192.168.1.1') do + expect(described_class).not_to be_blocked_url("http://#{domain}", + url_blocker_attributes) + end + + stub_domain_resolv(subdomain1, '192.168.1.1') do + expect(described_class).not_to be_blocked_url("http://#{subdomain1}", + url_blocker_attributes) + end + + # subdomain2 is not part of the whitelist so it should be blocked + stub_domain_resolv(subdomain2, '192.168.1.1') do + expect(described_class).to be_blocked_url("http://#{subdomain2}", + url_blocker_attributes) + end + end + + it 'works with unicode and idna encoded domains' do + unicode_domain = 'ğitlab.com' + idna_encoded_domain = 'xn--itlab-j1a.com' + + stub_domain_resolv(unicode_domain, '192.168.1.1') do + expect(described_class).not_to be_blocked_url("http://#{unicode_domain}", + url_blocker_attributes) + end + + stub_domain_resolv(idna_encoded_domain, '192.168.1.1') do + expect(described_class).not_to be_blocked_url("http://#{idna_encoded_domain}", + url_blocker_attributes) + end + end + end + + context 'with ip ranges in whitelist' do + let(:ipv4_range) { '127.0.0.0/28' } + let(:ipv6_range) { 'fd84:6d02:f6d8:c89e::/124' } + + let(:whitelist) do + [ + ipv4_range, + ipv6_range + ] + end + + it 'blocks ipv4 range when not in whitelist' do + stub_application_setting(outbound_local_requests_whitelist: []) + + IPAddr.new(ipv4_range).to_range.to_a.each do |ip| + expect(described_class).to be_blocked_url("http://#{ip}", + url_blocker_attributes) + end + end + + it 'allows all ipv4s in the range when in whitelist' do + IPAddr.new(ipv4_range).to_range.to_a.each do |ip| + expect(described_class).not_to be_blocked_url("http://#{ip}", + url_blocker_attributes) + end + end + + it 'blocks ipv6 range when not in whitelist' do + stub_application_setting(outbound_local_requests_whitelist: []) + + IPAddr.new(ipv6_range).to_range.to_a.each do |ip| + expect(described_class).to be_blocked_url("http://[#{ip}]", + url_blocker_attributes) + end + end + + it 'allows all ipv6s in the range when in whitelist' do + IPAddr.new(ipv6_range).to_range.to_a.each do |ip| + expect(described_class).not_to be_blocked_url("http://[#{ip}]", + url_blocker_attributes) + end + end + + it 'blocks IPs outside the range' do + expect(described_class).to be_blocked_url("http://[fd84:6d02:f6d8:c89e:0:0:1:f]", + url_blocker_attributes) + + expect(described_class).to be_blocked_url("http://127.0.1.15", + url_blocker_attributes) + end + end + end end - def stub_domain_resolv(domain, ip) + def stub_domain_resolv(domain, ip, &block) address = double(ip_address: ip, ipv4_private?: true, ipv6_link_local?: false, ipv4_loopback?: false, ipv6_loopback?: false, ipv4?: false) allow(Addrinfo).to receive(:getaddrinfo).with(domain, any_args).and_return([address]) allow(address).to receive(:ipv6_v4mapped?).and_return(false) - end - def unstub_domain_resolv + yield + allow(Addrinfo).to receive(:getaddrinfo).and_call_original end end context 'when enforce_user is' do - before do - stub_resolv - end - context 'false (default)' do it 'does not block urls with a non-alphanumeric username' do expect(described_class).not_to be_blocked_url('ssh://-oProxyCommand=whoami@example.com/a') @@ -351,6 +519,18 @@ describe Gitlab::UrlBlocker do expect(described_class.blocked_url?('https://gitlab.com/foo/foo.bar', ascii_only: true)).to be true end end + + it 'blocks urls with invalid ip address' do + stub_env('RSPEC_ALLOW_INVALID_URLS', 'false') + + expect(described_class).to be_blocked_url('http://8.8.8.8.8') + end + + it 'blocks urls whose hostname cannot be resolved' do + stub_env('RSPEC_ALLOW_INVALID_URLS', 'false') + + expect(described_class).to be_blocked_url('http://foobar.x') + end end describe '#validate_hostname' do @@ -382,10 +562,4 @@ describe Gitlab::UrlBlocker do end end end - - # Resolv does not support resolving UTF-8 domain names - # See https://bugs.ruby-lang.org/issues/4270 - def stub_resolv - allow(Resolv).to receive(:getaddresses).and_return([]) - end end diff --git a/spec/lib/gitlab/usage_data_counters/search_counter_spec.rb b/spec/lib/gitlab/usage_data_counters/search_counter_spec.rb new file mode 100644 index 00000000000..50a9f980dc7 --- /dev/null +++ b/spec/lib/gitlab/usage_data_counters/search_counter_spec.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::UsageDataCounters::SearchCounter, :clean_gitlab_redis_shared_state do + it 'increments counter and return the total count' do + expect(described_class.total_navbar_searches_count).to eq(0) + + 2.times { described_class.increment_navbar_searches_count } + + expect(described_class.total_navbar_searches_count).to eq(2) + end +end diff --git a/spec/lib/gitlab/usage_data_counters/wiki_page_counter_spec.rb b/spec/lib/gitlab/usage_data_counters/wiki_page_counter_spec.rb index 41afbbb191c..4e8ae35187e 100644 --- a/spec/lib/gitlab/usage_data_counters/wiki_page_counter_spec.rb +++ b/spec/lib/gitlab/usage_data_counters/wiki_page_counter_spec.rb @@ -2,68 +2,13 @@ require 'spec_helper' -describe Gitlab::UsageDataCounters::WikiPageCounter, :clean_gitlab_redis_shared_state do - shared_examples :wiki_page_event do |event| - describe ".count(#{event})" do - it "increments the wiki page #{event} counter by 1" do - expect do - described_class.count(event) - end.to change { described_class.read(event) }.by 1 - end - end - - describe ".read(#{event})" do - event_count = 5 - - it "returns the total number of #{event} events" do - event_count.times do - described_class.count(event) - end - - expect(described_class.read(event)).to eq(event_count) - end - end - end - - include_examples :wiki_page_event, :create - include_examples :wiki_page_event, :update - include_examples :wiki_page_event, :delete - - describe 'totals' do - creations = 5 - edits = 3 - deletions = 2 - - before do - creations.times do - described_class.count(:create) - end - edits.times do - described_class.count(:update) - end - deletions.times do - described_class.count(:delete) - end - end - - it 'can report all totals' do - expect(described_class.totals).to include( - wiki_pages_update: edits, - wiki_pages_create: creations, - wiki_pages_delete: deletions - ) - end - end - - describe 'unknown events' do - error = described_class::UnknownEvent - - it 'cannot increment' do - expect { described_class.count(:wibble) }.to raise_error error - end - - it 'cannot read' do - expect { described_class.read(:wibble) }.to raise_error error - end - end +describe Gitlab::UsageDataCounters::WikiPageCounter do + it_behaves_like 'a redis usage counter', 'Wiki Page', :create + it_behaves_like 'a redis usage counter', 'Wiki Page', :update + it_behaves_like 'a redis usage counter', 'Wiki Page', :delete + + it_behaves_like 'a redis usage counter with totals', :wiki_pages, + create: 5, + update: 3, + delete: 2 end diff --git a/spec/lib/gitlab/usage_data_spec.rb b/spec/lib/gitlab/usage_data_spec.rb index 2289d906944..6d0a2098b2e 100644 --- a/spec/lib/gitlab/usage_data_spec.rb +++ b/spec/lib/gitlab/usage_data_spec.rb @@ -67,7 +67,8 @@ describe Gitlab::UsageData do wiki_pages_delete: a_kind_of(Integer), web_ide_views: a_kind_of(Integer), web_ide_commits: a_kind_of(Integer), - web_ide_merge_requests: a_kind_of(Integer) + web_ide_merge_requests: a_kind_of(Integer), + navbar_searches: a_kind_of(Integer) ) end diff --git a/spec/lib/gitlab/utils/sanitize_node_link_spec.rb b/spec/lib/gitlab/utils/sanitize_node_link_spec.rb new file mode 100644 index 00000000000..064c2707d06 --- /dev/null +++ b/spec/lib/gitlab/utils/sanitize_node_link_spec.rb @@ -0,0 +1,72 @@ +require 'spec_helper' + +describe Gitlab::Utils::SanitizeNodeLink do + let(:klass) do + struct = Struct.new(:value) + struct.include(described_class) + + struct + end + + subject(:object) { klass.new(:value) } + + invalid_schemes = [ + "javascript:", + "JaVaScRiPt:", + "\u0001java\u0003script:", + "javascript :", + "javascript: ", + "javascript : ", + ":javascript:", + "javascript:", + "javascript:", + "  javascript:" + ] + + invalid_schemes.each do |scheme| + context "with the scheme: #{scheme}" do + describe "#remove_unsafe_links" do + tags = { + a: { + doc: HTML::Pipeline.parse("<a href='#{scheme}alert(1);'>foo</a>"), + attr: "href", + node_to_check: -> (doc) { doc.children.first } + }, + img: { + doc: HTML::Pipeline.parse("<img src='#{scheme}alert(1);'>"), + attr: "src", + node_to_check: -> (doc) { doc.children.first } + }, + video: { + doc: HTML::Pipeline.parse("<video><source src='#{scheme}alert(1);'></video>"), + attr: "src", + node_to_check: -> (doc) { doc.children.first.children.filter("source").first } + } + } + + tags.each do |tag, opts| + context "<#{tag}> tags" do + it "removes the unsafe link" do + node = opts[:node_to_check].call(opts[:doc]) + + expect { object.remove_unsafe_links({ node: node }, remove_invalid_links: true) } + .to change { node[opts[:attr]] } + + expect(node[opts[:attr]]).to be_blank + end + end + end + end + + describe "#safe_protocol?" do + let(:doc) { HTML::Pipeline.parse("<a href='#{scheme}alert(1);'>foo</a>") } + let(:node) { doc.children.first } + let(:uri) { Addressable::URI.parse(node['href'])} + + it "returns false" do + expect(object.safe_protocol?(scheme)).to be_falsy + end + end + end + end +end diff --git a/spec/lib/gitlab/utils_spec.rb b/spec/lib/gitlab/utils_spec.rb index 4645339f439..0c20b3aa4c8 100644 --- a/spec/lib/gitlab/utils_spec.rb +++ b/spec/lib/gitlab/utils_spec.rb @@ -231,4 +231,23 @@ describe Gitlab::Utils do end end end + + describe '.string_to_ip_object' do + it 'returns nil when string is nil' do + expect(described_class.string_to_ip_object(nil)).to eq(nil) + end + + it 'returns nil when string is invalid IP' do + expect(described_class.string_to_ip_object('invalid ip')).to eq(nil) + expect(described_class.string_to_ip_object('')).to eq(nil) + end + + it 'returns IP object when string is valid IP' do + expect(described_class.string_to_ip_object('192.168.1.1')).to eq(IPAddr.new('192.168.1.1')) + expect(described_class.string_to_ip_object('::ffff:a9fe:a864')).to eq(IPAddr.new('::ffff:a9fe:a864')) + expect(described_class.string_to_ip_object('[::ffff:a9fe:a864]')).to eq(IPAddr.new('::ffff:a9fe:a864')) + expect(described_class.string_to_ip_object('127.0.0.0/28')).to eq(IPAddr.new('127.0.0.0/28')) + expect(described_class.string_to_ip_object('1:0:0:0:0:0:0:0/124')).to eq(IPAddr.new('1:0:0:0:0:0:0:0/124')) + end + end end diff --git a/spec/lib/gitlab/zoom_link_extractor_spec.rb b/spec/lib/gitlab/zoom_link_extractor_spec.rb index 52387fc3688..c3d1679d031 100644 --- a/spec/lib/gitlab/zoom_link_extractor_spec.rb +++ b/spec/lib/gitlab/zoom_link_extractor_spec.rb @@ -20,5 +20,15 @@ describe Gitlab::ZoomLinkExtractor do it { is_expected.to eq(links) } end + + describe '#match?' do + it 'is true when a zoom link found' do + expect(described_class.new('issue text https://zoom.us/j/123')).to be_match + end + + it 'is false when no zoom link found' do + expect(described_class.new('issue text')).not_to be_match + end + end end end diff --git a/spec/lib/gitlab_spec.rb b/spec/lib/gitlab_spec.rb index 82b0e819063..c293f58c9cb 100644 --- a/spec/lib/gitlab_spec.rb +++ b/spec/lib/gitlab_spec.rb @@ -136,6 +136,12 @@ describe Gitlab do expect(described_class.ee?).to eq(false) end + + it 'returns true when the IS_GITLAB_EE variable is not empty' do + stub_env('IS_GITLAB_EE', '1') + + expect(described_class.ee?).to eq(true) + end end describe '.http_proxy_env?' do diff --git a/spec/lib/peek/views/rugged_spec.rb b/spec/lib/peek/views/rugged_spec.rb new file mode 100644 index 00000000000..8bf996fc6bc --- /dev/null +++ b/spec/lib/peek/views/rugged_spec.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Peek::Views::Rugged, :request_store do + subject { described_class.new } + + let(:project) { create(:project) } + + before do + allow(Gitlab::RuggedInstrumentation).to receive(:peek_enabled?).and_return(true) + end + + it 'returns no results' do + expect(subject.results).to eq({}) + end + + it 'returns aggregated results' do + ::Gitlab::RuggedInstrumentation.query_time += 1.234 + ::Gitlab::RuggedInstrumentation.increment_query_count + ::Gitlab::RuggedInstrumentation.increment_query_count + + ::Gitlab::RuggedInstrumentation.add_call_details(feature: :rugged_test, + args: [project.repository.raw, 'HEAD'], + duration: 0.123) + ::Gitlab::RuggedInstrumentation.add_call_details(feature: :rugged_test2, + args: [project.repository.raw, 'refs/heads/master'], + duration: 0.456) + + results = subject.results + expect(results[:calls]).to eq(2) + expect(results[:duration]).to eq('1234.00ms') + expect(results[:details].count).to eq(2) + + expect(results[:details][0][:args]).to eq([project.repository.raw.to_s, "refs/heads/master"]) + expect(results[:details][1][:args]).to eq([project.repository.raw.to_s, "HEAD"]) + end +end diff --git a/spec/lib/prometheus/pid_provider_spec.rb b/spec/lib/prometheus/pid_provider_spec.rb index e7d500612b1..ba843b27254 100644 --- a/spec/lib/prometheus/pid_provider_spec.rb +++ b/spec/lib/prometheus/pid_provider_spec.rb @@ -25,22 +25,60 @@ describe Prometheus::PidProvider do before do stub_const('Unicorn::Worker', Class.new) hide_const('Puma') + + expect(described_class).to receive(:process_name) + .at_least(:once) + .and_return(process_name) end - context 'when `Prometheus::Client::Support::Unicorn` provides worker_id' do - before do - expect(::Prometheus::Client::Support::Unicorn).to receive(:worker_id).and_return(1) + context 'when unicorn master is specified in process name' do + context 'when running in Omnibus' do + context 'before the process was renamed' do + let(:process_name) { "/opt/gitlab/embedded/bin/unicorn"} + + it { is_expected.to eq 'unicorn_master' } + end + + context 'after the process was renamed' do + let(:process_name) { "unicorn master -D -E production -c /var/opt/gitlab/gitlab-rails/etc/unicorn.rb /opt/gitlab/embedded/service/gitlab-rails/config.ru" } + + it { is_expected.to eq 'unicorn_master' } + end end - it { is_expected.to eq 'unicorn_1' } + context 'when in development env' do + context 'before the process was renamed' do + let(:process_name) { "path_to_bindir/bin/unicorn_rails"} + + it { is_expected.to eq 'unicorn_master' } + end + + context 'after the process was renamed' do + let(:process_name) { "unicorn_rails master -c /gitlab_dir/config/unicorn.rb -E development" } + + it { is_expected.to eq 'unicorn_master' } + end + end end - context 'when no worker_id is provided from `Prometheus::Client::Support::Unicorn`' do - before do - expect(::Prometheus::Client::Support::Unicorn).to receive(:worker_id).and_return(nil) + context 'when unicorn worker id is specified in process name' do + context 'when running in Omnibus' do + let(:process_name) { "unicorn worker[1] -D -E production -c /var/opt/gitlab/gitlab-rails/etc/unicorn.rb /opt/gitlab/embedded/service/gitlab-rails/config.ru" } + + it { is_expected.to eq 'unicorn_1' } end - it { is_expected.to eq 'unicorn_master' } + context 'when in development env' do + let(:process_name) { "unicorn_rails worker[1] -c gitlab_dir/config/unicorn.rb -E development" } + + it { is_expected.to eq 'unicorn_1' } + end + end + + context 'when no specified unicorn master or worker id in process name' do + let(:process_name) { "bin/unknown_process"} + + it { is_expected.to eq "process_#{Process.pid}" } end end @@ -48,20 +86,20 @@ describe Prometheus::PidProvider do before do stub_const('Puma', Module.new) hide_const('Unicorn::Worker') + + expect(described_class).to receive(:process_name) + .at_least(:once) + .and_return(process_name) end context 'when cluster worker id is specified in process name' do - before do - expect(described_class).to receive(:process_name).and_return('puma: cluster worker 1: 17483 [gitlab-puma-worker]') - end + let(:process_name) { 'puma: cluster worker 1: 17483 [gitlab-puma-worker]' } it { is_expected.to eq 'puma_1' } end context 'when no worker id is specified in process name' do - before do - expect(described_class).to receive(:process_name).and_return('bin/puma') - end + let(:process_name) { 'bin/puma' } it { is_expected.to eq 'puma_master' } end diff --git a/spec/lib/quality/test_level_spec.rb b/spec/lib/quality/test_level_spec.rb index 3465c3a050b..59870ce44a7 100644 --- a/spec/lib/quality/test_level_spec.rb +++ b/spec/lib/quality/test_level_spec.rb @@ -7,7 +7,7 @@ RSpec.describe Quality::TestLevel do context 'when level is unit' do it 'returns a pattern' do expect(subject.pattern(:unit)) - .to eq("spec/{bin,config,db,dependencies,factories,finders,frontend,graphql,helpers,initializers,javascripts,lib,migrations,models,policies,presenters,rack_servers,routing,rubocop,serializers,services,sidekiq,tasks,uploaders,validators,views,workers,elastic_integration}{,/**/}*_spec.rb") + .to eq("spec/{bin,config,db,dependencies,factories,finders,frontend,graphql,haml_lint,helpers,initializers,javascripts,lib,migrations,models,policies,presenters,rack_servers,routing,rubocop,serializers,services,sidekiq,tasks,uploaders,validators,views,workers,elastic_integration}{,/**/}*_spec.rb") end end @@ -47,7 +47,7 @@ RSpec.describe Quality::TestLevel do context 'when level is unit' do it 'returns a regexp' do expect(subject.regexp(:unit)) - .to eq(%r{spec/(bin|config|db|dependencies|factories|finders|frontend|graphql|helpers|initializers|javascripts|lib|migrations|models|policies|presenters|rack_servers|routing|rubocop|serializers|services|sidekiq|tasks|uploaders|validators|views|workers|elastic_integration)}) + .to eq(%r{spec/(bin|config|db|dependencies|factories|finders|frontend|graphql|haml_lint|helpers|initializers|javascripts|lib|migrations|models|policies|presenters|rack_servers|routing|rubocop|serializers|services|sidekiq|tasks|uploaders|validators|views|workers|elastic_integration)}) end end diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb index 56bbcc4c306..dcc4b70a382 100644 --- a/spec/mailers/notify_spec.rb +++ b/spec/mailers/notify_spec.rb @@ -640,7 +640,7 @@ describe Notify do project.request_access(user) project.requesters.find_by(user_id: user.id) end - subject { described_class.member_access_requested_email('project', project_member.id, recipient.notification_email) } + subject { described_class.member_access_requested_email('project', project_member.id, recipient.id) } it_behaves_like 'an email sent from GitLab' it_behaves_like 'it should not have Gmail Actions links' @@ -737,9 +737,9 @@ describe Notify do describe 'project invitation accepted' do let(:invited_user) { create(:user, name: 'invited user') } - let(:maintainer) { create(:user).tap { |u| project.add_maintainer(u) } } + let(:recipient) { create(:user).tap { |u| project.add_maintainer(u) } } let(:project_member) do - invitee = invite_to_project(project, inviter: maintainer) + invitee = invite_to_project(project, inviter: recipient) invitee.accept_invite!(invited_user) invitee end @@ -747,6 +747,7 @@ describe Notify do subject { described_class.member_invite_accepted_email('project', project_member.id) } it_behaves_like 'an email sent from GitLab' + it_behaves_like 'an email sent to a user' it_behaves_like 'it should not have Gmail Actions links' it_behaves_like "a user cannot unsubscribe through footer link" it_behaves_like 'appearance header and footer enabled' @@ -762,16 +763,17 @@ describe Notify do end describe 'project invitation declined' do - let(:maintainer) { create(:user).tap { |u| project.add_maintainer(u) } } + let(:recipient) { create(:user).tap { |u| project.add_maintainer(u) } } let(:project_member) do - invitee = invite_to_project(project, inviter: maintainer) + invitee = invite_to_project(project, inviter: recipient) invitee.decline_invite! invitee end - subject { described_class.member_invite_declined_email('Project', project.id, project_member.invite_email, maintainer.id) } + subject { described_class.member_invite_declined_email('Project', project.id, project_member.invite_email, recipient.id) } it_behaves_like 'an email sent from GitLab' + it_behaves_like 'an email sent to a user' it_behaves_like 'it should not have Gmail Actions links' it_behaves_like "a user cannot unsubscribe through footer link" it_behaves_like 'appearance header and footer enabled' @@ -1087,9 +1089,10 @@ describe Notify do group.request_access(user) group.requesters.find_by(user_id: user.id) end - subject { described_class.member_access_requested_email('group', group_member.id, recipient.notification_email) } + subject { described_class.member_access_requested_email('group', group_member.id, recipient.id) } it_behaves_like 'an email sent from GitLab' + it_behaves_like 'an email sent to a user' it_behaves_like 'it should not have Gmail Actions links' it_behaves_like "a user cannot unsubscribe through footer link" it_behaves_like 'appearance header and footer enabled' @@ -1111,9 +1114,11 @@ describe Notify do group.request_access(user) group.requesters.find_by(user_id: user.id) end + let(:recipient) { user } subject { described_class.member_access_denied_email('group', group.id, user.id) } it_behaves_like 'an email sent from GitLab' + it_behaves_like 'an email sent to a user' it_behaves_like 'it should not have Gmail Actions links' it_behaves_like "a user cannot unsubscribe through footer link" it_behaves_like 'appearance header and footer enabled' @@ -1128,10 +1133,12 @@ describe Notify do describe 'group access changed' do let(:group_member) { create(:group_member, group: group, user: user) } + let(:recipient) { user } subject { described_class.member_access_granted_email('group', group_member.id) } it_behaves_like 'an email sent from GitLab' + it_behaves_like 'an email sent to a user' it_behaves_like 'it should not have Gmail Actions links' it_behaves_like "a user cannot unsubscribe through footer link" it_behaves_like 'appearance header and footer enabled' diff --git a/spec/migrations/change_outbound_local_requests_whitelist_default_spec.rb b/spec/migrations/change_outbound_local_requests_whitelist_default_spec.rb new file mode 100644 index 00000000000..232f6f090c3 --- /dev/null +++ b/spec/migrations/change_outbound_local_requests_whitelist_default_spec.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +require 'spec_helper' +require Rails.root.join('db', 'migrate', '20190725012225_change_outbound_local_requests_whitelist_default.rb') + +describe ChangeOutboundLocalRequestsWhitelistDefault, :migration do + let(:application_settings) { table(:application_settings) } + + it 'defaults to empty array' do + setting = application_settings.create! + setting_with_value = application_settings.create!(outbound_local_requests_whitelist: '{a,b}') + + expect(application_settings.where(outbound_local_requests_whitelist: nil).count).to eq(1) + + migrate! + + expect(application_settings.where(outbound_local_requests_whitelist: nil).count).to eq(0) + expect(setting.reload.outbound_local_requests_whitelist).to eq([]) + expect(setting_with_value.reload.outbound_local_requests_whitelist).to eq(%w[a b]) + end +end diff --git a/spec/migrations/set_issue_id_for_all_versions_spec.rb b/spec/migrations/set_issue_id_for_all_versions_spec.rb new file mode 100644 index 00000000000..bfc2731181b --- /dev/null +++ b/spec/migrations/set_issue_id_for_all_versions_spec.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +require 'spec_helper' +require Rails.root.join('db', 'migrate', '20190715043954_set_issue_id_for_all_versions.rb') + +describe SetIssueIdForAllVersions, :migration do + let(:projects) { table(:projects) } + let(:issues) { table(:issues) } + let(:designs) { table(:design_management_designs) } + let(:designs_versions) { table(:design_management_designs_versions) } + let(:versions) { table(:design_management_versions) } + + before do + @project = projects.create!(name: 'gitlab', path: 'gitlab-org/gitlab-ce', namespace_id: 1) + + @issue_1 = issues.create!(description: 'first', project_id: @project.id) + @issue_2 = issues.create!(description: 'second', project_id: @project.id) + + @design_1 = designs.create!(issue_id: @issue_1.id, filename: 'homepage-1.jpg', project_id: @project.id) + @design_2 = designs.create!(issue_id: @issue_2.id, filename: 'homepage-2.jpg', project_id: @project.id) + + @version_1 = versions.create!(sha: 'foo') + @version_2 = versions.create!(sha: 'bar') + + designs_versions.create!(version_id: @version_1.id, design_id: @design_1.id) + designs_versions.create!(version_id: @version_2.id, design_id: @design_2.id) + end + + it 'correctly sets issue_id' do + expect(versions.where(issue_id: nil).count).to eq(2) + + migrate! + + expect(versions.where(issue_id: nil).count).to eq(0) + expect(versions.find(@version_1.id).issue_id).to eq(@issue_1.id) + expect(versions.find(@version_2.id).issue_id).to eq(@issue_2.id) + end +end diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb index ab6f6dfe720..bd87bbd8d68 100644 --- a/spec/models/application_setting_spec.rb +++ b/spec/models/application_setting_spec.rb @@ -37,6 +37,17 @@ describe ApplicationSetting do it { is_expected.not_to allow_value("myemail@example.com").for(:lets_encrypt_notification_email) } it { is_expected.to allow_value("myemail@test.example.com").for(:lets_encrypt_notification_email) } + it { is_expected.to allow_value(['192.168.1.1'] * 1_000).for(:outbound_local_requests_whitelist) } + it { is_expected.not_to allow_value(['192.168.1.1'] * 1_001).for(:outbound_local_requests_whitelist) } + it { is_expected.to allow_value(['1' * 255]).for(:outbound_local_requests_whitelist) } + it { is_expected.not_to allow_value(['1' * 256]).for(:outbound_local_requests_whitelist) } + it { is_expected.not_to allow_value(['ğitlab.com']).for(:outbound_local_requests_whitelist) } + it { is_expected.to allow_value(['xn--itlab-j1a.com']).for(:outbound_local_requests_whitelist) } + it { is_expected.not_to allow_value(['<h1></h1>']).for(:outbound_local_requests_whitelist) } + it { is_expected.to allow_value(['gitlab.com']).for(:outbound_local_requests_whitelist) } + it { is_expected.to allow_value(nil).for(:outbound_local_requests_whitelist) } + it { is_expected.to allow_value([]).for(:outbound_local_requests_whitelist) } + context "when user accepted let's encrypt terms of service" do before do setting.update(lets_encrypt_terms_of_service_accepted: true) diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index c30cb70e1c1..17c7c05324a 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -21,7 +21,8 @@ describe Ci::Build do it { is_expected.to belong_to(:erased_by) } it { is_expected.to have_many(:trace_sections)} it { is_expected.to have_one(:deployment) } - it { is_expected.to have_one(:runner_session)} + it { is_expected.to have_one(:runner_session) } + it { is_expected.to have_many(:job_variables) } it { is_expected.to validate_presence_of(:ref) } it { is_expected.to respond_to(:has_trace?) } it { is_expected.to respond_to(:trace) } @@ -2258,6 +2259,16 @@ describe Ci::Build do it { is_expected.to include(manual_variable) } end + context 'when job variable is defined' do + let(:job_variable) { { key: 'first', value: 'first', public: false, masked: false } } + + before do + create(:ci_job_variable, job_variable.slice(:key, :value).merge(job: build)) + end + + it { is_expected.to include(job_variable) } + end + context 'when build is for tag' do let(:tag_variable) do { key: 'CI_COMMIT_TAG', value: 'master', public: true, masked: false } diff --git a/spec/models/ci/job_variable_spec.rb b/spec/models/ci/job_variable_spec.rb new file mode 100644 index 00000000000..b94a914c784 --- /dev/null +++ b/spec/models/ci/job_variable_spec.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Ci::JobVariable do + subject { build(:ci_job_variable) } + + it_behaves_like "CI variable" + + it { is_expected.to belong_to(:job) } + it { is_expected.to validate_uniqueness_of(:key).scoped_to(:job_id) } +end diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index e24bbc39761..1fb83fbb088 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -1799,7 +1799,7 @@ describe Ci::Pipeline, :mailer do end end - describe '.latest_successful_for' do + describe '.latest_successful_for_ref' do include_context 'with some outdated pipelines' let!(:latest_successful_pipeline) do @@ -1807,7 +1807,20 @@ describe Ci::Pipeline, :mailer do end it 'returns the latest successful pipeline' do - expect(described_class.latest_successful_for('ref')) + expect(described_class.latest_successful_for_ref('ref')) + .to eq(latest_successful_pipeline) + end + end + + describe '.latest_successful_for_sha' do + include_context 'with some outdated pipelines' + + let!(:latest_successful_pipeline) do + create_pipeline(:success, 'ref', 'awesomesha', project) + end + + it 'returns the latest successful pipeline' do + expect(described_class.latest_successful_for_sha('awesomesha')) .to eq(latest_successful_pipeline) end end diff --git a/spec/models/ci/runner_spec.rb b/spec/models/ci/runner_spec.rb index 24ea059e871..78b151631c1 100644 --- a/spec/models/ci/runner_spec.rb +++ b/spec/models/ci/runner_spec.rb @@ -146,7 +146,7 @@ describe Ci::Runner do expect(described_class.belonging_to_parent_group_of_project(project.id)).to contain_exactly(runner) end - context 'with a parent group with a runner', :nested_groups do + context 'with a parent group with a runner' do let(:runner) { create(:ci_runner, :group, groups: [parent_group]) } let(:project) { create(:project, group: group) } let(:group) { create(:group, parent: parent_group) } diff --git a/spec/models/clusters/cluster_spec.rb b/spec/models/clusters/cluster_spec.rb index 52661178d76..8f2f1b200e4 100644 --- a/spec/models/clusters/cluster_spec.rb +++ b/spec/models/clusters/cluster_spec.rb @@ -342,7 +342,7 @@ describe Clusters::Cluster, :use_clean_rails_memory_store_caching do end end - context 'when sub-group has configured kubernetes cluster', :nested_groups do + context 'when sub-group has configured kubernetes cluster' do let(:sub_group_cluster) { create(:cluster, :provided_by_gcp, :group) } let(:sub_group) { sub_group_cluster.group } let(:project) { create(:project, group: sub_group) } diff --git a/spec/models/concerns/deployment_platform_spec.rb b/spec/models/concerns/deployment_platform_spec.rb index c4f9f62ece5..27f535487c8 100644 --- a/spec/models/concerns/deployment_platform_spec.rb +++ b/spec/models/concerns/deployment_platform_spec.rb @@ -45,7 +45,7 @@ describe DeploymentPlatform do is_expected.to eq(group_cluster.platform_kubernetes) end - context 'when child group has configured kubernetes cluster', :nested_groups do + context 'when child group has configured kubernetes cluster' do let(:child_group1) { create(:group, parent: group) } let!(:child_group1_cluster) { create(:cluster_for_group, groups: [child_group1]) } diff --git a/spec/models/concerns/group_descendant_spec.rb b/spec/models/concerns/group_descendant_spec.rb index 194caac3fce..192e884f3e8 100644 --- a/spec/models/concerns/group_descendant_spec.rb +++ b/spec/models/concerns/group_descendant_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe GroupDescendant, :nested_groups do +describe GroupDescendant do let(:parent) { create(:group) } let(:subgroup) { create(:group, parent: parent) } let(:subsub_group) { create(:group, parent: subgroup) } @@ -84,7 +84,7 @@ describe GroupDescendant, :nested_groups do it 'tracks the exception when a parent was not preloaded' do expect(Gitlab::Sentry).to receive(:track_exception).and_call_original - expect { GroupDescendant.build_hierarchy([subsub_group]) }.to raise_error(ArgumentError) + expect { described_class.build_hierarchy([subsub_group]) }.to raise_error(ArgumentError) end it 'recovers if a parent was not reloaded by querying for the parent' do @@ -93,7 +93,7 @@ describe GroupDescendant, :nested_groups do # this does not raise in production, so stubbing it here. allow(Gitlab::Sentry).to receive(:track_exception) - expect(GroupDescendant.build_hierarchy([subsub_group])).to eq(expected_hierarchy) + expect(described_class.build_hierarchy([subsub_group])).to eq(expected_hierarchy) end it 'raises an error if not all elements were preloaded' do diff --git a/spec/models/concerns/issuable_spec.rb b/spec/models/concerns/issuable_spec.rb index e19da41c3fe..39680c0e51a 100644 --- a/spec/models/concerns/issuable_spec.rb +++ b/spec/models/concerns/issuable_spec.rb @@ -128,7 +128,7 @@ describe Issuable do expect(build_issuable(milestone.id).milestone_available?).to be_truthy end - it 'returns true with a milestone from the the parent of the issue project group', :nested_groups do + it 'returns true with a milestone from the the parent of the issue project group' do parent = create(:group) group.update(parent: parent) milestone = create(:milestone, group: parent) diff --git a/spec/models/concerns/relative_positioning_spec.rb b/spec/models/concerns/relative_positioning_spec.rb deleted file mode 100644 index d0ae45f7871..00000000000 --- a/spec/models/concerns/relative_positioning_spec.rb +++ /dev/null @@ -1,242 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -describe RelativePositioning do - let(:project) { create(:project) } - let(:issue) { create(:issue, project: project) } - let(:issue1) { create(:issue, project: project) } - let(:new_issue) { create(:issue, project: project) } - - describe '.move_to_end' do - it 'moves the object to the end' do - Issue.move_to_end([issue, issue1]) - - expect(issue1.prev_relative_position).to eq issue.relative_position - expect(issue.prev_relative_position).to eq nil - expect(issue1.next_relative_position).to eq nil - end - - it 'does not perform any moves if all issues have their relative_position set' do - issue.update!(relative_position: 1) - - expect(issue).not_to receive(:save) - - Issue.move_to_end([issue]) - end - end - - describe '#max_relative_position' do - it 'returns maximum position' do - expect(issue.max_relative_position).to eq issue1.relative_position - end - end - - describe '#prev_relative_position' do - it 'returns previous position if there is an issue above' do - expect(issue1.prev_relative_position).to eq issue.relative_position - end - - it 'returns nil if there is no issue above' do - expect(issue.prev_relative_position).to eq nil - end - end - - describe '#next_relative_position' do - it 'returns next position if there is an issue below' do - expect(issue.next_relative_position).to eq issue1.relative_position - end - - it 'returns nil if there is no issue below' do - expect(issue1.next_relative_position).to eq nil - end - end - - describe '#move_before' do - it 'moves issue before' do - [issue1, issue].each(&:move_to_end) - - issue.move_before(issue1) - - expect(issue.relative_position).to be < issue1.relative_position - end - end - - describe '#move_after' do - it 'moves issue after' do - [issue, issue1].each(&:move_to_end) - - issue.move_after(issue1) - - expect(issue.relative_position).to be > issue1.relative_position - end - end - - describe '#move_to_end' do - before do - [issue, issue1].each do |issue| - issue.move_to_end && issue.save - end - end - - it 'moves issue to the end' do - new_issue.move_to_end - - expect(new_issue.relative_position).to be > issue1.relative_position - end - end - - describe '#shift_after?' do - before do - [issue, issue1].each do |issue| - issue.move_to_end && issue.save - end - end - - it 'returns true' do - issue.update(relative_position: issue1.relative_position - 1) - - expect(issue.shift_after?).to be_truthy - end - - it 'returns false' do - issue.update(relative_position: issue1.relative_position - 2) - - expect(issue.shift_after?).to be_falsey - end - end - - describe '#shift_before?' do - before do - [issue, issue1].each do |issue| - issue.move_to_end && issue.save - end - end - - it 'returns true' do - issue.update(relative_position: issue1.relative_position + 1) - - expect(issue.shift_before?).to be_truthy - end - - it 'returns false' do - issue.update(relative_position: issue1.relative_position + 2) - - expect(issue.shift_before?).to be_falsey - end - end - - describe '#move_between' do - before do - [issue, issue1].each do |issue| - issue.move_to_end && issue.save - end - end - - it 'positions issue between two other' do - new_issue.move_between(issue, issue1) - - expect(new_issue.relative_position).to be > issue.relative_position - expect(new_issue.relative_position).to be < issue1.relative_position - end - - it 'positions issue between on top' do - new_issue.move_between(nil, issue) - - expect(new_issue.relative_position).to be < issue.relative_position - end - - it 'positions issue between to end' do - new_issue.move_between(issue1, nil) - - expect(new_issue.relative_position).to be > issue1.relative_position - end - - it 'positions issues even when after and before positions are the same' do - issue1.update relative_position: issue.relative_position - - new_issue.move_between(issue, issue1) - - expect(new_issue.relative_position).to be > issue.relative_position - expect(issue.relative_position).to be < issue1.relative_position - end - - it 'positions issues between other two if distance is 1' do - issue1.update relative_position: issue.relative_position + 1 - - new_issue.move_between(issue, issue1) - - expect(new_issue.relative_position).to be > issue.relative_position - expect(issue.relative_position).to be < issue1.relative_position - end - - it 'positions issue in the middle of other two if distance is big enough' do - issue.update relative_position: 6000 - issue1.update relative_position: 10000 - - new_issue.move_between(issue, issue1) - - expect(new_issue.relative_position).to eq(8000) - end - - it 'positions issue closer to the middle if we are at the very top' do - issue1.update relative_position: 6000 - - new_issue.move_between(nil, issue1) - - expect(new_issue.relative_position).to eq(6000 - RelativePositioning::IDEAL_DISTANCE) - end - - it 'positions issue closer to the middle if we are at the very bottom' do - issue.update relative_position: 6000 - issue1.update relative_position: nil - - new_issue.move_between(issue, nil) - - expect(new_issue.relative_position).to eq(6000 + RelativePositioning::IDEAL_DISTANCE) - end - - it 'positions issue in the middle of other two if distance is not big enough' do - issue.update relative_position: 100 - issue1.update relative_position: 400 - - new_issue.move_between(issue, issue1) - - expect(new_issue.relative_position).to eq(250) - end - - it 'positions issue in the middle of other two is there is no place' do - issue.update relative_position: 100 - issue1.update relative_position: 101 - - new_issue.move_between(issue, issue1) - - expect(new_issue.relative_position).to be_between(issue.relative_position, issue1.relative_position) - end - - it 'uses rebalancing if there is no place' do - issue.update relative_position: 100 - issue1.update relative_position: 101 - issue2 = create(:issue, relative_position: 102, project: project) - new_issue.update relative_position: 103 - - new_issue.move_between(issue1, issue2) - new_issue.save! - - expect(new_issue.relative_position).to be_between(issue1.relative_position, issue2.relative_position) - expect(issue.reload.relative_position).not_to eq(100) - end - - it 'positions issue right if we pass none-sequential parameters' do - issue.update relative_position: 99 - issue1.update relative_position: 101 - issue2 = create(:issue, relative_position: 102, project: project) - new_issue.update relative_position: 103 - - new_issue.move_between(issue, issue2) - new_issue.save! - - expect(new_issue.relative_position).to be(100) - end - end -end diff --git a/spec/models/container_repository_spec.rb b/spec/models/container_repository_spec.rb index 013112d1d51..935838ce294 100644 --- a/spec/models/container_repository_spec.rb +++ b/spec/models/container_repository_spec.rb @@ -16,7 +16,7 @@ describe ContainerRepository do host_port: 'registry.gitlab') stub_request(:get, 'http://registry.gitlab/v2/group/test/my_image/tags/list') - .with(headers: { 'Accept' => 'application/vnd.docker.distribution.manifest.v2+json' }) + .with(headers: { 'Accept' => ContainerRegistry::Client::ACCEPTED_TYPES.join(', ') }) .to_return( status: 200, body: JSON.dump(tags: ['test_tag']), diff --git a/spec/models/deployment_metrics_spec.rb b/spec/models/deployment_metrics_spec.rb index 0aadb1f3a5e..7c574a8b6c8 100644 --- a/spec/models/deployment_metrics_spec.rb +++ b/spec/models/deployment_metrics_spec.rb @@ -49,18 +49,6 @@ describe DeploymentMetrics do it { is_expected.to be_truthy } end - - context 'fallback deployment platform' do - let(:cluster) { create(:cluster, :provided_by_user, environment_scope: '*', projects: [deployment.project]) } - let!(:prometheus) { create(:clusters_applications_prometheus, :installed, cluster: cluster) } - - before do - expect(deployment.project).to receive(:deployment_platform).and_return(cluster.platform) - expect(cluster.application_prometheus).to receive(:can_query?).and_return(true) - end - - it { is_expected.to be_truthy } - end end end diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb index 90e0900445e..7e9bbf5a407 100644 --- a/spec/models/group_spec.rb +++ b/spec/models/group_spec.rb @@ -71,7 +71,7 @@ describe Group do end end - describe '#notification_settings', :nested_groups do + describe '#notification_settings' do let(:user) { create(:user) } let(:group) { create(:group) } let(:sub_group) { create(:group, parent_id: group.id) } @@ -237,7 +237,7 @@ describe Group do it { is_expected.to match_array([private_group, internal_group, group]) } end - context 'when user is a member of private subgroup', :postgresql do + context 'when user is a member of private subgroup' do let!(:private_subgroup) { create(:group, :private, parent: private_group) } before do @@ -416,7 +416,7 @@ describe Group do it { expect(group.last_owner?(@members[:owner])).to be_falsy } end - context 'with owners from a parent', :postgresql do + context 'with owners from a parent' do before do parent_group = create(:group) create(:group_member, :owner, group: parent_group) @@ -524,7 +524,7 @@ describe Group do it { expect(subject.parent).to be_kind_of(described_class) } end - describe '#members_with_parents', :nested_groups do + describe '#members_with_parents' do let!(:group) { create(:group, :nested) } let!(:maintainer) { group.parent.add_user(create(:user), GroupMember::MAINTAINER) } let!(:developer) { group.add_user(create(:user), GroupMember::DEVELOPER) } @@ -535,7 +535,7 @@ describe Group do end end - describe '#direct_and_indirect_members', :nested_groups do + describe '#direct_and_indirect_members' do let!(:group) { create(:group, :nested) } let!(:sub_group) { create(:group, parent: group) } let!(:maintainer) { group.parent.add_user(create(:user), GroupMember::MAINTAINER) } @@ -552,7 +552,7 @@ describe Group do end end - describe '#users_with_descendants', :nested_groups do + describe '#users_with_descendants' do let(:user_a) { create(:user) } let(:user_b) { create(:user) } @@ -571,7 +571,7 @@ describe Group do end end - describe '#direct_and_indirect_users', :nested_groups do + describe '#direct_and_indirect_users' do let(:user_a) { create(:user) } let(:user_b) { create(:user) } let(:user_c) { create(:user) } @@ -601,7 +601,7 @@ describe Group do end end - describe '#project_users_with_descendants', :nested_groups do + describe '#project_users_with_descendants' do let(:user_a) { create(:user) } let(:user_b) { create(:user) } let(:user_c) { create(:user) } @@ -678,7 +678,7 @@ describe Group do end end - context 'sub groups and projects', :nested_groups do + context 'sub groups and projects' do it 'enables two_factor_requirement for group member' do group.add_user(user, GroupMember::OWNER) @@ -687,7 +687,7 @@ describe Group do expect(user.reload.require_two_factor_authentication_from_group).to be_truthy end - context 'expanded group members', :nested_groups do + context 'expanded group members' do let(:indirect_user) { create(:user) } it 'enables two_factor_requirement for subgroup member' do @@ -720,7 +720,7 @@ describe Group do expect(user.reload.require_two_factor_authentication_from_group).to be_falsey end - it 'does not enable two_factor_requirement for subgroup child project member', :nested_groups do + it 'does not enable two_factor_requirement for subgroup child project member' do subgroup = create(:group, :nested, parent: group) project = create(:project, group: subgroup) project.add_maintainer(user) @@ -820,7 +820,7 @@ describe Group do it_behaves_like 'ref is protected' end - context 'when group has children', :postgresql do + context 'when group has children' do let(:group_child) { create(:group, parent: group) } let(:group_child_2) { create(:group, parent: group_child) } let(:group_child_3) { create(:group, parent: group_child_2) } @@ -843,7 +843,7 @@ describe Group do end end - describe '#highest_group_member', :nested_groups do + describe '#highest_group_member' do let(:nested_group) { create(:group, parent: group) } let(:nested_group_2) { create(:group, parent: nested_group) } let(:user) { create(:user) } @@ -932,7 +932,7 @@ describe Group do it { is_expected.to eq(config) } end - context 'with parent groups', :nested_groups do + context 'with parent groups' do where(:instance_value, :parent_value, :group_value, :config) do # Instance level enabled true | nil | nil | { status: true, scope: :instance } diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb index d5b016dc8f6..2e7d78d77a8 100644 --- a/spec/models/issue_spec.rb +++ b/spec/models/issue_spec.rb @@ -871,4 +871,12 @@ describe Issue do expect(issue.labels_hook_attrs).to eq([label.hook_attrs]) end end + + context "relative positioning" do + it_behaves_like "a class that supports relative positioning" do + let(:project) { create(:project) } + let(:factory) { :issue } + let(:default_params) { { project: project } } + end + end end diff --git a/spec/models/label_spec.rb b/spec/models/label_spec.rb index 5174c590a10..c2e2298823e 100644 --- a/spec/models/label_spec.rb +++ b/spec/models/label_spec.rb @@ -193,4 +193,17 @@ describe Label do expect(described_class.optionally_subscribed_by(nil)).to match_array([label, label2]) end end + + describe '#templates' do + context 'with invalid template labels' do + it 'returns only valid template labels' do + create(:label) + # Project labels should not have template set to true + create(:label, template: true) + valid_template_label = described_class.create!(title: 'test', template: true, type: nil) + + expect(described_class.templates).to eq([valid_template_label]) + end + end + end end diff --git a/spec/models/members/group_member_spec.rb b/spec/models/members/group_member_spec.rb index f227abd3dae..ebb0bfca369 100644 --- a/spec/models/members/group_member_spec.rb +++ b/spec/models/members/group_member_spec.rb @@ -69,7 +69,7 @@ describe GroupMember do end end - context 'access levels', :nested_groups do + context 'access levels' do context 'with parent group' do it_behaves_like 'inherited access level as a member of entity' do let(:entity) { create(:group, parent: parent_entity) } diff --git a/spec/models/members/project_member_spec.rb b/spec/models/members/project_member_spec.rb index 497764b6825..79c39b81196 100644 --- a/spec/models/members/project_member_spec.rb +++ b/spec/models/members/project_member_spec.rb @@ -130,7 +130,7 @@ describe ProjectMember do end end - context 'with parent group and a subgroup', :nested_groups do + context 'with parent group and a subgroup' do it_behaves_like 'inherited access level as a member of entity' do let(:subgroup) { create(:group, parent: parent_entity) } let(:entity) { create(:project, group: subgroup) } diff --git a/spec/models/namespace/root_storage_statistics_spec.rb b/spec/models/namespace/root_storage_statistics_spec.rb index 3229a32234e..5341278db7c 100644 --- a/spec/models/namespace/root_storage_statistics_spec.rb +++ b/spec/models/namespace/root_storage_statistics_spec.rb @@ -56,7 +56,7 @@ RSpec.describe Namespace::RootStorageStatistics, type: :model do it_behaves_like 'data refresh' - context 'with subgroups', :nested_groups do + context 'with subgroups' do let(:subgroup1) { create(:group, parent: namespace)} let(:subgroup2) { create(:group, parent: subgroup1)} diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb index f908f3504e0..2b9c3c43af9 100644 --- a/spec/models/namespace_spec.rb +++ b/spec/models/namespace_spec.rb @@ -191,7 +191,7 @@ describe Namespace do end end - describe '#ancestors_upto', :nested_groups do + describe '#ancestors_upto' do let(:parent) { create(:group) } let(:child) { create(:group, parent: parent) } let(:child2) { create(:group, parent: child) } @@ -271,7 +271,7 @@ describe Namespace do end end - context 'with subgroups', :nested_groups do + context 'with subgroups' do let(:parent) { create(:group, name: 'parent', path: 'parent') } let(:new_parent) { create(:group, name: 'new_parent', path: 'new_parent') } let(:child) { create(:group, name: 'child', path: 'child', parent: parent) } @@ -475,7 +475,7 @@ describe Namespace do end end - describe '#self_and_hierarchy', :nested_groups do + describe '#self_and_hierarchy' do let!(:group) { create(:group, path: 'git_lab') } let!(:nested_group) { create(:group, parent: group) } let!(:deep_nested_group) { create(:group, parent: nested_group) } @@ -490,7 +490,7 @@ describe Namespace do end end - describe '#ancestors', :nested_groups do + describe '#ancestors' do let(:group) { create(:group) } let(:nested_group) { create(:group, parent: group) } let(:deep_nested_group) { create(:group, parent: nested_group) } @@ -504,7 +504,7 @@ describe Namespace do end end - describe '#self_and_ancestors', :nested_groups do + describe '#self_and_ancestors' do let(:group) { create(:group) } let(:nested_group) { create(:group, parent: group) } let(:deep_nested_group) { create(:group, parent: nested_group) } @@ -518,7 +518,7 @@ describe Namespace do end end - describe '#descendants', :nested_groups do + describe '#descendants' do let!(:group) { create(:group, path: 'git_lab') } let!(:nested_group) { create(:group, parent: group) } let!(:deep_nested_group) { create(:group, parent: nested_group) } @@ -534,7 +534,7 @@ describe Namespace do end end - describe '#self_and_descendants', :nested_groups do + describe '#self_and_descendants' do let!(:group) { create(:group, path: 'git_lab') } let!(:nested_group) { create(:group, parent: group) } let!(:deep_nested_group) { create(:group, parent: nested_group) } @@ -550,7 +550,7 @@ describe Namespace do end end - describe '#users_with_descendants', :nested_groups do + describe '#users_with_descendants' do let(:user_a) { create(:user) } let(:user_b) { create(:user) } @@ -597,7 +597,7 @@ describe Namespace do it { expect(group.all_pipelines.to_a).to match_array([pipeline1, pipeline2]) } end - describe '#share_with_group_lock with subgroups', :nested_groups do + describe '#share_with_group_lock with subgroups' do context 'when creating a subgroup' do let(:subgroup) { create(:group, parent: root_group )} @@ -738,7 +738,7 @@ describe Namespace do end describe '#root_ancestor' do - it 'returns the top most ancestor', :nested_groups do + it 'returns the top most ancestor' do root_group = create(:group) nested_group = create(:group, parent: root_group) deep_nested_group = create(:group, parent: nested_group) diff --git a/spec/models/notification_recipient_spec.rb b/spec/models/notification_recipient_spec.rb index 20278d81f6d..4122736c148 100644 --- a/spec/models/notification_recipient_spec.rb +++ b/spec/models/notification_recipient_spec.rb @@ -49,7 +49,7 @@ describe NotificationRecipient do end context '#notification_setting' do - context 'for child groups', :nested_groups do + context 'for child groups' do let!(:moved_group) { create(:group) } let(:group) { create(:group) } let(:sub_group_1) { create(:group, parent: group) } diff --git a/spec/models/postgresql/replication_slot_spec.rb b/spec/models/postgresql/replication_slot_spec.rb index 95ae204a8a8..d435fccc09a 100644 --- a/spec/models/postgresql/replication_slot_spec.rb +++ b/spec/models/postgresql/replication_slot_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Postgresql::ReplicationSlot, :postgresql do +describe Postgresql::ReplicationSlot do describe '.in_use?' do it 'returns true when replication slots are present' do expect(described_class).to receive(:exists?).and_return(true) diff --git a/spec/models/project_auto_devops_spec.rb b/spec/models/project_auto_devops_spec.rb index 7bdd2367a68..da9e56ef897 100644 --- a/spec/models/project_auto_devops_spec.rb +++ b/spec/models/project_auto_devops_spec.rb @@ -15,7 +15,7 @@ describe ProjectAutoDevops do it { is_expected.to respond_to(:updated_at) } describe '#predefined_variables' do - let(:auto_devops) { build_stubbed(:project_auto_devops, project: project, domain: domain) } + let(:auto_devops) { build_stubbed(:project_auto_devops, project: project) } context 'when deploy_strategy is manual' do let(:auto_devops) { build_stubbed(:project_auto_devops, :manual_deployment, project: project) } diff --git a/spec/models/project_feature_spec.rb b/spec/models/project_feature_spec.rb index 31e55bf6be6..dc7a8433064 100644 --- a/spec/models/project_feature_spec.rb +++ b/spec/models/project_feature_spec.rb @@ -8,11 +8,7 @@ describe ProjectFeature do describe '.quoted_access_level_column' do it 'returns the table name and quoted column name for a feature' do - expected = if Gitlab::Database.postgresql? - '"project_features"."issues_access_level"' - else - '`project_features`.`issues_access_level`' - end + expected = '"project_features"."issues_access_level"' expect(described_class.quoted_access_level_column(:issues)).to eq(expected) end diff --git a/spec/models/project_group_link_spec.rb b/spec/models/project_group_link_spec.rb index dad5506900b..cd997224122 100644 --- a/spec/models/project_group_link_spec.rb +++ b/spec/models/project_group_link_spec.rb @@ -25,7 +25,7 @@ describe ProjectGroupLink do expect(project_group_link).not_to be_valid end - it "doesn't allow a project to be shared with an ancestor of the group it is in", :nested_groups do + it "doesn't allow a project to be shared with an ancestor of the group it is in" do project_group_link.group = parent_group expect(project_group_link).not_to be_valid diff --git a/spec/models/project_services/chat_message/pipeline_message_spec.rb b/spec/models/project_services/chat_message/pipeline_message_spec.rb index 8f9fa310ad4..619ab96af94 100644 --- a/spec/models/project_services/chat_message/pipeline_message_spec.rb +++ b/spec/models/project_services/chat_message/pipeline_message_spec.rb @@ -1,12 +1,9 @@ # frozen_string_literal: true - require 'spec_helper' describe ChatMessage::PipelineMessage do subject { described_class.new(args) } - let(:user) { { name: "The Hacker", username: 'hacker' } } - let(:duration) { 7210 } let(:args) do { object_attributes: { @@ -14,122 +11,437 @@ describe ChatMessage::PipelineMessage do sha: '97de212e80737a608d939f648d959671fb0a0142', tag: false, ref: 'develop', - status: status, - duration: duration + status: 'success', + detailed_status: nil, + duration: 7210, + finished_at: "2019-05-27 11:56:36 -0300" }, project: { - path_with_namespace: 'project_name', - web_url: 'http://example.gitlab.com' + id: 234, + name: "project_name", + path_with_namespace: 'group/project_name', + web_url: 'http://example.gitlab.com', + avatar_url: 'http://example.com/project_avatar' + }, + user: { + id: 345, + name: "The Hacker", + username: "hacker", + email: "hacker@example.gitlab.com", + avatar_url: "http://example.com/avatar" + }, + commit: { + id: "abcdef" }, - user: user + builds: nil, + markdown: false } end - let(:combined_name) { "The Hacker (hacker)" } - context 'without markdown' do - context 'pipeline succeeded' do - let(:status) { 'success' } - let(:color) { 'good' } - let(:message) { build_message('passed', combined_name) } + let(:has_yaml_errors) { false } + + before do + test_commit = double("A test commit", committer: args[:user], title: "A test commit message") + test_project = double("A test project", + commit_by: test_commit, name: args[:project][:name], + web_url: args[:project][:web_url], avatar_url: args[:project][:avatar_url]) + allow(Project).to receive(:find) { test_project } + + test_pipeline = double("A test pipeline", has_yaml_errors?: has_yaml_errors, + yaml_errors: "yaml error description here") + allow(Ci::Pipeline).to receive(:find) { test_pipeline } + + allow(Gitlab::UrlBuilder).to receive(:build).with(test_commit).and_return("http://example.com/commit") + allow(Gitlab::UrlBuilder).to receive(:build).with(args[:user]).and_return("http://example.gitlab.com/hacker") + end + + context 'when the fancy_pipeline_slack_notifications feature flag is disabled' do + before do + stub_feature_flags(fancy_pipeline_slack_notifications: false) + end + + it 'returns an empty pretext' do + expect(subject.pretext).to be_empty + end + + it "returns the pipeline summary in the activity's title" do + expect(subject.activity[:title]).to eq( + "Pipeline [#123](http://example.gitlab.com/pipelines/123)" \ + " of branch [develop](http://example.gitlab.com/commits/develop)" \ + " by The Hacker (hacker) passed" + ) + end - it 'returns a message with information about succeeded build' do - expect(subject.pretext).to be_empty - expect(subject.fallback).to eq(message) - expect(subject.attachments).to eq([text: message, color: color]) + context "when the pipeline failed" do + before do + args[:object_attributes][:status] = 'failed' + end + + it "returns the summary with a 'failed' status" do + expect(subject.activity[:title]).to eq( + "Pipeline [#123](http://example.gitlab.com/pipelines/123)" \ + " of branch [develop](http://example.gitlab.com/commits/develop)" \ + " by The Hacker (hacker) failed" + ) end end - context 'pipeline failed' do - let(:status) { 'failed' } - let(:color) { 'danger' } - let(:message) { build_message(status, combined_name) } + context 'when no user is provided because the pipeline was triggered by the API' do + before do + args[:user] = nil + end - it 'returns a message with information about failed build' do - expect(subject.pretext).to be_empty - expect(subject.fallback).to eq(message) - expect(subject.attachments).to eq([text: message, color: color]) + it "returns the summary with 'API' as the username" do + expect(subject.activity[:title]).to eq( + "Pipeline [#123](http://example.gitlab.com/pipelines/123)" \ + " of branch [develop](http://example.gitlab.com/commits/develop)" \ + " by API passed" + ) end + end - context 'when triggered by API therefore lacking user' do - let(:user) { nil } - let(:message) { build_message(status, 'API') } + it "returns a link to the project in the activity's subtitle" do + expect(subject.activity[:subtitle]).to eq("in [project_name](http://example.gitlab.com)") + end - it 'returns a message stating it is by API' do - expect(subject.pretext).to be_empty - expect(subject.fallback).to eq(message) - expect(subject.attachments).to eq([text: message, color: color]) - end + it "returns the build duration in the activity's text property" do + expect(subject.activity[:text]).to eq("in 02:00:10") + end + + it "returns the user's avatar image URL in the activity's image property" do + expect(subject.activity[:image]).to eq("http://example.com/avatar") + end + + context 'when the user does not have an avatar' do + before do + args[:user][:avatar_url] = nil + end + + it "returns an empty string in the activity's image property" do + expect(subject.activity[:image]).to be_empty + end + end + + it "returns the pipeline summary as the attachment's text property" do + expect(subject.attachments.first[:text]).to eq( + "<http://example.gitlab.com|project_name>:" \ + " Pipeline <http://example.gitlab.com/pipelines/123|#123>" \ + " of branch <http://example.gitlab.com/commits/develop|develop>" \ + " by The Hacker (hacker) passed in 02:00:10" + ) + end + + it "returns 'good' as the attachment's color property" do + expect(subject.attachments.first[:color]).to eq('good') + end + + context "when the pipeline failed" do + before do + args[:object_attributes][:status] = 'failed' + end + + it "returns 'danger' as the attachment's color property" do + expect(subject.attachments.first[:color]).to eq('danger') end end - def build_message(status_text = status, name = user[:name]) - "<http://example.gitlab.com|project_name>:" \ - " Pipeline <http://example.gitlab.com/pipelines/123|#123>" \ - " of branch <http://example.gitlab.com/commits/develop|develop>" \ - " by #{name} #{status_text} in 02:00:10" + context 'when rendering markdown' do + before do + args[:markdown] = true + end + + it 'returns the pipeline summary as the attachments in markdown format' do + expect(subject.attachments).to eq( + "[project_name](http://example.gitlab.com):" \ + " Pipeline [#123](http://example.gitlab.com/pipelines/123)" \ + " of branch [develop](http://example.gitlab.com/commits/develop)" \ + " by The Hacker (hacker) passed in 02:00:10" + ) + end end end - context 'with markdown' do + context 'when the fancy_pipeline_slack_notifications feature flag is enabled' do before do - args[:markdown] = true - end - - context 'pipeline succeeded' do - let(:status) { 'success' } - let(:color) { 'good' } - let(:message) { build_markdown_message('passed', combined_name) } - - it 'returns a message with information about succeeded build' do - expect(subject.pretext).to be_empty - expect(subject.attachments).to eq(message) - expect(subject.activity).to eq({ - title: 'Pipeline [#123](http://example.gitlab.com/pipelines/123) of branch [develop](http://example.gitlab.com/commits/develop) by The Hacker (hacker) passed', - subtitle: 'in [project_name](http://example.gitlab.com)', - text: 'in 02:00:10', - image: '' - }) + stub_feature_flags(fancy_pipeline_slack_notifications: true) + end + + it 'returns an empty pretext' do + expect(subject.pretext).to be_empty + end + + it "returns the pipeline summary in the activity's title" do + expect(subject.activity[:title]).to eq( + "Pipeline [#123](http://example.gitlab.com/pipelines/123)" \ + " of branch [develop](http://example.gitlab.com/commits/develop)" \ + " by The Hacker (hacker) has passed" + ) + end + + context "when the pipeline failed" do + before do + args[:object_attributes][:status] = 'failed' + end + + it "returns the summary with a 'failed' status" do + expect(subject.activity[:title]).to eq( + "Pipeline [#123](http://example.gitlab.com/pipelines/123)" \ + " of branch [develop](http://example.gitlab.com/commits/develop)" \ + " by The Hacker (hacker) has failed" + ) + end + end + + context "when the pipeline passed with warnings" do + before do + args[:object_attributes][:detailed_status] = 'passed with warnings' + end + + it "returns the summary with a 'passed with warnings' status" do + expect(subject.activity[:title]).to eq( + "Pipeline [#123](http://example.gitlab.com/pipelines/123)" \ + " of branch [develop](http://example.gitlab.com/commits/develop)" \ + " by The Hacker (hacker) has passed with warnings" + ) + end + end + + context 'when no user is provided because the pipeline was triggered by the API' do + before do + args[:user] = nil + end + + it "returns the summary with 'API' as the username" do + expect(subject.activity[:title]).to eq( + "Pipeline [#123](http://example.gitlab.com/pipelines/123)" \ + " of branch [develop](http://example.gitlab.com/commits/develop)" \ + " by API has passed" + ) + end + end + + it "returns a link to the project in the activity's subtitle" do + expect(subject.activity[:subtitle]).to eq("in [project_name](http://example.gitlab.com)") + end + + it "returns the build duration in the activity's text property" do + expect(subject.activity[:text]).to eq("in 02:00:10") + end + + it "returns the user's avatar image URL in the activity's image property" do + expect(subject.activity[:image]).to eq("http://example.com/avatar") + end + + context 'when the user does not have an avatar' do + before do + args[:user][:avatar_url] = nil + end + + it "returns an empty string in the activity's image property" do + expect(subject.activity[:image]).to be_empty + end + end + + it "returns the pipeline summary as the attachment's fallback property" do + expect(subject.attachments.first[:fallback]).to eq( + "<http://example.gitlab.com|project_name>:" \ + " Pipeline <http://example.gitlab.com/pipelines/123|#123>" \ + " of branch <http://example.gitlab.com/commits/develop|develop>" \ + " by The Hacker (hacker) has passed in 02:00:10" + ) + end + + it "returns 'good' as the attachment's color property" do + expect(subject.attachments.first[:color]).to eq('good') + end + + context "when the pipeline failed" do + before do + args[:object_attributes][:status] = 'failed' + end + + it "returns 'danger' as the attachment's color property" do + expect(subject.attachments.first[:color]).to eq('danger') + end + end + + context "when the pipeline passed with warnings" do + before do + args[:object_attributes][:detailed_status] = 'passed with warnings' + end + + it "returns 'warning' as the attachment's color property" do + expect(subject.attachments.first[:color]).to eq('warning') end end - context 'pipeline failed' do - let(:status) { 'failed' } - let(:color) { 'danger' } - let(:message) { build_markdown_message(status, combined_name) } + it "returns the committer's name and username as the attachment's author_name property" do + expect(subject.attachments.first[:author_name]).to eq('The Hacker (hacker)') + end + + it "returns the committer's avatar URL as the attachment's author_icon property" do + expect(subject.attachments.first[:author_icon]).to eq('http://example.com/avatar') + end + + it "returns the committer's GitLab profile URL as the attachment's author_link property" do + expect(subject.attachments.first[:author_link]).to eq('http://example.gitlab.com/hacker') + end + + context 'when no user is provided because the pipeline was triggered by the API' do + before do + args[:user] = nil + end + + it "returns the committer's name and username as the attachment's author_name property" do + expect(subject.attachments.first[:author_name]).to eq('API') + end + + it "returns nil as the attachment's author_icon property" do + expect(subject.attachments.first[:author_icon]).to be_nil + end + + it "returns nil as the attachment's author_link property" do + expect(subject.attachments.first[:author_link]).to be_nil + end + end + + it "returns the pipeline ID, status, and duration as the attachment's title property" do + expect(subject.attachments.first[:title]).to eq("Pipeline #123 has passed in 02:00:10") + end + + it "returns the pipeline URL as the attachment's title_link property" do + expect(subject.attachments.first[:title_link]).to eq("http://example.gitlab.com/pipelines/123") + end + + it "returns two attachment fields" do + expect(subject.attachments.first[:fields].count).to eq(2) + end + + it "returns the commit message as the attachment's second field property" do + expect(subject.attachments.first[:fields][0]).to eq({ + title: "Branch", + value: "<http://example.gitlab.com/commits/develop|develop>", + short: true + }) + end + + it "returns the ref name and link as the attachment's second field property" do + expect(subject.attachments.first[:fields][1]).to eq({ + title: "Commit", + value: "<http://example.com/commit|A test commit message>", + short: true + }) + end + + context "when a job in the pipeline fails" do + before do + args[:builds] = [ + { id: 1, name: "rspec", status: "failed", stage: "test" }, + { id: 2, name: "karma", status: "success", stage: "test" } + ] + end + + it "returns four attachment fields" do + expect(subject.attachments.first[:fields].count).to eq(4) + end - it 'returns a message with information about failed build' do - expect(subject.pretext).to be_empty - expect(subject.attachments).to eq(message) - expect(subject.activity).to eq({ - title: 'Pipeline [#123](http://example.gitlab.com/pipelines/123) of branch [develop](http://example.gitlab.com/commits/develop) by The Hacker (hacker) failed', - subtitle: 'in [project_name](http://example.gitlab.com)', - text: 'in 02:00:10', - image: '' + it "returns the stage name and link to the 'Failed jobs' tab on the pipeline's page as the attachment's third field property" do + expect(subject.attachments.first[:fields][2]).to eq({ + title: "Failed stage", + value: "<http://example.gitlab.com/pipelines/123/failures|test>", + short: true }) end - context 'when triggered by API therefore lacking user' do - let(:user) { nil } - let(:message) { build_markdown_message(status, 'API') } + it "returns the job name and link as the attachment's fourth field property" do + expect(subject.attachments.first[:fields][3]).to eq({ + title: "Failed job", + value: "<http://example.gitlab.com/-/jobs/1|rspec>", + short: true + }) + end + end + + context "when lots of jobs across multiple stages fail" do + before do + args[:builds] = (1..25).map do |i| + { id: i, name: "job-#{i}", status: "failed", stage: "stage-" + ((i % 3) + 1).to_s } + end + end + + it "returns the stage names and links to the 'Failed jobs' tab on the pipeline's page as the attachment's third field property" do + expect(subject.attachments.first[:fields][2]).to eq({ + title: "Failed stages", + value: "<http://example.gitlab.com/pipelines/123/failures|stage-2>, <http://example.gitlab.com/pipelines/123/failures|stage-1>, <http://example.gitlab.com/pipelines/123/failures|stage-3>", + short: true + }) + end - it 'returns a message stating it is by API' do - expect(subject.pretext).to be_empty - expect(subject.attachments).to eq(message) - expect(subject.activity).to eq({ - title: 'Pipeline [#123](http://example.gitlab.com/pipelines/123) of branch [develop](http://example.gitlab.com/commits/develop) by API failed', - subtitle: 'in [project_name](http://example.gitlab.com)', - text: 'in 02:00:10', - image: '' - }) + it "returns the job names and links as the attachment's fourth field property" do + expected_jobs = 25.downto(16).map do |i| + "<http://example.gitlab.com/-/jobs/#{i}|job-#{i}>" end + + expected_jobs << "and <http://example.gitlab.com/pipelines/123/failures|15 more>" + + expect(subject.attachments.first[:fields][3]).to eq({ + title: "Failed jobs", + value: expected_jobs.join(", "), + short: true + }) end end - def build_markdown_message(status_text = status, name = user[:name]) - "[project_name](http://example.gitlab.com):" \ - " Pipeline [#123](http://example.gitlab.com/pipelines/123)" \ - " of branch [develop](http://example.gitlab.com/commits/develop)" \ - " by #{name} #{status_text} in 02:00:10" + context "when the CI config file contains a YAML error" do + let(:has_yaml_errors) { true } + + it "returns three attachment fields" do + expect(subject.attachments.first[:fields].count).to eq(3) + end + + it "returns the YAML error deatils as the attachment's third field property" do + expect(subject.attachments.first[:fields][2]).to eq({ + title: "Invalid CI config YAML file", + value: "yaml error description here", + short: false + }) + end + end + + it "returns the stage name and link as the attachment's second field property" do + expect(subject.attachments.first[:fields][1]).to eq({ + title: "Commit", + value: "<http://example.com/commit|A test commit message>", + short: true + }) + end + + it "returns the project's name as the attachment's footer property" do + expect(subject.attachments.first[:footer]).to eq("project_name") + end + + it "returns the project's avatar URL as the attachment's footer_icon property" do + expect(subject.attachments.first[:footer_icon]).to eq("http://example.com/project_avatar") + end + + it "returns the pipeline's timestamp as the attachment's ts property" do + expected_ts = Time.parse(args[:object_attributes][:finished_at]).to_i + expect(subject.attachments.first[:ts]).to eq(expected_ts) + end + + context 'when rendering markdown' do + before do + args[:markdown] = true + end + + it 'returns the pipeline summary as the attachments in markdown format' do + expect(subject.attachments).to eq( + "[project_name](http://example.gitlab.com):" \ + " Pipeline [#123](http://example.gitlab.com/pipelines/123)" \ + " of branch [develop](http://example.gitlab.com/commits/develop)" \ + " by The Hacker (hacker) has passed in 02:00:10" + ) + end end end end diff --git a/spec/models/project_services/microsoft_teams_service_spec.rb b/spec/models/project_services/microsoft_teams_service_spec.rb index 3ffe633868f..73c20359091 100644 --- a/spec/models/project_services/microsoft_teams_service_spec.rb +++ b/spec/models/project_services/microsoft_teams_service_spec.rb @@ -292,7 +292,8 @@ describe MicrosoftTeamsService do context 'when disabled' do let(:pipeline) do - create(:ci_pipeline, :failed, project: project, ref: 'not-the-default-branch') + create(:ci_pipeline, :failed, project: project, + sha: project.commit.sha, ref: 'not-the-default-branch') end before do diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 9a083eee05e..24dfd0c5605 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -2019,62 +2019,33 @@ describe Project do end end - describe '#latest_successful_build_for' do + describe '#latest_successful_build_for_ref' do let(:project) { create(:project, :repository) } let(:pipeline) { create_pipeline(project) } - context 'with many builds' do - it 'gives the latest builds from latest pipeline' do - pipeline1 = create_pipeline(project) - pipeline2 = create_pipeline(project) - create_build(pipeline1, 'test') - create_build(pipeline1, 'test2') - build1_p2 = create_build(pipeline2, 'test') - create_build(pipeline2, 'test2') + it_behaves_like 'latest successful build for sha or ref' - expect(project.latest_successful_build_for(build1_p2.name)) - .to eq(build1_p2) - end - end + subject { project.latest_successful_build_for_ref(build_name) } - context 'with succeeded pipeline' do - let!(:build) { create_build } + context 'with a specified ref' do + let(:build) { create_build } - context 'standalone pipeline' do - it 'returns builds for ref for default_branch' do - expect(project.latest_successful_build_for(build.name)) - .to eq(build) - end + subject { project.latest_successful_build_for_ref(build.name, project.default_branch) } - it 'returns empty relation if the build cannot be found' do - expect(project.latest_successful_build_for('TAIL')) - .to be_nil - end - end - - context 'with some pending pipeline' do - before do - create_build(create_pipeline(project, 'pending')) - end - - it 'gives the latest build from latest pipeline' do - expect(project.latest_successful_build_for(build.name)) - .to eq(build) - end - end + it { is_expected.to eq(build) } end + end - context 'with pending pipeline' do - it 'returns empty relation' do - pipeline.update(status: 'pending') - pending_build = create_build(pipeline) + describe '#latest_successful_build_for_sha' do + let(:project) { create(:project, :repository) } + let(:pipeline) { create_pipeline(project) } - expect(project.latest_successful_build_for(pending_build.name)).to be_nil - end - end + it_behaves_like 'latest successful build for sha or ref' + + subject { project.latest_successful_build_for_sha(build_name, project.commit.sha) } end - describe '#latest_successful_build_for!' do + describe '#latest_successful_build_for_ref!' do let(:project) { create(:project, :repository) } let(:pipeline) { create_pipeline(project) } @@ -2087,7 +2058,7 @@ describe Project do build1_p2 = create_build(pipeline2, 'test') create_build(pipeline2, 'test2') - expect(project.latest_successful_build_for(build1_p2.name)) + expect(project.latest_successful_build_for_ref!(build1_p2.name)) .to eq(build1_p2) end end @@ -2097,12 +2068,12 @@ describe Project do context 'standalone pipeline' do it 'returns builds for ref for default_branch' do - expect(project.latest_successful_build_for!(build.name)) + expect(project.latest_successful_build_for_ref!(build.name)) .to eq(build) end it 'returns exception if the build cannot be found' do - expect { project.latest_successful_build_for!(build.name, 'TAIL') } + expect { project.latest_successful_build_for_ref!(build.name, 'TAIL') } .to raise_error(ActiveRecord::RecordNotFound) end end @@ -2113,7 +2084,7 @@ describe Project do end it 'gives the latest build from latest pipeline' do - expect(project.latest_successful_build_for!(build.name)) + expect(project.latest_successful_build_for_ref!(build.name)) .to eq(build) end end @@ -2124,7 +2095,7 @@ describe Project do pipeline.update(status: 'pending') pending_build = create_build(pipeline) - expect { project.latest_successful_build_for!(pending_build.name) } + expect { project.latest_successful_build_for_ref!(pending_build.name) } .to raise_error(ActiveRecord::RecordNotFound) end end @@ -2292,7 +2263,7 @@ describe Project do end end - describe '#ancestors_upto', :nested_groups do + describe '#ancestors_upto' do let(:parent) { create(:group) } let(:child) { create(:group, parent: parent) } let(:child2) { create(:group, parent: child) } @@ -2331,7 +2302,7 @@ describe Project do it { is_expected.to eq(group) } end - context 'in a nested group', :nested_groups do + context 'in a nested group' do let(:root) { create(:group) } let(:child) { create(:group, parent: root) } let(:project) { create(:project, group: child) } @@ -2479,7 +2450,7 @@ describe Project do expect(forked_project.in_fork_network_of?(project)).to be_truthy end - it 'is true for a fork of a fork', :postgresql do + it 'is true for a fork of a fork' do other_fork = fork_project(forked_project) expect(other_fork.in_fork_network_of?(project)).to be_truthy @@ -3117,11 +3088,8 @@ describe Project do let(:project) { create(:project) } it 'shows full error updating an invalid MR' do - error_message = 'Failed to replace merge_requests because one or more of the new records could not be saved.'\ - ' Validate fork Source project is not a fork of the target project' - expect { project.append_or_update_attribute(:merge_requests, [create(:merge_request)]) } - .to raise_error(ActiveRecord::RecordNotSaved, error_message) + .to raise_error(ActiveRecord::RecordInvalid, /Failed to set merge_requests:/) end it 'updates the project successfully' do @@ -3804,7 +3772,7 @@ describe Project do end end - context 'when enabled on root parent', :nested_groups do + context 'when enabled on root parent' do let(:parent_group) { create(:group, parent: create(:group, :auto_devops_enabled)) } context 'when auto devops instance enabled' do @@ -3824,7 +3792,7 @@ describe Project do end end - context 'when disabled on root parent', :nested_groups do + context 'when disabled on root parent' do let(:parent_group) { create(:group, parent: create(:group, :auto_devops_disabled)) } context 'when auto devops instance enabled' do @@ -4036,7 +4004,7 @@ describe Project do context 'with a ref that is not the default branch' do it 'returns the latest successful pipeline for the given ref' do - expect(project.ci_pipelines).to receive(:latest_successful_for).with('foo') + expect(project.ci_pipelines).to receive(:latest_successful_for_ref).with('foo') project.latest_successful_pipeline_for('foo') end @@ -4064,7 +4032,7 @@ describe Project do it 'memoizes and returns the latest successful pipeline for the default branch' do pipeline = double(:pipeline) - expect(project.ci_pipelines).to receive(:latest_successful_for) + expect(project.ci_pipelines).to receive(:latest_successful_for_ref) .with(project.default_branch) .and_return(pipeline) .once @@ -4267,18 +4235,16 @@ describe Project do expect(project.badges.count).to eq 3 end - if Group.supports_nested_objects? - context 'with nested_groups' do - let(:parent_group) { create(:group) } + context 'with nested_groups' do + let(:parent_group) { create(:group) } - before do - create_list(:group_badge, 2, group: project_group) - project_group.update(parent: parent_group) - end + before do + create_list(:group_badge, 2, group: project_group) + project_group.update(parent: parent_group) + end - it 'returns the project and the project nested groups badges' do - expect(project.badges.count).to eq 5 - end + it 'returns the project and the project nested groups badges' do + expect(project.badges.count).to eq 5 end end end diff --git a/spec/models/todo_spec.rb b/spec/models/todo_spec.rb index b5bf294790a..9aeef7c3b4b 100644 --- a/spec/models/todo_spec.rb +++ b/spec/models/todo_spec.rb @@ -262,11 +262,7 @@ describe Todo do todo2 = create(:todo, group: child_group) todos = described_class.for_group_and_descendants(parent_group) - expect(todos).to include(todo1) - - # Nested groups only work on PostgreSQL, so on MySQL todo2 won't be - # present. - expect(todos).to include(todo2) if Gitlab::Database.postgresql? + expect(todos).to contain_exactly(todo1, todo2) end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 2d20f8c78cc..35c335c5b5c 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -985,7 +985,7 @@ describe User do it { expect(user.namespaces).to contain_exactly(user.namespace, group) } it { expect(user.manageable_namespaces).to contain_exactly(user.namespace, group) } - context 'with child groups', :nested_groups do + context 'with child groups' do let!(:subgroup) { create(:group, parent: group) } describe '#manageable_namespaces' do @@ -2082,11 +2082,7 @@ describe User do subject { user.membership_groups } - if Group.supports_nested_objects? - it { is_expected.to contain_exactly parent_group, child_group } - else - it { is_expected.to contain_exactly parent_group } - end + it { is_expected.to contain_exactly parent_group, child_group } end describe '#authorizations_for_projects' do @@ -2386,7 +2382,7 @@ describe User do it_behaves_like :member end - context 'with subgroup with different owner for project runner', :nested_groups do + context 'with subgroup with different owner for project runner' do let(:group) { create(:group) } let(:another_user) { create(:user) } let(:subgroup) { create(:group, parent: group) } @@ -2490,22 +2486,16 @@ describe User do group.add_owner(user) end - if Group.supports_nested_objects? - it 'returns all groups' do - is_expected.to match_array [ - group, - nested_group_1, nested_group_1_1, - nested_group_2, nested_group_2_1 - ] - end - else - it 'returns the top-level groups' do - is_expected.to match_array [group] - end + it 'returns all groups' do + is_expected.to match_array [ + group, + nested_group_1, nested_group_1_1, + nested_group_2, nested_group_2_1 + ] end end - context 'user is member of the first child (internal node), branch 1', :nested_groups do + context 'user is member of the first child (internal node), branch 1' do before do nested_group_1.add_owner(user) end @@ -2518,7 +2508,7 @@ describe User do end end - context 'user is member of the first child (internal node), branch 2', :nested_groups do + context 'user is member of the first child (internal node), branch 2' do before do nested_group_2.add_owner(user) end @@ -2531,7 +2521,7 @@ describe User do end end - context 'user is member of the last child (leaf node)', :nested_groups do + context 'user is member of the last child (leaf node)' do before do nested_group_1_1.add_owner(user) end @@ -2687,7 +2677,7 @@ describe User do end end - context 'with 2FA requirement from expanded groups', :nested_groups do + context 'with 2FA requirement from expanded groups' do let!(:group1) { create :group, require_two_factor_authentication: true } let!(:group1a) { create :group, parent: group1 } @@ -2702,7 +2692,7 @@ describe User do end end - context 'with 2FA requirement on nested child group', :nested_groups do + context 'with 2FA requirement on nested child group' do let!(:group1) { create :group, require_two_factor_authentication: false } let!(:group1a) { create :group, require_two_factor_authentication: true, parent: group1 } diff --git a/spec/models/wiki_page_spec.rb b/spec/models/wiki_page_spec.rb index 520a06e138e..18c62c917dc 100644 --- a/spec/models/wiki_page_spec.rb +++ b/spec/models/wiki_page_spec.rb @@ -81,10 +81,9 @@ describe WikiPage do grouped_entries = described_class.group_by_directory(wiki.list_pages) actual_order = - grouped_entries.map do |page_or_dir| + grouped_entries.flat_map do |page_or_dir| get_slugs(page_or_dir) end - .flatten expect(actual_order).to eq(expected_order) end end diff --git a/spec/policies/group_member_policy_spec.rb b/spec/policies/group_member_policy_spec.rb index 7bd7184cffe..a4f3301a064 100644 --- a/spec/policies/group_member_policy_spec.rb +++ b/spec/policies/group_member_policy_spec.rb @@ -58,7 +58,7 @@ describe GroupMemberPolicy do end end - context 'with the group parent', :postgresql do + context 'with the group parent' do let(:current_user) { create :user } let(:subgroup) { create(:group, :private, parent: group)} diff --git a/spec/policies/group_policy_spec.rb b/spec/policies/group_policy_spec.rb index dc3675a7b9e..be55d94daec 100644 --- a/spec/policies/group_policy_spec.rb +++ b/spec/policies/group_policy_spec.rb @@ -51,7 +51,7 @@ describe GroupPolicy do it { expect_allowed(:read_label, :read_list) } - context 'in subgroups', :nested_groups do + context 'in subgroups' do let(:subgroup) { create(:group, :private, parent: group) } let(:project) { create(:project, namespace: subgroup) } @@ -104,8 +104,6 @@ describe GroupPolicy do end it 'allows every maintainer permission plus creating subgroups' do - allow(Group).to receive(:supports_nested_objects?).and_return(true) - create_subgroup_permission = [:create_subgroup] updated_maintainer_permissions = maintainer_permissions + create_subgroup_permission @@ -122,8 +120,6 @@ describe GroupPolicy do context 'with subgroup_creation_level set to owner' do it 'allows every maintainer permission' do - allow(Group).to receive(:supports_nested_objects?).and_return(true) - expect_allowed(*guest_permissions) expect_allowed(*reporter_permissions) expect_allowed(*developer_permissions) @@ -137,8 +133,6 @@ describe GroupPolicy do let(:current_user) { owner } it do - allow(Group).to receive(:supports_nested_objects?).and_return(true) - expect_allowed(*guest_permissions) expect_allowed(*reporter_permissions) expect_allowed(*developer_permissions) @@ -151,8 +145,6 @@ describe GroupPolicy do let(:current_user) { admin } it do - allow(Group).to receive(:supports_nested_objects?).and_return(true) - expect_allowed(*guest_permissions) expect_allowed(*reporter_permissions) expect_allowed(*developer_permissions) @@ -161,52 +153,7 @@ describe GroupPolicy do end end - describe 'when nested group support feature is disabled' do - before do - allow(Group).to receive(:supports_nested_objects?).and_return(false) - end - - context 'admin' do - let(:current_user) { admin } - - it 'allows every owner permission except creating subgroups' do - create_subgroup_permission = [:create_subgroup] - updated_owner_permissions = - owner_permissions - create_subgroup_permission - - expect_disallowed(*create_subgroup_permission) - expect_allowed(*updated_owner_permissions) - end - end - - context 'owner' do - let(:current_user) { owner } - - it 'allows every owner permission except creating subgroups' do - create_subgroup_permission = [:create_subgroup] - updated_owner_permissions = - owner_permissions - create_subgroup_permission - - expect_disallowed(*create_subgroup_permission) - expect_allowed(*updated_owner_permissions) - end - end - - context 'maintainer' do - let(:current_user) { maintainer } - - it 'allows every maintainer permission except creating subgroups' do - create_subgroup_permission = [:create_subgroup] - updated_maintainer_permissions = - maintainer_permissions - create_subgroup_permission - - expect_disallowed(*create_subgroup_permission) - expect_allowed(*updated_maintainer_permissions) - end - end - end - - describe 'private nested group use the highest access level from the group and inherited permissions', :nested_groups do + describe 'private nested group use the highest access level from the group and inherited permissions' do let(:nested_group) do create(:group, :private, :owner_subgroup_creation_only, parent: group) end @@ -289,8 +236,6 @@ describe GroupPolicy do let(:current_user) { owner } it do - allow(Group).to receive(:supports_nested_objects?).and_return(true) - expect_allowed(*guest_permissions) expect_allowed(*reporter_permissions) expect_allowed(*developer_permissions) diff --git a/spec/presenters/clusters/cluster_presenter_spec.rb b/spec/presenters/clusters/cluster_presenter_spec.rb index 7054a70e2ed..6b988e2645b 100644 --- a/spec/presenters/clusters/cluster_presenter_spec.rb +++ b/spec/presenters/clusters/cluster_presenter_spec.rb @@ -43,7 +43,7 @@ describe Clusters::ClusterPresenter do end shared_examples 'ancestor clusters' do - context 'ancestor clusters', :nested_groups do + context 'ancestor clusters' do let(:root_group) { create(:group, name: 'Root Group') } let(:parent) { create(:group, name: 'parent', parent: root_group) } let(:child) { create(:group, name: 'child', parent: parent) } diff --git a/spec/requests/api/boards_spec.rb b/spec/requests/api/boards_spec.rb index de79e8c4c5c..0b9c0c2ebe9 100644 --- a/spec/requests/api/boards_spec.rb +++ b/spec/requests/api/boards_spec.rb @@ -63,7 +63,7 @@ describe API::Boards do end end - describe "POST /groups/:id/boards/lists", :nested_groups do + describe "POST /groups/:id/boards/lists" do set(:group) { create(:group) } set(:board_parent) { create(:group, parent: group ) } let(:url) { "/groups/#{board_parent.id}/boards/#{board.id}/lists" } diff --git a/spec/requests/api/files_spec.rb b/spec/requests/api/files_spec.rb index 1ad536258ba..21b67357543 100644 --- a/spec/requests/api/files_spec.rb +++ b/spec/requests/api/files_spec.rb @@ -186,6 +186,14 @@ describe API::Files do expect(headers[Gitlab::Workhorse::DETECT_HEADER]).to eq "true" end + it 'returns blame file info' do + url = route(file_path) + '/blame' + + get api(url, current_user), params: params + + expect(response).to have_gitlab_http_status(200) + end + it 'sets inline content disposition by default' do url = route(file_path) + "/raw" @@ -252,6 +260,160 @@ describe API::Files do end end + describe 'GET /projects/:id/repository/files/:file_path/blame' do + shared_examples_for 'repository blame files' do + let(:expected_blame_range_sizes) do + [3, 2, 1, 2, 1, 1, 1, 1, 8, 1, 3, 1, 2, 1, 4, 1, 2, 2] + end + + let(:expected_blame_range_commit_ids) do + %w[ + 913c66a37b4a45b9769037c55c2d238bd0942d2e + 874797c3a73b60d2187ed6e2fcabd289ff75171e + 913c66a37b4a45b9769037c55c2d238bd0942d2e + 874797c3a73b60d2187ed6e2fcabd289ff75171e + 570e7b2abdd848b95f2f578043fc23bd6f6fd24d + 874797c3a73b60d2187ed6e2fcabd289ff75171e + 913c66a37b4a45b9769037c55c2d238bd0942d2e + 874797c3a73b60d2187ed6e2fcabd289ff75171e + 570e7b2abdd848b95f2f578043fc23bd6f6fd24d + 913c66a37b4a45b9769037c55c2d238bd0942d2e + 874797c3a73b60d2187ed6e2fcabd289ff75171e + 913c66a37b4a45b9769037c55c2d238bd0942d2e + 874797c3a73b60d2187ed6e2fcabd289ff75171e + 570e7b2abdd848b95f2f578043fc23bd6f6fd24d + 874797c3a73b60d2187ed6e2fcabd289ff75171e + 913c66a37b4a45b9769037c55c2d238bd0942d2e + 874797c3a73b60d2187ed6e2fcabd289ff75171e + 913c66a37b4a45b9769037c55c2d238bd0942d2e + ] + end + + it 'returns file attributes in headers' do + head api(route(file_path) + '/blame', current_user), params: params + + expect(response).to have_gitlab_http_status(200) + expect(response.headers['X-Gitlab-File-Path']).to eq(CGI.unescape(file_path)) + expect(response.headers['X-Gitlab-File-Name']).to eq('popen.rb') + expect(response.headers['X-Gitlab-Last-Commit-Id']).to eq('570e7b2abdd848b95f2f578043fc23bd6f6fd24d') + expect(response.headers['X-Gitlab-Content-Sha256']) + .to eq('c440cd09bae50c4632cc58638ad33c6aa375b6109d811e76a9cc3a613c1e8887') + end + + it 'returns blame file attributes as json' do + get api(route(file_path) + '/blame', current_user), params: params + + expect(response).to have_gitlab_http_status(200) + expect(json_response.map { |x| x['lines'].size }).to eq(expected_blame_range_sizes) + expect(json_response.map { |x| x['commit']['id'] }).to eq(expected_blame_range_commit_ids) + range = json_response[0] + expect(range['lines']).to eq(["require 'fileutils'", "require 'open3'", '']) + expect(range['commit']['id']).to eq('913c66a37b4a45b9769037c55c2d238bd0942d2e') + expect(range['commit']['parent_ids']).to eq(['cfe32cf61b73a0d5e9f13e774abde7ff789b1660']) + expect(range['commit']['message']) + .to eq("Files, encoding and much more\n\nSigned-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>\n") + + expect(range['commit']['authored_date']).to eq('2014-02-27T08:14:56.000Z') + expect(range['commit']['author_name']).to eq('Dmitriy Zaporozhets') + expect(range['commit']['author_email']).to eq('dmitriy.zaporozhets@gmail.com') + + expect(range['commit']['committed_date']).to eq('2014-02-27T08:14:56.000Z') + expect(range['commit']['committer_name']).to eq('Dmitriy Zaporozhets') + expect(range['commit']['committer_email']).to eq('dmitriy.zaporozhets@gmail.com') + end + + it 'returns blame file info for files with dots' do + url = route('.gitignore') + '/blame' + + get api(url, current_user), params: params + + expect(response).to have_gitlab_http_status(200) + end + + it 'returns file by commit sha' do + # This file is deleted on HEAD + file_path = 'files%2Fjs%2Fcommit%2Ejs%2Ecoffee' + params[:ref] = '6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9' + + get api(route(file_path) + '/blame', current_user), params: params + + expect(response).to have_gitlab_http_status(200) + end + + context 'when mandatory params are not given' do + it_behaves_like '400 response' do + let(:request) { get api(route('any%2Ffile/blame'), current_user) } + end + end + + context 'when file_path does not exist' do + let(:params) { { ref: 'master' } } + + it_behaves_like '404 response' do + let(:request) { get api(route('app%2Fmodels%2Fapplication%2Erb/blame'), current_user), params: params } + let(:message) { '404 File Not Found' } + end + end + + context 'when commit does not exist' do + let(:params) { { ref: '1111111111111111111111111111111111111111' } } + + it_behaves_like '404 response' do + let(:request) { get api(route(file_path + '/blame'), current_user), params: params } + let(:message) { '404 Commit Not Found' } + end + end + + context 'when repository is disabled' do + include_context 'disabled repository' + + it_behaves_like '403 response' do + let(:request) { get api(route(file_path + '/blame'), current_user), params: params } + end + end + end + + context 'when unauthenticated', 'and project is public' do + it_behaves_like 'repository blame files' do + let(:project) { create(:project, :public, :repository) } + let(:current_user) { nil } + end + end + + context 'when unauthenticated', 'and project is private' do + it_behaves_like '404 response' do + let(:request) { get api(route(file_path)), params: params } + let(:message) { '404 Project Not Found' } + end + end + + context 'when authenticated', 'as a developer' do + it_behaves_like 'repository blame files' do + let(:current_user) { user } + end + end + + context 'when authenticated', 'as a guest' do + it_behaves_like '403 response' do + let(:request) { get api(route(file_path) + '/blame', guest), params: params } + end + end + + context 'when PATs are used' do + it 'returns blame file by commit sha' do + token = create(:personal_access_token, scopes: ['read_repository'], user: user) + + # This file is deleted on HEAD + file_path = 'files%2Fjs%2Fcommit%2Ejs%2Ecoffee' + params[:ref] = '6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9' + + get api(route(file_path) + '/blame', personal_access_token: token), params: params + + expect(response).to have_gitlab_http_status(200) + end + end + end + describe "GET /projects/:id/repository/files/:file_path/raw" do shared_examples_for 'repository raw files' do it 'returns raw file info' do diff --git a/spec/requests/api/graphql/namespace/projects_spec.rb b/spec/requests/api/graphql/namespace/projects_spec.rb index 63fa16c79ca..815e9531ecf 100644 --- a/spec/requests/api/graphql/namespace/projects_spec.rb +++ b/spec/requests/api/graphql/namespace/projects_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe 'getting projects', :nested_groups do +describe 'getting projects' do include GraphqlHelpers let(:group) { create(:group) } diff --git a/spec/requests/api/group_labels_spec.rb b/spec/requests/api/group_labels_spec.rb index 3769f8b78e4..fcea57d9df7 100644 --- a/spec/requests/api/group_labels_spec.rb +++ b/spec/requests/api/group_labels_spec.rb @@ -94,7 +94,7 @@ describe API::GroupLabels do expect(response).to have_gitlab_http_status(400) end - it "does not delete parent's group labels", :nested_groups do + it "does not delete parent's group labels" do subgroup = create(:group, parent: group) subgroup_label = create(:group_label, title: 'feature', group: subgroup) @@ -127,7 +127,7 @@ describe API::GroupLabels do expect(json_response['description']).to eq('test') end - it "does not update parent's group label", :nested_groups do + it "does not update parent's group label" do subgroup = create(:group, parent: group) subgroup_label = create(:group_label, title: 'feature', group: subgroup) diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb index 52d926d5484..50f36141aed 100644 --- a/spec/requests/api/groups_spec.rb +++ b/spec/requests/api/groups_spec.rb @@ -530,7 +530,7 @@ describe API::Groups do expect(json_response.length).to eq(2) end - it "returns projects including those in subgroups", :nested_groups do + it "returns projects including those in subgroups" do subgroup = create(:group, parent: group1) create(:project, group: subgroup) create(:project, group: subgroup) @@ -642,7 +642,7 @@ describe API::Groups do end end - describe 'GET /groups/:id/subgroups', :nested_groups do + describe 'GET /groups/:id/subgroups' do let!(:subgroup1) { create(:group, parent: group1) } let!(:subgroup2) { create(:group, :private, parent: group1) } let!(:subgroup3) { create(:group, :private, parent: group2) } @@ -786,7 +786,7 @@ describe API::Groups do expect(response).to have_gitlab_http_status(403) end - context 'as owner', :nested_groups do + context 'as owner' do before do group2.add_owner(user1) end @@ -798,7 +798,7 @@ describe API::Groups do end end - context 'as maintainer', :nested_groups do + context 'as maintainer' do before do group2.add_maintainer(user1) end @@ -825,7 +825,7 @@ describe API::Groups do expect(json_response["visibility"]).to eq(Gitlab::VisibilityLevel.string_level(Gitlab::CurrentSettings.current_application_settings.default_group_visibility)) end - it "creates a nested group", :nested_groups do + it "creates a nested group" do parent = create(:group) parent.add_owner(user3) group = attributes_for(:group, { parent_id: parent.id }) diff --git a/spec/requests/api/issues/get_group_issues_spec.rb b/spec/requests/api/issues/get_group_issues_spec.rb index 9a41d790945..5916bb11516 100644 --- a/spec/requests/api/issues/get_group_issues_spec.rb +++ b/spec/requests/api/issues/get_group_issues_spec.rb @@ -82,7 +82,7 @@ describe API::Issues do end end - context 'when group has subgroups', :nested_groups do + context 'when group has subgroups' do let(:subgroup_1) { create(:group, parent: group) } let(:subgroup_2) { create(:group, parent: subgroup_1) } diff --git a/spec/requests/api/members_spec.rb b/spec/requests/api/members_spec.rb index 55f38079b1f..26f6e705528 100644 --- a/spec/requests/api/members_spec.rb +++ b/spec/requests/api/members_spec.rb @@ -99,7 +99,7 @@ describe API::Members do end end - describe 'GET /:source_type/:id/members/all', :nested_groups do + describe 'GET /:source_type/:id/members/all' do let(:nested_user) { create(:user) } let(:project_user) { create(:user) } let(:linked_group_user) { create(:user) } @@ -238,7 +238,7 @@ describe API::Members do end context 'access levels' do - it 'does not create the member if group level is higher', :nested_groups do + it 'does not create the member if group level is higher' do parent = create(:group) group.update(parent: parent) @@ -252,7 +252,7 @@ describe API::Members do expect(json_response['message']['access_level']).to eq(["should be greater than or equal to Developer inherited membership from group #{parent.name}"]) end - it 'creates the member if group level is lower', :nested_groups do + it 'creates the member if group level is lower' do parent = create(:group) group.update(parent: parent) diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb index ced853caab4..7a6f1cd548c 100644 --- a/spec/requests/api/merge_requests_spec.rb +++ b/spec/requests/api/merge_requests_spec.rb @@ -723,7 +723,7 @@ describe API::MergeRequests do it_behaves_like 'merge requests list' - context 'when have subgroups', :nested_groups do + context 'when have subgroups' do let!(:group) { create(:group, :public) } let!(:subgroup) { create(:group, parent: group) } let!(:project) { create(:project, :public, :repository, creator: user, namespace: subgroup, only_allow_merge_if_pipeline_succeeds: false) } diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index fee300e9d7a..5b3a2412aff 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -1357,7 +1357,7 @@ describe API::Projects do end end - context 'nested group project', :nested_groups do + context 'nested group project' do let(:group) { create(:group) } let(:nested_group) { create(:group, parent: group) } let(:project2) { create(:project, group: nested_group) } diff --git a/spec/requests/api/resource_label_events_spec.rb b/spec/requests/api/resource_label_events_spec.rb index 37b46eaeb86..25bea627b0c 100644 --- a/spec/requests/api/resource_label_events_spec.rb +++ b/spec/requests/api/resource_label_events_spec.rb @@ -4,55 +4,12 @@ require 'spec_helper' describe API::ResourceLabelEvents do set(:user) { create(:user) } - set(:project) { create(:project, :public, :repository, namespace: user.namespace) } - set(:private_user) { create(:user) } + set(:project) { create(:project, :public, namespace: user.namespace) } before do project.add_developer(user) end - shared_examples 'resource_label_events API' do |parent_type, eventable_type, id_name| - describe "GET /#{parent_type}/:id/#{eventable_type}/:noteable_id/resource_label_events" do - it "returns an array of resource label events" do - get api("/#{parent_type}/#{parent.id}/#{eventable_type}/#{eventable[id_name]}/resource_label_events", user) - - expect(response).to have_gitlab_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.first['id']).to eq(event.id) - end - - it "returns a 404 error when eventable id not found" do - get api("/#{parent_type}/#{parent.id}/#{eventable_type}/12345/resource_label_events", user) - - expect(response).to have_gitlab_http_status(404) - end - - it "returns 404 when not authorized" do - parent.update!(visibility_level: Gitlab::VisibilityLevel::PRIVATE) - - get api("/#{parent_type}/#{parent.id}/#{eventable_type}/#{eventable[id_name]}/resource_label_events", private_user) - - expect(response).to have_gitlab_http_status(404) - end - end - - describe "GET /#{parent_type}/:id/#{eventable_type}/:noteable_id/resource_label_events/:event_id" do - it "returns a resource label event by id" do - get api("/#{parent_type}/#{parent.id}/#{eventable_type}/#{eventable[id_name]}/resource_label_events/#{event.id}", user) - - expect(response).to have_gitlab_http_status(200) - expect(json_response['id']).to eq(event.id) - end - - it "returns a 404 error if resource label event not found" do - get api("/#{parent_type}/#{parent.id}/#{eventable_type}/#{eventable[id_name]}/resource_label_events/12345", user) - - expect(response).to have_gitlab_http_status(404) - end - end - end - context 'when eventable is an Issue' do let(:issue) { create(:issue, project: project, author: user) } diff --git a/spec/requests/api/triggers_spec.rb b/spec/requests/api/triggers_spec.rb index f0f01e97f1d..8ea3d16a41f 100644 --- a/spec/requests/api/triggers_spec.rb +++ b/spec/requests/api/triggers_spec.rb @@ -270,34 +270,6 @@ describe API::Triggers do end end - describe 'POST /projects/:id/triggers/:trigger_id/take_ownership' do - context 'authenticated user with valid permissions' do - it 'updates owner' do - post api("/projects/#{project.id}/triggers/#{trigger.id}/take_ownership", user) - - expect(response).to have_gitlab_http_status(200) - expect(json_response).to include('owner') - expect(trigger.reload.owner).to eq(user) - end - end - - context 'authenticated user with invalid permissions' do - it 'does not update owner' do - post api("/projects/#{project.id}/triggers/#{trigger.id}/take_ownership", user2) - - expect(response).to have_gitlab_http_status(403) - end - end - - context 'unauthenticated user' do - it 'does not update owner' do - post api("/projects/#{project.id}/triggers/#{trigger.id}/take_ownership") - - expect(response).to have_gitlab_http_status(401) - end - end - end - describe 'DELETE /projects/:id/triggers/:trigger_id' do context 'authenticated user with valid permissions' do it 'deletes trigger' do diff --git a/spec/requests/openid_connect_spec.rb b/spec/requests/openid_connect_spec.rb index 86e41cbdf00..025568d8bea 100644 --- a/spec/requests/openid_connect_spec.rb +++ b/spec/requests/openid_connect_spec.rb @@ -104,7 +104,7 @@ describe 'OpenID Connect requests' do expect(json_response).to match(id_token_claims.merge(user_info_claims)) expected_groups = [group1.full_path, group3.full_path] - expected_groups << group4.full_path if Group.supports_nested_objects? + expected_groups << group4.full_path expect(json_response['groups']).to match_array(expected_groups) end diff --git a/spec/routing/git_http_routing_spec.rb b/spec/routing/git_http_routing_spec.rb new file mode 100644 index 00000000000..af14e5f81cb --- /dev/null +++ b/spec/routing/git_http_routing_spec.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'git_http routing' do + include RSpec::Rails::RequestExampleGroup + + describe 'wiki.git routing', 'routing' do + let(:wiki_path) { '/gitlab/gitlabhq/wikis' } + + it 'redirects namespace/project.wiki.git to the project wiki' do + expect(get('/gitlab/gitlabhq.wiki.git')).to redirect_to(wiki_path) + end + + it 'preserves query parameters' do + expect(get('/gitlab/gitlabhq.wiki.git?foo=bar&baz=qux')).to redirect_to("#{wiki_path}?foo=bar&baz=qux") + end + + it 'only redirects when the format is .git' do + expect(get('/gitlab/gitlabhq.wiki')).not_to redirect_to(wiki_path) + expect(get('/gitlab/gitlabhq.wiki.json')).not_to redirect_to(wiki_path) + end + end +end diff --git a/spec/serializers/group_child_entity_spec.rb b/spec/serializers/group_child_entity_spec.rb index b58d95ccb43..00e2f931549 100644 --- a/spec/serializers/group_child_entity_spec.rb +++ b/spec/serializers/group_child_entity_spec.rb @@ -62,7 +62,7 @@ describe GroupChildEntity do it_behaves_like 'group child json' end - describe 'for a group', :nested_groups do + describe 'for a group' do let(:description) { 'Awesomeness' } let(:object) do create(:group, :nested, :with_avatar, diff --git a/spec/serializers/group_child_serializer_spec.rb b/spec/serializers/group_child_serializer_spec.rb index 5541ada3750..c9e8535585b 100644 --- a/spec/serializers/group_child_serializer_spec.rb +++ b/spec/serializers/group_child_serializer_spec.rb @@ -16,7 +16,7 @@ describe GroupChildSerializer do end end - context 'with a hierarchy', :nested_groups do + context 'with a hierarchy' do let(:parent) { create(:group) } subject(:serializer) do @@ -75,7 +75,7 @@ describe GroupChildSerializer do expect(serializer.represent(build_list(:project, 2))).to be_kind_of(Array) end - context 'with a hierarchy', :nested_groups do + context 'with a hierarchy' do let(:parent) { create(:group) } subject(:serializer) do diff --git a/spec/serializers/issue_entity_spec.rb b/spec/serializers/issue_entity_spec.rb index caa3e41402b..0e05b3c84f4 100644 --- a/spec/serializers/issue_entity_spec.rb +++ b/spec/serializers/issue_entity_spec.rb @@ -17,4 +17,37 @@ describe IssueEntity do it 'has time estimation attributes' do expect(subject).to include(:time_estimate, :total_time_spent, :human_time_estimate, :human_total_time_spent) end + + context 'when issue got moved' do + let(:public_project) { create(:project, :public) } + let(:member) { create(:user) } + let(:non_member) { create(:user) } + let(:issue) { create(:issue, project: public_project) } + + before do + project.add_developer(member) + public_project.add_developer(member) + Issues::MoveService.new(public_project, member).execute(issue, project) + end + + context 'when user cannot read target project' do + it 'does not return moved_to_id' do + request = double('request', current_user: non_member) + + response = described_class.new(issue, request: request).as_json + + expect(response[:moved_to_id]).to be_nil + end + end + + context 'when user can read target project' do + it 'returns moved moved_to_id' do + request = double('request', current_user: member) + + response = described_class.new(issue, request: request).as_json + + expect(response[:moved_to_id]).to eq(issue.moved_to_id) + end + end + end end diff --git a/spec/serializers/pipeline_serializer_spec.rb b/spec/serializers/pipeline_serializer_spec.rb index 54e6abc2d3a..7f9827329b3 100644 --- a/spec/serializers/pipeline_serializer_spec.rb +++ b/spec/serializers/pipeline_serializer_spec.rb @@ -126,7 +126,7 @@ describe PipelineSerializer do expect(subject.all? { |entry| entry[:merge_request].present? }).to be_truthy end - it 'preloads related merge requests', :postgresql do + it 'preloads related merge requests' do recorded = ActiveRecord::QueryRecorder.new { subject } expect(recorded.log) diff --git a/spec/services/application_settings/update_service_spec.rb b/spec/services/application_settings/update_service_spec.rb index a641828faa5..33cd1f37ff6 100644 --- a/spec/services/application_settings/update_service_spec.rb +++ b/spec/services/application_settings/update_service_spec.rb @@ -180,4 +180,20 @@ describe ApplicationSettings::UpdateService do described_class.new(application_settings, admin, { home_page_url: 'http://foo.bar' }).execute end end + + context 'when raw_blob_request_limit is passsed' do + let(:params) do + { + raw_blob_request_limit: 600 + } + end + + it 'updates raw_blob_request_limit value' do + subject.execute + + application_settings.reload + + expect(application_settings.raw_blob_request_limit).to eq(600) + end + end end diff --git a/spec/services/boards/issues/list_service_spec.rb b/spec/services/boards/issues/list_service_spec.rb index 40878e24cb4..931b67b2950 100644 --- a/spec/services/boards/issues/list_service_spec.rb +++ b/spec/services/boards/issues/list_service_spec.rb @@ -112,7 +112,7 @@ describe Boards::Issues::ListService do it_behaves_like 'issues list service' end - context 'and group is an ancestor', :nested_groups do + context 'and group is an ancestor' do let(:parent) { create(:group) } let(:group) { create(:group, parent: parent) } let!(:backlog) { create(:backlog_list, board: board) } diff --git a/spec/services/ci/play_build_service_spec.rb b/spec/services/ci/play_build_service_spec.rb index 1e68b7956ea..cf39f3da4fe 100644 --- a/spec/services/ci/play_build_service_spec.rb +++ b/spec/services/ci/play_build_service_spec.rb @@ -60,6 +60,19 @@ describe Ci::PlayBuildService, '#execute' do expect(build.reload.user).to eq user end + + context 'when variables are supplied' do + let(:job_variables) do + [{ key: 'first', secret_value: 'first' }, + { key: 'second', secret_value: 'second' }] + end + + it 'assigns the variables to the build' do + service.execute(build, job_variables) + + expect(build.reload.job_variables.map(&:key)).to contain_exactly('first', 'second') + end + end end context 'when build is not a playable manual action' do diff --git a/spec/services/ci/retry_build_service_spec.rb b/spec/services/ci/retry_build_service_spec.rb index 11b06ef5019..915288cd916 100644 --- a/spec/services/ci/retry_build_service_spec.rb +++ b/spec/services/ci/retry_build_service_spec.rb @@ -30,7 +30,8 @@ describe Ci::RetryBuildService do job_artifacts_sast job_artifacts_dependency_scanning job_artifacts_container_scanning job_artifacts_dast job_artifacts_license_management job_artifacts_performance - job_artifacts_codequality job_artifacts_metrics scheduled_at].freeze + job_artifacts_codequality job_artifacts_metrics scheduled_at + job_variables].freeze IGNORE_ACCESSORS = %i[type lock_version target_url base_tags trace_sections @@ -65,6 +66,8 @@ describe Ci::RetryBuildService do file_type: file_type, job: build, expire_at: build.artifacts_expire_at) end + create(:ci_job_variable, job: build) + build.reload end diff --git a/spec/services/clusters/refresh_service_spec.rb b/spec/services/clusters/refresh_service_spec.rb deleted file mode 100644 index 5bc8a709941..00000000000 --- a/spec/services/clusters/refresh_service_spec.rb +++ /dev/null @@ -1,113 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -describe Clusters::RefreshService do - shared_examples 'creates a kubernetes namespace' do - let(:token) { 'aaaaaa' } - let(:service_account_creator) { double(Clusters::Gcp::Kubernetes::CreateOrUpdateServiceAccountService, execute: true) } - let(:secrets_fetcher) { double(Clusters::Gcp::Kubernetes::FetchKubernetesTokenService, execute: token) } - - it 'creates a kubernetes namespace' do - expect(Clusters::Gcp::Kubernetes::CreateOrUpdateServiceAccountService).to receive(:namespace_creator).and_return(service_account_creator) - expect(Clusters::Gcp::Kubernetes::FetchKubernetesTokenService).to receive(:new).and_return(secrets_fetcher) - - expect { subject }.to change(project.kubernetes_namespaces, :count) - - kubernetes_namespace = cluster.kubernetes_namespaces.first - expect(kubernetes_namespace).to be_present - expect(kubernetes_namespace.project).to eq(project) - end - end - - shared_examples 'does not create a kubernetes namespace' do - it 'does not create a new kubernetes namespace' do - expect(Clusters::Gcp::Kubernetes::CreateOrUpdateServiceAccountService).not_to receive(:namespace_creator) - expect(Clusters::Gcp::Kubernetes::FetchKubernetesTokenService).not_to receive(:new) - - expect { subject }.not_to change(Clusters::KubernetesNamespace, :count) - end - end - - describe '.create_or_update_namespaces_for_cluster' do - let(:cluster) { create(:cluster, :provided_by_user, :project) } - let(:project) { cluster.project } - - subject { described_class.create_or_update_namespaces_for_cluster(cluster) } - - context 'cluster is project level' do - include_examples 'creates a kubernetes namespace' - - context 'when project already has kubernetes namespace' do - before do - create(:cluster_kubernetes_namespace, project: project, cluster: cluster) - end - - include_examples 'does not create a kubernetes namespace' - end - end - - context 'cluster is group level' do - let(:cluster) { create(:cluster, :provided_by_user, :group) } - let(:group) { cluster.group } - let(:project) { create(:project, group: group) } - - include_examples 'creates a kubernetes namespace' - - context 'when project already has kubernetes namespace' do - before do - create(:cluster_kubernetes_namespace, project: project, cluster: cluster) - end - - include_examples 'does not create a kubernetes namespace' - end - end - end - - describe '.create_or_update_namespaces_for_project' do - let(:project) { create(:project) } - - subject { described_class.create_or_update_namespaces_for_project(project) } - - it 'creates no kubernetes namespaces' do - expect { subject }.not_to change(project.kubernetes_namespaces, :count) - end - - context 'project has a project cluster' do - let!(:cluster) { create(:cluster, :provided_by_gcp, cluster_type: :project_type, projects: [project]) } - - include_examples 'creates a kubernetes namespace' - - context 'when project already has kubernetes namespace' do - before do - create(:cluster_kubernetes_namespace, project: project, cluster: cluster) - end - - include_examples 'does not create a kubernetes namespace' - end - end - - context 'project belongs to a group cluster' do - let!(:cluster) { create(:cluster, :provided_by_gcp, :group) } - - let(:group) { cluster.group } - let(:project) { create(:project, group: group) } - - include_examples 'does not create a kubernetes namespace' - - context 'when project already has kubernetes namespace' do - before do - create(:cluster_kubernetes_namespace, project: project, cluster: cluster) - end - - include_examples 'does not create a kubernetes namespace' - end - end - - context 'cluster is not managed' do - let!(:cluster) { create(:cluster, :project, :not_managed, projects: [project]) } - - include_examples 'does not create a kubernetes namespace' - end - end -end diff --git a/spec/services/groups/auto_devops_service_spec.rb b/spec/services/groups/auto_devops_service_spec.rb index 7f8ab517cef..7591b2f6f12 100644 --- a/spec/services/groups/auto_devops_service_spec.rb +++ b/spec/services/groups/auto_devops_service_spec.rb @@ -47,7 +47,7 @@ describe Groups::AutoDevopsService, '#execute' do expect(subgroup_1.auto_devops_enabled?).to eq(false) end - context 'when subgroups have projects', :nested_groups do + context 'when subgroups have projects' do it 'reflects changes on projects' do subgroup_1 = create(:group, parent: group) project_1 = create(:project, namespace: subgroup_1) diff --git a/spec/services/groups/create_service_spec.rb b/spec/services/groups/create_service_spec.rb index a7c95428485..0f9f20de586 100644 --- a/spec/services/groups/create_service_spec.rb +++ b/spec/services/groups/create_service_spec.rb @@ -44,7 +44,7 @@ describe Groups::CreateService, '#execute' do end end - describe 'creating subgroup', :nested_groups do + describe 'creating subgroup' do let!(:group) { create(:group) } let!(:service) { described_class.new(user, group_params.merge(parent_id: group.id)) } @@ -54,47 +54,31 @@ describe Groups::CreateService, '#execute' do end it { is_expected.to be_persisted } + end - context 'when nested groups feature is disabled' do - it 'does not save group and returns an error' do - allow(Group).to receive(:supports_nested_objects?).and_return(false) + context 'as guest' do + it 'does not save group and returns an error' do + is_expected.not_to be_persisted - is_expected.not_to be_persisted - expect(subject.errors[:parent_id]).to include('You don’t have permission to create a subgroup in this group.') - expect(subject.parent_id).to be_nil - end + expect(subject.errors[:parent_id].first).to eq('You don’t have permission to create a subgroup in this group.') + expect(subject.parent_id).to be_nil end end - context 'when nested groups feature is enabled' do + context 'as owner' do before do - allow(Group).to receive(:supports_nested_objects?).and_return(true) - end - - context 'as guest' do - it 'does not save group and returns an error' do - is_expected.not_to be_persisted - - expect(subject.errors[:parent_id].first).to eq('You don’t have permission to create a subgroup in this group.') - expect(subject.parent_id).to be_nil - end + group.add_owner(user) end - context 'as owner' do - before do - group.add_owner(user) - end + it { is_expected.to be_persisted } + end - it { is_expected.to be_persisted } + context 'as maintainer' do + before do + group.add_maintainer(user) end - context 'as maintainer' do - before do - group.add_maintainer(user) - end - - it { is_expected.to be_persisted } - end + it { is_expected.to be_persisted } end end diff --git a/spec/services/groups/nested_create_service_spec.rb b/spec/services/groups/nested_create_service_spec.rb index 13acf9e055b..b30392c1b12 100644 --- a/spec/services/groups/nested_create_service_spec.rb +++ b/spec/services/groups/nested_create_service_spec.rb @@ -28,35 +28,7 @@ describe Groups::NestedCreateService do end end - describe 'without subgroups' do - let(:params) { { group_path: 'a-group' } } - - before do - allow(Group).to receive(:supports_nested_objects?) { false } - end - - it 'creates the group' do - group = service.execute - - expect(group).to be_persisted - end - - it 'returns the group if it already existed' do - existing_group = create(:group, path: 'a-group') - - expect(service.execute).to eq(existing_group) - end - - it 'raises an error when tring to create a subgroup' do - service = described_class.new(user, group_path: 'a-group/a-sub-group') - - expect { service.execute }.to raise_error('Nested groups are not supported on MySQL') - end - - it_behaves_like 'with a visibility level' - end - - describe 'with subgroups', :nested_groups do + describe 'with subgroups' do let(:params) { { group_path: 'a-group/a-sub-group' } } describe "#execute" do diff --git a/spec/services/groups/transfer_service_spec.rb b/spec/services/groups/transfer_service_spec.rb index b5708ebba76..f3af8cf5f3b 100644 --- a/spec/services/groups/transfer_service_spec.rb +++ b/spec/services/groups/transfer_service_spec.rb @@ -2,28 +2,13 @@ require 'rails_helper' -describe Groups::TransferService, :postgresql do +describe Groups::TransferService do let(:user) { create(:user) } let(:new_parent_group) { create(:group, :public) } let!(:group_member) { create(:group_member, :owner, group: group, user: user) } let(:transfer_service) { described_class.new(group, user) } shared_examples 'ensuring allowed transfer for a group' do - context 'with other database than PostgreSQL' do - before do - allow(Group).to receive(:supports_nested_objects?).and_return(false) - end - - it 'returns false' do - expect(transfer_service.execute(new_parent_group)).to be_falsy - end - - it 'adds an error on group' do - transfer_service.execute(new_parent_group) - expect(transfer_service.error).to eq('Transfer failed: Database is not supported.') - end - end - context "when there's an exception on GitLab shell directories" do let(:new_parent_group) { create(:group, :public) } diff --git a/spec/services/groups/update_service_spec.rb b/spec/services/groups/update_service_spec.rb index d081c20f669..5d4576139f7 100644 --- a/spec/services/groups/update_service_spec.rb +++ b/spec/services/groups/update_service_spec.rb @@ -133,7 +133,7 @@ describe Groups::UpdateService do end end - context 'for a subgroup', :nested_groups do + context 'for a subgroup' do let(:subgroup) { create(:group, :private, parent: private_group) } context 'when the parent group share_with_group_lock is enabled' do diff --git a/spec/services/issuable/bulk_update_service_spec.rb b/spec/services/issuable/bulk_update_service_spec.rb index 40da3d31408..fb12877fa05 100644 --- a/spec/services/issuable/bulk_update_service_spec.rb +++ b/spec/services/issuable/bulk_update_service_spec.rb @@ -265,7 +265,7 @@ describe Issuable::BulkUpdateService do end it 'removes the label IDs from all issues passed' do - expect(issues.map(&:reload).map(&:label_ids).flatten).not_to include(merge_requests.id) + expect(issues.map(&:reload).flat_map(&:label_ids)).not_to include(merge_requests.id) end it 'does not update issues not passed in' do @@ -297,11 +297,11 @@ describe Issuable::BulkUpdateService do let(:remove_labels) { [regression] } it 'removes the label IDs from all issues passed' do - expect(issues.map(&:reload).map(&:label_ids).flatten).not_to include(regression.id) + expect(issues.map(&:reload).flat_map(&:label_ids)).not_to include(regression.id) end it 'ignores the label IDs parameter' do - expect(issues.map(&:reload).map(&:label_ids).flatten).not_to include(merge_requests.id) + expect(issues.map(&:reload).flat_map(&:label_ids)).not_to include(merge_requests.id) end it 'does not update issues not passed in' do @@ -320,11 +320,11 @@ describe Issuable::BulkUpdateService do end it 'removes the label IDs from all issues passed' do - expect(issues.map(&:reload).map(&:label_ids).flatten).not_to include(merge_requests.id) + expect(issues.map(&:reload).flat_map(&:label_ids)).not_to include(merge_requests.id) end it 'ignores the label IDs parameter' do - expect(issues.map(&:reload).map(&:label_ids).flatten).not_to include(regression.id) + expect(issues.map(&:reload).flat_map(&:label_ids)).not_to include(regression.id) end it 'does not update issues not passed in' do diff --git a/spec/services/issues/update_service_spec.rb b/spec/services/issues/update_service_spec.rb index 468e7c286d5..d9f35afee06 100644 --- a/spec/services/issues/update_service_spec.rb +++ b/spec/services/issues/update_service_spec.rb @@ -116,7 +116,7 @@ describe Issues::UpdateService, :mailer do expect(issue.relative_position).to be_between(issue1.relative_position, issue2.relative_position) end - context 'when moving issue between issues from different projects', :nested_groups do + context 'when moving issue between issues from different projects' do let(:group) { create(:group) } let(:subgroup) { create(:group, parent: group) } @@ -179,7 +179,7 @@ describe Issues::UpdateService, :mailer do it 'sends email to user2 about assign of new issue and email to user3 about issue unassignment' do deliveries = ActionMailer::Base.deliveries email = deliveries.last - recipients = deliveries.last(2).map(&:to).flatten + recipients = deliveries.last(2).flat_map(&:to) expect(recipients).to include(user2.email, user3.email) expect(email.subject).to include(issue.title) end @@ -226,6 +226,15 @@ describe Issues::UpdateService, :mailer do end end + it 'creates zoom_link_added system note when a zoom link is added to the description' do + update_issue(description: 'Changed description https://zoom.us/j/5873603787') + + note = find_note('a Zoom call was added') + + expect(note).not_to be_nil + expect(note.note).to eq('a Zoom call was added to this issue') + end + context 'when issue turns confidential' do let(:opts) do { @@ -703,7 +712,7 @@ describe Issues::UpdateService, :mailer do end end - context 'when moving an issue ', :nested_groups do + context 'when moving an issue ' do it 'raises an error for invalid move ids within a project' do opts = { move_between_ids: [9000, 9999] } diff --git a/spec/services/members/destroy_service_spec.rb b/spec/services/members/destroy_service_spec.rb index 52f9a305d8f..7dce7f035d4 100644 --- a/spec/services/members/destroy_service_spec.rb +++ b/spec/services/members/destroy_service_spec.rb @@ -267,15 +267,15 @@ describe Members::DestroyService do expect(group.members.map(&:user)).not_to include(member_user) end - it 'removes the subgroup membership', :postgresql do + it 'removes the subgroup membership' do expect(subgroup.members.map(&:user)).not_to include(member_user) end - it 'removes the subsubgroup membership', :postgresql do + it 'removes the subsubgroup membership' do expect(subsubgroup.members.map(&:user)).not_to include(member_user) end - it 'removes the subsubproject membership', :postgresql do + it 'removes the subsubproject membership' do expect(subsubproject.members.map(&:user)).not_to include(member_user) end diff --git a/spec/services/merge_requests/build_service_spec.rb b/spec/services/merge_requests/build_service_spec.rb index 5c3b209086c..f18239f6d39 100644 --- a/spec/services/merge_requests/build_service_spec.rb +++ b/spec/services/merge_requests/build_service_spec.rb @@ -1,5 +1,4 @@ # frozen_string_literal: true - require 'spec_helper' describe MergeRequests::BuildService do @@ -225,6 +224,11 @@ describe MergeRequests::BuildService do let(:label_ids) { [label2.id] } let(:milestone_id) { milestone2.id } + before do + # Guests are not able to assign labels or milestones to an issue + project.add_developer(user) + end + it 'assigns milestone_id and label_ids instead of issue labels and milestone' do expect(merge_request.milestone).to eq(milestone2) expect(merge_request.labels).to match_array([label2]) @@ -479,4 +483,35 @@ describe MergeRequests::BuildService do end end end + + context 'when assigning labels' do + let(:label_ids) { [create(:label, project: project).id] } + + context 'for members with less than developer access' do + it 'is not allowed' do + expect(merge_request.label_ids).to be_empty + end + end + + context 'for users allowed to assign labels' do + before do + project.add_developer(user) + end + + context 'for labels in the project' do + it 'is allowed for developers' do + expect(merge_request.label_ids).to contain_exactly(*label_ids) + end + end + + context 'for unrelated labels' do + let(:project_label) { create(:label, project: project) } + let(:label_ids) { [create(:label).id, project_label.id] } + + it 'only assigns related labels' do + expect(merge_request.label_ids).to contain_exactly(project_label.id) + end + end + end + end end diff --git a/spec/services/merge_requests/push_options_handler_service_spec.rb b/spec/services/merge_requests/push_options_handler_service_spec.rb index ac40cf02c48..a27fea0c90f 100644 --- a/spec/services/merge_requests/push_options_handler_service_spec.rb +++ b/spec/services/merge_requests/push_options_handler_service_spec.rb @@ -11,6 +11,8 @@ describe MergeRequests::PushOptionsHandlerService do let(:service) { described_class.new(project, user, changes, push_options) } let(:source_branch) { 'fix' } let(:target_branch) { 'feature' } + let(:title) { 'my title' } + let(:description) { 'my description' } let(:new_branch_changes) { "#{Gitlab::Git::BLANK_SHA} 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/#{source_branch}" } let(:existing_branch_changes) { "d14d6c0abdd253381df51a723d58691b2ee1ab08 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/#{source_branch}" } let(:deleted_branch_changes) { "d14d6c0abdd253381df51a723d58691b2ee1ab08 #{Gitlab::Git::BLANK_SHA} refs/heads/#{source_branch}" } @@ -73,6 +75,26 @@ describe MergeRequests::PushOptionsHandlerService do end end + shared_examples_for 'a service that can set the title of a merge request' do + subject(:last_mr) { MergeRequest.last } + + it 'sets the title' do + service.execute + + expect(last_mr.title).to eq(title) + end + end + + shared_examples_for 'a service that can set the description of a merge request' do + subject(:last_mr) { MergeRequest.last } + + it 'sets the description' do + service.execute + + expect(last_mr.description).to eq(description) + end + end + shared_examples_for 'a service that can set the merge request to merge when pipeline succeeds' do subject(:last_mr) { MergeRequest.last } @@ -350,6 +372,138 @@ describe MergeRequests::PushOptionsHandlerService do end end + describe '`title` push option' do + let(:push_options) { { title: title } } + + context 'with a new branch' do + let(:changes) { new_branch_changes } + + it_behaves_like 'a service that does not create a merge request' + + it 'adds an error to the service' do + error = "A merge_request.create push option is required to create a merge request for branch #{source_branch}" + + service.execute + + expect(service.errors).to include(error) + end + + context 'when coupled with the `create` push option' do + let(:push_options) { { create: true, title: title } } + + it_behaves_like 'a service that can create a merge request' + it_behaves_like 'a service that can set the title of a merge request' + end + end + + context 'with an existing branch but no open MR' do + let(:changes) { existing_branch_changes } + + it_behaves_like 'a service that does not create a merge request' + + it 'adds an error to the service' do + error = "A merge_request.create push option is required to create a merge request for branch #{source_branch}" + + service.execute + + expect(service.errors).to include(error) + end + + context 'when coupled with the `create` push option' do + let(:push_options) { { create: true, title: title } } + + it_behaves_like 'a service that can create a merge request' + it_behaves_like 'a service that can set the title of a merge request' + end + end + + context 'with an existing branch that has a merge request open' do + let(:changes) { existing_branch_changes } + let!(:merge_request) { create(:merge_request, source_project: project, source_branch: source_branch)} + + it_behaves_like 'a service that does not create a merge request' + it_behaves_like 'a service that can set the title of a merge request' + end + + context 'with a deleted branch' do + let(:changes) { deleted_branch_changes } + + it_behaves_like 'a service that does nothing' + end + + context 'with the project default branch' do + let(:changes) { default_branch_changes } + + it_behaves_like 'a service that does nothing' + end + end + + describe '`description` push option' do + let(:push_options) { { description: description } } + + context 'with a new branch' do + let(:changes) { new_branch_changes } + + it_behaves_like 'a service that does not create a merge request' + + it 'adds an error to the service' do + error = "A merge_request.create push option is required to create a merge request for branch #{source_branch}" + + service.execute + + expect(service.errors).to include(error) + end + + context 'when coupled with the `create` push option' do + let(:push_options) { { create: true, description: description } } + + it_behaves_like 'a service that can create a merge request' + it_behaves_like 'a service that can set the description of a merge request' + end + end + + context 'with an existing branch but no open MR' do + let(:changes) { existing_branch_changes } + + it_behaves_like 'a service that does not create a merge request' + + it 'adds an error to the service' do + error = "A merge_request.create push option is required to create a merge request for branch #{source_branch}" + + service.execute + + expect(service.errors).to include(error) + end + + context 'when coupled with the `create` push option' do + let(:push_options) { { create: true, description: description } } + + it_behaves_like 'a service that can create a merge request' + it_behaves_like 'a service that can set the description of a merge request' + end + end + + context 'with an existing branch that has a merge request open' do + let(:changes) { existing_branch_changes } + let!(:merge_request) { create(:merge_request, source_project: project, source_branch: source_branch)} + + it_behaves_like 'a service that does not create a merge request' + it_behaves_like 'a service that can set the description of a merge request' + end + + context 'with a deleted branch' do + let(:changes) { deleted_branch_changes } + + it_behaves_like 'a service that does nothing' + end + + context 'with the project default branch' do + let(:changes) { default_branch_changes } + + it_behaves_like 'a service that does nothing' + end + end + describe 'multiple pushed branches' do let(:push_options) { { create: true } } let(:changes) do diff --git a/spec/services/merge_requests/update_service_spec.rb b/spec/services/merge_requests/update_service_spec.rb index 7e5837a4798..9688e02d6ac 100644 --- a/spec/services/merge_requests/update_service_spec.rb +++ b/spec/services/merge_requests/update_service_spec.rb @@ -91,7 +91,8 @@ describe MergeRequests::UpdateService, :mailer do labels: [], mentioned_users: [user2], assignees: [user3], - total_time_spent: 0 + total_time_spent: 0, + description: "FYI #{user2.to_reference}" } ) end @@ -99,7 +100,7 @@ describe MergeRequests::UpdateService, :mailer do it 'sends email to user2 about assign of new merge request and email to user3 about merge request unassignment' do deliveries = ActionMailer::Base.deliveries email = deliveries.last - recipients = deliveries.last(2).map(&:to).flatten + recipients = deliveries.last(2).flat_map(&:to) expect(recipients).to include(user2.email, user3.email) expect(email.subject).to include(merge_request.title) end diff --git a/spec/lib/gitlab/metrics/dashboard/dynamic_dashboard_service_spec.rb b/spec/services/metrics/dashboard/default_embed_service_spec.rb index 79a78df44ae..5b24b9b2a14 100644 --- a/spec/lib/gitlab/metrics/dashboard/dynamic_dashboard_service_spec.rb +++ b/spec/services/metrics/dashboard/default_embed_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Gitlab::Metrics::Dashboard::DynamicDashboardService, :use_clean_rails_memory_store_caching do +describe Metrics::Dashboard::DefaultEmbedService, :use_clean_rails_memory_store_caching do include MetricsDashboardHelpers set(:project) { build(:project) } diff --git a/spec/lib/gitlab/metrics/dashboard/project_dashboard_service_spec.rb b/spec/services/metrics/dashboard/project_dashboard_service_spec.rb index 468e8ec9ef2..1357914be2a 100644 --- a/spec/lib/gitlab/metrics/dashboard/project_dashboard_service_spec.rb +++ b/spec/services/metrics/dashboard/project_dashboard_service_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -describe Gitlab::Metrics::Dashboard::ProjectDashboardService, :use_clean_rails_memory_store_caching do +describe Metrics::Dashboard::ProjectDashboardService, :use_clean_rails_memory_store_caching do include MetricsDashboardHelpers set(:user) { create(:user) } diff --git a/spec/lib/gitlab/metrics/dashboard/system_dashboard_service_spec.rb b/spec/services/metrics/dashboard/system_dashboard_service_spec.rb index 13f22dd01c5..8be3e7f6064 100644 --- a/spec/lib/gitlab/metrics/dashboard/system_dashboard_service_spec.rb +++ b/spec/services/metrics/dashboard/system_dashboard_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Gitlab::Metrics::Dashboard::SystemDashboardService, :use_clean_rails_memory_store_caching do +describe Metrics::Dashboard::SystemDashboardService, :use_clean_rails_memory_store_caching do include MetricsDashboardHelpers set(:user) { create(:user) } diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb index c20de1fd079..1dcade1de0d 100644 --- a/spec/services/notification_service_spec.rb +++ b/spec/services/notification_service_spec.rb @@ -111,7 +111,7 @@ describe NotificationService, :mailer do should_email(participant) end - context 'for subgroups', :nested_groups do + context 'for subgroups' do before do build_group(project) end @@ -337,7 +337,7 @@ describe NotificationService, :mailer do it_behaves_like 'new note notifications' - context 'which is a subgroup', :nested_groups do + context 'which is a subgroup' do let!(:parent) { create(:group) } let!(:group) { create(:group, parent: parent) } @@ -388,7 +388,7 @@ describe NotificationService, :mailer do should_email(admin) end - context 'on project that belongs to subgroup', :nested_groups do + context 'on project that belongs to subgroup' do let(:group_reporter) { create(:user) } let(:group_guest) { create(:user) } let(:parent_group) { create(:group) } @@ -458,7 +458,7 @@ describe NotificationService, :mailer do should_not_email_nested_group_user(@pg_disabled) end - it 'notifies parent group members with mention level', :nested_groups do + it 'notifies parent group members with mention level' do note = create(:note_on_issue, noteable: issue, project_id: issue.project_id, note: "@#{@pg_mention.username}") notification.new_note(note) @@ -2410,52 +2410,40 @@ describe NotificationService, :mailer do group end - # Creates a nested group only if supported - # to avoid errors on MySQL def create_nested_group(visibility) - if Group.supports_nested_objects? - parent_group = create(:group, visibility) - child_group = create(:group, visibility, parent: parent_group) + parent_group = create(:group, visibility) + child_group = create(:group, visibility, parent: parent_group) - # Parent group member: global=disabled, parent_group=watch, child_group=global - @pg_watcher ||= create_user_with_notification(:watch, 'parent_group_watcher', parent_group) - @pg_watcher.notification_settings_for(nil).disabled! + # Parent group member: global=disabled, parent_group=watch, child_group=global + @pg_watcher ||= create_user_with_notification(:watch, 'parent_group_watcher', parent_group) + @pg_watcher.notification_settings_for(nil).disabled! - # Parent group member: global=global, parent_group=disabled, child_group=global - @pg_disabled ||= create_user_with_notification(:disabled, 'parent_group_disabled', parent_group) - @pg_disabled.notification_settings_for(nil).global! + # Parent group member: global=global, parent_group=disabled, child_group=global + @pg_disabled ||= create_user_with_notification(:disabled, 'parent_group_disabled', parent_group) + @pg_disabled.notification_settings_for(nil).global! - # Parent group member: global=global, parent_group=mention, child_group=global - @pg_mention ||= create_user_with_notification(:mention, 'parent_group_mention', parent_group) - @pg_mention.notification_settings_for(nil).global! + # Parent group member: global=global, parent_group=mention, child_group=global + @pg_mention ||= create_user_with_notification(:mention, 'parent_group_mention', parent_group) + @pg_mention.notification_settings_for(nil).global! - # Parent group member: global=global, parent_group=participating, child_group=global - @pg_participant ||= create_user_with_notification(:participating, 'parent_group_participant', parent_group) - @pg_mention.notification_settings_for(nil).global! + # Parent group member: global=global, parent_group=participating, child_group=global + @pg_participant ||= create_user_with_notification(:participating, 'parent_group_participant', parent_group) + @pg_mention.notification_settings_for(nil).global! - child_group - else - create(:group, visibility) - end + child_group end def add_member_for_parent_group(user, project) - return unless Group.supports_nested_objects? - project.reload project.group.parent.add_maintainer(user) end def should_email_nested_group_user(user, times: 1, recipients: email_recipients) - return unless Group.supports_nested_objects? - should_email(user, times: 1, recipients: email_recipients) end def should_not_email_nested_group_user(user, recipients: email_recipients) - return unless Group.supports_nested_objects? - should_not_email(user, recipients: email_recipients) end diff --git a/spec/services/projects/autocomplete_service_spec.rb b/spec/services/projects/autocomplete_service_spec.rb index 2f70c8ea94d..b625653bc77 100644 --- a/spec/services/projects/autocomplete_service_spec.rb +++ b/spec/services/projects/autocomplete_service_spec.rb @@ -118,7 +118,7 @@ describe Projects::AutocompleteService do expect(milestone_titles).to eq([group_milestone2.title, group_milestone1.title]) end - context 'with nested groups', :nested_groups do + context 'with nested groups' do let(:subgroup) { create(:group, :public, parent: group) } let!(:subgroup_milestone) { create(:milestone, group: subgroup) } diff --git a/spec/services/projects/destroy_service_spec.rb b/spec/services/projects/destroy_service_spec.rb index 3af7ee3ad50..e436af77ed4 100644 --- a/spec/services/projects/destroy_service_spec.rb +++ b/spec/services/projects/destroy_service_spec.rb @@ -121,7 +121,22 @@ describe Projects::DestroyService do it { expect(Dir.exist?(remove_path)).to be_truthy } end - context 'when flushing caches fail' do + context 'when flushing caches fail due to Git errors' do + before do + allow(project.repository).to receive(:before_delete).and_raise(::Gitlab::Git::CommandError) + allow(Gitlab::GitLogger).to receive(:warn).with( + class: described_class.name, + project_id: project.id, + disk_path: project.disk_path, + message: 'Gitlab::Git::CommandError').and_call_original + + perform_enqueued_jobs { destroy_project(project, user, {}) } + end + + it_behaves_like 'deleting the project' + end + + context 'when flushing caches fail due to Redis' do before do new_user = create(:user) project.team.add_user(new_user, Gitlab::Access::DEVELOPER) diff --git a/spec/services/projects/download_service_spec.rb b/spec/services/projects/download_service_spec.rb index f25233ceeb1..06efc2ff825 100644 --- a/spec/services/projects/download_service_spec.rb +++ b/spec/services/projects/download_service_spec.rb @@ -20,13 +20,8 @@ describe Projects::DownloadService do context 'for URLs that are on the whitelist' do before do - sham_rack_app = ShamRack.at('mycompany.fogbugz.com').stub - sham_rack_app.register_resource('/rails_sample.jpg', File.read(Rails.root + 'spec/fixtures/rails_sample.jpg'), 'image/jpg') - sham_rack_app.register_resource('/doc_sample.txt', File.read(Rails.root + 'spec/fixtures/doc_sample.txt'), 'text/plain') - end - - after do - ShamRack.unmount_all + stub_request(:get, 'http://mycompany.fogbugz.com/rails_sample.jpg').to_return(body: File.read(Rails.root + 'spec/fixtures/rails_sample.jpg')) + stub_request(:get, 'http://mycompany.fogbugz.com/doc_sample.txt').to_return(body: File.read(Rails.root + 'spec/fixtures/doc_sample.txt')) end context 'an image file' do diff --git a/spec/services/quick_actions/interpret_service_spec.rb b/spec/services/quick_actions/interpret_service_spec.rb index 95a131e8c86..bf5f211b11c 100644 --- a/spec/services/quick_actions/interpret_service_spec.rb +++ b/spec/services/quick_actions/interpret_service_spec.rb @@ -28,61 +28,108 @@ describe QuickActions::InterpretService do shared_examples 'reopen command' do it 'returns state_event: "reopen" if content contains /reopen' do issuable.close! - _, updates = service.execute(content, issuable) + _, updates, _ = service.execute(content, issuable) expect(updates).to eq(state_event: 'reopen') end + + it 'returns the reopen message' do + issuable.close! + _, _, message = service.execute(content, issuable) + + expect(message).to eq("Reopened this #{issuable.to_ability_name.humanize(capitalize: false)}.") + end end shared_examples 'close command' do it 'returns state_event: "close" if content contains /close' do - _, updates = service.execute(content, issuable) + _, updates, _ = service.execute(content, issuable) expect(updates).to eq(state_event: 'close') end + + it 'returns the close message' do + _, _, message = service.execute(content, issuable) + + expect(message).to eq("Closed this #{issuable.to_ability_name.humanize(capitalize: false)}.") + end end shared_examples 'title command' do it 'populates title: "A brand new title" if content contains /title A brand new title' do - _, updates = service.execute(content, issuable) + _, updates, _ = service.execute(content, issuable) expect(updates).to eq(title: 'A brand new title') end + + it 'returns the title message' do + _, _, message = service.execute(content, issuable) + + expect(message).to eq(%{Changed the title to "A brand new title".}) + end end shared_examples 'milestone command' do it 'fetches milestone and populates milestone_id if content contains /milestone' do milestone # populate the milestone - _, updates = service.execute(content, issuable) + _, updates, _ = service.execute(content, issuable) expect(updates).to eq(milestone_id: milestone.id) end + + it 'returns the milestone message' do + milestone # populate the milestone + _, _, message = service.execute(content, issuable) + + expect(message).to eq("Set the milestone to #{milestone.to_reference}.") + end + + it 'returns empty milestone message when milestone is wrong' do + _, _, message = service.execute('/milestone %wrong-milestone', issuable) + + expect(message).to be_empty + end end shared_examples 'remove_milestone command' do it 'populates milestone_id: nil if content contains /remove_milestone' do issuable.update!(milestone_id: milestone.id) - _, updates = service.execute(content, issuable) + _, updates, _ = service.execute(content, issuable) expect(updates).to eq(milestone_id: nil) end + + it 'returns removed milestone message' do + issuable.update!(milestone_id: milestone.id) + _, _, message = service.execute(content, issuable) + + expect(message).to eq("Removed #{milestone.to_reference} milestone.") + end end shared_examples 'label command' do it 'fetches label ids and populates add_label_ids if content contains /label' do bug # populate the label inprogress # populate the label - _, updates = service.execute(content, issuable) + _, updates, _ = service.execute(content, issuable) expect(updates).to eq(add_label_ids: [bug.id, inprogress.id]) end + + it 'returns the label message' do + bug # populate the label + inprogress # populate the label + _, _, message = service.execute(content, issuable) + + expect(message).to eq("Added #{bug.to_reference(format: :name)} #{inprogress.to_reference(format: :name)} labels.") + end end shared_examples 'multiple label command' do it 'fetches label ids and populates add_label_ids if content contains multiple /label' do bug # populate the label inprogress # populate the label - _, updates = service.execute(content, issuable) + _, updates, _ = service.execute(content, issuable) expect(updates).to eq(add_label_ids: [inprogress.id, bug.id]) end @@ -91,7 +138,7 @@ describe QuickActions::InterpretService do shared_examples 'multiple label with same argument' do it 'prevents duplicate label ids and populates add_label_ids if content contains multiple /label' do inprogress # populate the label - _, updates = service.execute(content, issuable) + _, updates, _ = service.execute(content, issuable) expect(updates).to eq(add_label_ids: [inprogress.id]) end @@ -120,16 +167,23 @@ describe QuickActions::InterpretService do shared_examples 'unlabel command' do it 'fetches label ids and populates remove_label_ids if content contains /unlabel' do issuable.update!(label_ids: [inprogress.id]) # populate the label - _, updates = service.execute(content, issuable) + _, updates, _ = service.execute(content, issuable) expect(updates).to eq(remove_label_ids: [inprogress.id]) end + + it 'returns the unlabel message' do + issuable.update!(label_ids: [inprogress.id]) # populate the label + _, _, message = service.execute(content, issuable) + + expect(message).to eq("Removed #{inprogress.to_reference(format: :name)} label.") + end end shared_examples 'multiple unlabel command' do it 'fetches label ids and populates remove_label_ids if content contains mutiple /unlabel' do issuable.update!(label_ids: [inprogress.id, bug.id]) # populate the label - _, updates = service.execute(content, issuable) + _, updates, _ = service.execute(content, issuable) expect(updates).to eq(remove_label_ids: [inprogress.id, bug.id]) end @@ -138,7 +192,7 @@ describe QuickActions::InterpretService do shared_examples 'unlabel command with no argument' do it 'populates label_ids: [] if content contains /unlabel with no arguments' do issuable.update!(label_ids: [inprogress.id]) # populate the label - _, updates = service.execute(content, issuable) + _, updates, _ = service.execute(content, issuable) expect(updates).to eq(label_ids: []) end @@ -148,91 +202,161 @@ describe QuickActions::InterpretService do it 'populates label_ids: [] if content contains /relabel' do issuable.update!(label_ids: [bug.id]) # populate the label inprogress # populate the label - _, updates = service.execute(content, issuable) + _, updates, _ = service.execute(content, issuable) expect(updates).to eq(label_ids: [inprogress.id]) end + + it 'returns the relabel message' do + issuable.update!(label_ids: [bug.id]) # populate the label + inprogress # populate the label + _, _, message = service.execute(content, issuable) + + expect(message).to eq("Replaced all labels with #{inprogress.to_reference(format: :name)} label.") + end end shared_examples 'todo command' do it 'populates todo_event: "add" if content contains /todo' do - _, updates = service.execute(content, issuable) + _, updates, _ = service.execute(content, issuable) expect(updates).to eq(todo_event: 'add') end + + it 'returns the todo message' do + _, _, message = service.execute(content, issuable) + + expect(message).to eq('Added a todo.') + end end shared_examples 'done command' do it 'populates todo_event: "done" if content contains /done' do TodoService.new.mark_todo(issuable, developer) - _, updates = service.execute(content, issuable) + _, updates, _ = service.execute(content, issuable) expect(updates).to eq(todo_event: 'done') end + + it 'returns the done message' do + TodoService.new.mark_todo(issuable, developer) + _, _, message = service.execute(content, issuable) + + expect(message).to eq('Marked to do as done.') + end end shared_examples 'subscribe command' do it 'populates subscription_event: "subscribe" if content contains /subscribe' do - _, updates = service.execute(content, issuable) + _, updates, _ = service.execute(content, issuable) expect(updates).to eq(subscription_event: 'subscribe') end + + it 'returns the subscribe message' do + _, _, message = service.execute(content, issuable) + + expect(message).to eq("Subscribed to this #{issuable.to_ability_name.humanize(capitalize: false)}.") + end end shared_examples 'unsubscribe command' do it 'populates subscription_event: "unsubscribe" if content contains /unsubscribe' do issuable.subscribe(developer, project) - _, updates = service.execute(content, issuable) + _, updates, _ = service.execute(content, issuable) expect(updates).to eq(subscription_event: 'unsubscribe') end + + it 'returns the unsubscribe message' do + issuable.subscribe(developer, project) + _, _, message = service.execute(content, issuable) + + expect(message).to eq("Unsubscribed from this #{issuable.to_ability_name.humanize(capitalize: false)}.") + end end shared_examples 'due command' do + let(:expected_date) { Date.new(2016, 8, 28) } + it 'populates due_date: Date.new(2016, 8, 28) if content contains /due 2016-08-28' do - _, updates = service.execute(content, issuable) + _, updates, _ = service.execute(content, issuable) + + expect(updates).to eq(due_date: expected_date) + end - expect(updates).to eq(due_date: defined?(expected_date) ? expected_date : Date.new(2016, 8, 28)) + it 'returns due_date message: Date.new(2016, 8, 28) if content contains /due 2016-08-28' do + _, _, message = service.execute(content, issuable) + + expect(message).to eq("Set the due date to #{expected_date.to_s(:medium)}.") end end shared_examples 'remove_due_date command' do - it 'populates due_date: nil if content contains /remove_due_date' do + before do issuable.update!(due_date: Date.today) - _, updates = service.execute(content, issuable) + end + + it 'populates due_date: nil if content contains /remove_due_date' do + _, updates, _ = service.execute(content, issuable) expect(updates).to eq(due_date: nil) end + + it 'returns Removed the due date' do + _, _, message = service.execute(content, issuable) + + expect(message).to eq('Removed the due date.') + end end shared_examples 'wip command' do it 'returns wip_event: "wip" if content contains /wip' do - _, updates = service.execute(content, issuable) + _, updates, _ = service.execute(content, issuable) expect(updates).to eq(wip_event: 'wip') end + + it 'returns the wip message' do + _, _, message = service.execute(content, issuable) + + expect(message).to eq("Marked this #{issuable.to_ability_name.humanize(capitalize: false)} as Work In Progress.") + end end shared_examples 'unwip command' do it 'returns wip_event: "unwip" if content contains /wip' do issuable.update!(title: issuable.wip_title) - _, updates = service.execute(content, issuable) + _, updates, _ = service.execute(content, issuable) expect(updates).to eq(wip_event: 'unwip') end + + it 'returns the unwip message' do + issuable.update!(title: issuable.wip_title) + _, _, message = service.execute(content, issuable) + + expect(message).to eq("Unmarked this #{issuable.to_ability_name.humanize(capitalize: false)} as Work In Progress.") + end end shared_examples 'estimate command' do it 'populates time_estimate: 3600 if content contains /estimate 1h' do - _, updates = service.execute(content, issuable) + _, updates, _ = service.execute(content, issuable) expect(updates).to eq(time_estimate: 3600) end + + it 'returns the time_estimate formatted message' do + _, _, message = service.execute('/estimate 79d', issuable) + + expect(message).to eq('Set time estimate to 3mo 3w 4d.') + end end shared_examples 'spend command' do it 'populates spend_time: 3600 if content contains /spend 1h' do - _, updates = service.execute(content, issuable) + _, updates, _ = service.execute(content, issuable) expect(updates).to eq(spend_time: { duration: 3600, @@ -240,11 +364,17 @@ describe QuickActions::InterpretService do spent_at: DateTime.now.to_date }) end + + it 'returns the spend_time message including the formatted duration and verb' do + _, _, message = service.execute('/spend -120m', issuable) + + expect(message).to eq('Subtracted 2h spent time.') + end end shared_examples 'spend command with negative time' do it 'populates spend_time: -1800 if content contains /spend -30m' do - _, updates = service.execute(content, issuable) + _, updates, _ = service.execute(content, issuable) expect(updates).to eq(spend_time: { duration: -1800, @@ -256,7 +386,7 @@ describe QuickActions::InterpretService do shared_examples 'spend command with valid date' do it 'populates spend time: 1800 with date in date type format' do - _, updates = service.execute(content, issuable) + _, updates, _ = service.execute(content, issuable) expect(updates).to eq(spend_time: { duration: 1800, @@ -268,7 +398,7 @@ describe QuickActions::InterpretService do shared_examples 'spend command with invalid date' do it 'will not create any note and timelog' do - _, updates = service.execute(content, issuable) + _, updates, _ = service.execute(content, issuable) expect(updates).to eq({}) end @@ -276,7 +406,7 @@ describe QuickActions::InterpretService do shared_examples 'spend command with future date' do it 'will not create any note and timelog' do - _, updates = service.execute(content, issuable) + _, updates, _ = service.execute(content, issuable) expect(updates).to eq({}) end @@ -284,18 +414,30 @@ describe QuickActions::InterpretService do shared_examples 'remove_estimate command' do it 'populates time_estimate: 0 if content contains /remove_estimate' do - _, updates = service.execute(content, issuable) + _, updates, _ = service.execute(content, issuable) expect(updates).to eq(time_estimate: 0) end + + it 'returns the remove_estimate message' do + _, _, message = service.execute(content, issuable) + + expect(message).to eq('Removed time estimate.') + end end shared_examples 'remove_time_spent command' do it 'populates spend_time: :reset if content contains /remove_time_spent' do - _, updates = service.execute(content, issuable) + _, updates, _ = service.execute(content, issuable) expect(updates).to eq(spend_time: { duration: :reset, user_id: developer.id }) end + + it 'returns the remove_time_spent message' do + _, _, message = service.execute(content, issuable) + + expect(message).to eq('Removed spent time.') + end end shared_examples 'lock command' do @@ -303,10 +445,16 @@ describe QuickActions::InterpretService do 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) + _, updates, _ = service.execute(content, issuable) expect(updates).to eq(discussion_locked: true) end + + it 'returns the lock discussion message' do + _, _, message = service.execute(content, issuable) + + expect(message).to eq('Locked the discussion') + end end shared_examples 'unlock command' do @@ -314,45 +462,79 @@ describe QuickActions::InterpretService do 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) + _, updates, _ = service.execute(content, issuable) expect(updates).to eq(discussion_locked: false) end + + it 'returns the unlock discussion message' do + _, _, message = service.execute(content, issuable) + + expect(message).to eq('Unlocked the discussion') + end end - shared_examples 'empty command' do + shared_examples 'empty command' do |error_msg| it 'populates {} if content contains an unsupported command' do - _, updates = service.execute(content, issuable) + _, updates, _ = service.execute(content, issuable) expect(updates).to be_empty end + + it "returns #{error_msg || 'an empty'} message" do + _, _, message = service.execute(content, issuable) + + if error_msg + expect(message).to eq(error_msg) + else + expect(message).to be_empty + end + end end shared_examples 'merge command' do let(:project) { create(:project, :repository) } it 'runs merge command if content contains /merge' do - _, updates = service.execute(content, issuable) + _, updates, _ = service.execute(content, issuable) expect(updates).to eq(merge: merge_request.diff_head_sha) end + + it 'returns them merge message' do + _, _, message = service.execute(content, issuable) + + expect(message).to eq('Scheduled to merge this merge request when the pipeline succeeds.') + end end shared_examples 'award command' do it 'toggle award 100 emoji if content contains /award :100:' do - _, updates = service.execute(content, issuable) + _, updates, _ = service.execute(content, issuable) expect(updates).to eq(emoji_award: "100") end + + it 'returns the award message' do + _, _, message = service.execute(content, issuable) + + expect(message).to eq('Toggled :100: emoji award.') + end end shared_examples 'duplicate command' do it 'fetches issue and populates canonical_issue_id if content contains /duplicate issue_reference' do issue_duplicate # populate the issue - _, updates = service.execute(content, issuable) + _, updates, _ = service.execute(content, issuable) expect(updates).to eq(canonical_issue_id: issue_duplicate.id) end + + it 'returns the duplicate message' do + _, _, message = service.execute(content, issuable) + + expect(message).to eq("Marked this issue as a duplicate of #{issue_duplicate.to_reference(project)}.") + end end shared_examples 'copy_metadata command' do @@ -360,7 +542,7 @@ describe QuickActions::InterpretService do source_issuable # populate the issue todo_label # populate this label inreview_label # populate this label - _, updates = service.execute(content, issuable) + _, updates, _ = service.execute(content, issuable) expect(updates[:add_label_ids]).to match_array([inreview_label.id, todo_label.id]) @@ -370,19 +552,45 @@ describe QuickActions::InterpretService do expect(updates).not_to have_key(:milestone_id) end end + + it 'returns the copy metadata message' do + _, _, message = service.execute("/copy_metadata #{source_issuable.to_reference}", issuable) + + expect(message).to eq("Copied labels and milestone from #{source_issuable.to_reference}.") + end + end + + describe 'move issue command' do + it 'returns the move issue message' do + _, _, message = service.execute("/move #{project.full_path}", issue) + + expect(message).to eq("Moved this issue to #{project.full_path}.") + end + + it 'returns move issue failure message when the referenced issue is not found' do + _, _, message = service.execute('/move invalid', issue) + + expect(message).to eq("Move this issue failed because target project doesn't exists") + end end shared_examples 'confidential command' do it 'marks issue as confidential if content contains /confidential' do - _, updates = service.execute(content, issuable) + _, updates, _ = service.execute(content, issuable) expect(updates).to eq(confidential: true) end + + it 'returns the confidential message' do + _, _, message = service.execute(content, issuable) + + expect(message).to eq('Made this issue confidential') + end end shared_examples 'shrug command' do it 'appends ¯\_(ツ)_/¯ to the comment' do - new_content, _ = service.execute(content, issuable) + new_content, _, _ = service.execute(content, issuable) expect(new_content).to end_with(described_class::SHRUG) end @@ -390,7 +598,7 @@ describe QuickActions::InterpretService do shared_examples 'tableflip command' do it 'appends (╯°□°)╯︵ ┻━┻ to the comment' do - new_content, _ = service.execute(content, issuable) + new_content, _, _ = service.execute(content, issuable) expect(new_content).to end_with(described_class::TABLEFLIP) end @@ -398,18 +606,34 @@ describe QuickActions::InterpretService do shared_examples 'tag command' do it 'tags a commit' do - _, updates = service.execute(content, issuable) + _, updates, _ = service.execute(content, issuable) expect(updates).to eq(tag_name: tag_name, tag_message: tag_message) end + + it 'returns the tag message' do + _, _, message = service.execute(content, issuable) + + if tag_message.present? + expect(message).to eq(%{Tagged this commit to #{tag_name} with "#{tag_message}".}) + else + expect(message).to eq("Tagged this commit to #{tag_name}.") + end + end end shared_examples 'assign command' do it 'assigns to a single user' do - _, updates = service.execute(content, issuable) + _, updates, _ = service.execute(content, issuable) expect(updates).to eq(assignee_ids: [developer.id]) end + + it 'returns the assign message' do + _, _, message = service.execute(content, issuable) + + expect(message).to eq("Assigned #{developer.to_reference}.") + end end it_behaves_like 'reopen command' do @@ -463,7 +687,7 @@ describe QuickActions::InterpretService do let(:service) { described_class.new(project, developer, {}) } it 'precheck passes and returns merge command' do - _, updates = service.execute('/merge', merge_request) + _, updates, _ = service.execute('/merge', merge_request) expect(updates).to eq(merge: nil) end @@ -559,7 +783,7 @@ describe QuickActions::InterpretService do end end - it_behaves_like 'empty command' do + it_behaves_like 'empty command', "Assign command failed because no user was found" do let(:content) { '/assign @abcd1234' } let(:issuable) { issue } end @@ -574,20 +798,34 @@ describe QuickActions::InterpretService do context 'Issue' do it 'populates assignee_ids: [] if content contains /unassign' do - issue.update(assignee_ids: [developer.id]) - _, updates = service.execute(content, issue) + issue.update!(assignee_ids: [developer.id]) + _, updates, _ = service.execute(content, issue) expect(updates).to eq(assignee_ids: []) end + + it 'returns the unassign message for all the assignee if content contains /unassign' do + issue.update(assignee_ids: [developer.id, developer2.id]) + _, _, message = service.execute(content, issue) + + expect(message).to eq("Removed assignees #{developer.to_reference} and #{developer2.to_reference}.") + end end context 'Merge Request' do it 'populates assignee_ids: [] if content contains /unassign' do - merge_request.update(assignee_ids: [developer.id]) - _, updates = service.execute(content, merge_request) + merge_request.update!(assignee_ids: [developer.id]) + _, updates, _ = service.execute(content, merge_request) expect(updates).to eq(assignee_ids: []) end + + it 'returns the unassign message for all the assignee if content contains /unassign' do + merge_request.update(assignee_ids: [developer.id, developer2.id]) + _, _, message = service.execute(content, merge_request) + + expect(message).to eq("Removed assignees #{developer.to_reference} and #{developer2.to_reference}.") + end end end @@ -979,12 +1217,12 @@ describe QuickActions::InterpretService do let(:issuable) { issue } end - it_behaves_like 'empty command' do + it_behaves_like 'empty command', 'Mark as duplicate failed because referenced issue was not found' do let(:content) { "/duplicate imaginary#1234" } let(:issuable) { issue } end - it_behaves_like 'empty command' do + it_behaves_like 'empty command', 'Mark as duplicate failed because referenced issue was not found' do let(:other_project) { create(:project, :private) } let(:issue_duplicate) { create(:issue, project: other_project) } @@ -1049,7 +1287,7 @@ describe QuickActions::InterpretService do let(:issuable) { issue } end - it_behaves_like 'empty command' do + it_behaves_like 'empty command', 'Mark as duplicate failed because referenced issue was not found' do let(:content) { '/duplicate #{issue.to_reference}' } let(:issuable) { issue } end @@ -1132,13 +1370,13 @@ describe QuickActions::InterpretService do let(:service) { described_class.new(non_empty_project, developer)} it 'updates target_branch if /target_branch command is executed' do - _, updates = service.execute('/target_branch merge-test', merge_request) + _, updates, _ = service.execute('/target_branch merge-test', merge_request) expect(updates).to eq(target_branch: 'merge-test') end it 'handles blanks around param' do - _, updates = service.execute('/target_branch merge-test ', merge_request) + _, updates, _ = service.execute('/target_branch merge-test ', merge_request) expect(updates).to eq(target_branch: 'merge-test') end @@ -1156,6 +1394,12 @@ describe QuickActions::InterpretService do let(:issuable) { another_merge_request } end end + + it 'returns the target_branch message' do + _, _, message = service.execute('/target_branch merge-test', merge_request) + + expect(message).to eq('Set target branch to merge-test.') + end end context '/board_move command' do @@ -1171,13 +1415,13 @@ describe QuickActions::InterpretService do it 'populates remove_label_ids for all current board columns' do issue.update!(label_ids: [todo.id, inprogress.id]) - _, updates = service.execute(content, issue) + _, updates, _ = service.execute(content, issue) expect(updates[:remove_label_ids]).to match_array([todo.id, inprogress.id]) end it 'populates add_label_ids with the id of the given label' do - _, updates = service.execute(content, issue) + _, updates, _ = service.execute(content, issue) expect(updates[:add_label_ids]).to eq([inreview.id]) end @@ -1185,7 +1429,7 @@ describe QuickActions::InterpretService do it 'does not include the given label id in remove_label_ids' do issue.update!(label_ids: [todo.id, inreview.id]) - _, updates = service.execute(content, issue) + _, updates, _ = service.execute(content, issue) expect(updates[:remove_label_ids]).to match_array([todo.id]) end @@ -1193,11 +1437,19 @@ describe QuickActions::InterpretService do it 'does not remove label ids that are not lists on the board' do issue.update!(label_ids: [todo.id, bug.id]) - _, updates = service.execute(content, issue) + _, updates, _ = service.execute(content, issue) expect(updates[:remove_label_ids]).to match_array([todo.id]) end + it 'returns board_move message' do + issue.update!(label_ids: [todo.id, inprogress.id]) + + _, _, message = service.execute(content, issue) + + expect(message).to eq("Moved issue to ~#{inreview.id} column in the board.") + end + context 'if the project has multiple boards' do let(:issuable) { issue } @@ -1211,13 +1463,13 @@ describe QuickActions::InterpretService do context 'if the given label does not exist' do let(:issuable) { issue } let(:content) { '/board_move ~"Fake Label"' } - it_behaves_like 'empty command' + it_behaves_like 'empty command', 'Move this issue failed because you need to specify only one label.' end context 'if multiple labels are given' do let(:issuable) { issue } let(:content) { %{/board_move ~"#{inreview.title}" ~"#{todo.title}"} } - it_behaves_like 'empty command' + it_behaves_like 'empty command', 'Move this issue failed because you need to specify only one label.' end context 'if the given label is not a list on the board' do @@ -1292,10 +1544,16 @@ describe QuickActions::InterpretService do end it 'populates create_merge_request with branch_name and issue iid' do - _, updates = service.execute(content, issuable) + _, updates, _ = service.execute(content, issuable) expect(updates).to eq(create_merge_request: { branch_name: branch_name, issue_iid: issuable.iid }) end + + it 'returns the create_merge_request message' do + _, _, message = service.execute(content, issuable) + + expect(message).to eq("Created branch '#{branch_name}' and a merge request to resolve this issue") + end end end @@ -1558,6 +1816,12 @@ describe QuickActions::InterpretService do expect(explanations).to eq(['Creates a branch and a merge request to resolve this issue']) end + + it 'returns the execution message using the default branch name' do + _, _, message = service.execute(content, issue) + + expect(message).to eq('Created a branch and a merge request to resolve this issue') + end end context 'with a branch name' do @@ -1568,6 +1832,12 @@ describe QuickActions::InterpretService do expect(explanations).to eq(["Creates branch 'foo' and a merge request to resolve this issue"]) end + + it 'returns the execution message using the given branch name' do + _, _, message = service.execute(content, issue) + + expect(message).to eq("Created branch 'foo' and a merge request to resolve this issue") + end end end diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb index 157cfc46e69..486d0ca0c56 100644 --- a/spec/services/system_note_service_spec.rb +++ b/spec/services/system_note_service_spec.rb @@ -513,6 +513,30 @@ describe SystemNoteService do end end + describe '.zoom_link_added' do + subject { described_class.zoom_link_added(issue, project, author) } + + it_behaves_like 'a system note' do + let(:action) { 'pinned_embed' } + end + + it 'sets the zoom link added note text' do + expect(subject.note).to eq('a Zoom call was added to this issue') + end + end + + describe '.zoom_link_removed' do + subject { described_class.zoom_link_removed(issue, project, author) } + + it_behaves_like 'a system note' do + let(:action) { 'pinned_embed' } + end + + it 'sets the zoom link removed note text' do + expect(subject.note).to eq('a Zoom call was removed from this issue') + end + end + describe '.cross_reference' do subject { described_class.cross_reference(noteable, mentioner, author) } diff --git a/spec/services/todos/destroy/entity_leave_service_spec.rb b/spec/services/todos/destroy/entity_leave_service_spec.rb index 2a553e18807..ce809bbf6c5 100644 --- a/spec/services/todos/destroy/entity_leave_service_spec.rb +++ b/spec/services/todos/destroy/entity_leave_service_spec.rb @@ -176,7 +176,7 @@ describe Todos::Destroy::EntityLeaveService do end end - context 'with nested groups', :nested_groups do + context 'with nested groups' do let(:subgroup) { create(:group, :private, parent: group) } let(:subgroup2) { create(:group, :private, parent: group) } let(:subproject) { create(:project, group: subgroup) } diff --git a/spec/services/todos/destroy/group_private_service_spec.rb b/spec/services/todos/destroy/group_private_service_spec.rb index a1798686d7c..7dd495847b3 100644 --- a/spec/services/todos/destroy/group_private_service_spec.rb +++ b/spec/services/todos/destroy/group_private_service_spec.rb @@ -35,7 +35,7 @@ describe Todos::Destroy::GroupPrivateService do expect(project_member.todos).to match_array([todo_project_member]) end - context 'with nested groups', :nested_groups do + context 'with nested groups' do let(:parent_group) { create(:group) } let(:subgroup) { create(:group, :private, parent: group) } let(:subproject) { create(:project, group: subgroup) } diff --git a/spec/services/users/refresh_authorized_projects_service_spec.rb b/spec/services/users/refresh_authorized_projects_service_spec.rb index 0287a24808d..f5a914bb482 100644 --- a/spec/services/users/refresh_authorized_projects_service_spec.rb +++ b/spec/services/users/refresh_authorized_projects_service_spec.rb @@ -135,7 +135,7 @@ describe Users::RefreshAuthorizedProjectsService do end end - context 'projects of subgroups of groups the user is a member of', :nested_groups do + context 'projects of subgroups of groups the user is a member of' do let(:group) { create(:group) } let(:nested_group) { create(:group, parent: group) } let!(:other_project) { create(:project, group: nested_group) } @@ -163,7 +163,7 @@ describe Users::RefreshAuthorizedProjectsService do end end - context 'projects shared with subgroups of groups the user is a member of', :nested_groups do + context 'projects shared with subgroups of groups the user is a member of' do let(:group) { create(:group) } let(:nested_group) { create(:group, parent: group) } let(:other_project) { create(:project) } diff --git a/spec/services/zoom_notes_service_spec.rb b/spec/services/zoom_notes_service_spec.rb new file mode 100644 index 00000000000..419ecf3f374 --- /dev/null +++ b/spec/services/zoom_notes_service_spec.rb @@ -0,0 +1,81 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe ZoomNotesService do + describe '#execute' do + let(:issue) { OpenStruct.new(description: description) } + let(:project) { Object.new } + let(:user) { Object.new } + let(:description) { 'an issue description' } + let(:old_description) { nil } + + subject { described_class.new(issue, project, user, old_description: old_description) } + + shared_examples 'no notifications' do + it "doesn't create notifications" do + expect(SystemNoteService).not_to receive(:zoom_link_added) + expect(SystemNoteService).not_to receive(:zoom_link_removed) + + subject.execute + end + end + + it_behaves_like 'no notifications' + + context 'when the zoom link exists in both description and old_description' do + let(:description) { 'a changed issue description https://zoom.us/j/123' } + let(:old_description) { 'an issue description https://zoom.us/j/123' } + + it_behaves_like 'no notifications' + end + + context "when the zoom link doesn't exist in both description and old_description" do + let(:description) { 'a changed issue description' } + let(:old_description) { 'an issue description' } + + it_behaves_like 'no notifications' + end + + context 'when description == old_description' do + let(:old_description) { 'an issue description' } + + it_behaves_like 'no notifications' + end + + context 'when the description contains a zoom link and old_description is nil' do + let(:description) { 'a changed issue description https://zoom.us/j/123' } + + it 'creates a zoom_link_added notification' do + expect(SystemNoteService).to receive(:zoom_link_added).with(issue, project, user) + expect(SystemNoteService).not_to receive(:zoom_link_removed) + + subject.execute + end + end + + context 'when the zoom link has been added to the description' do + let(:description) { 'a changed issue description https://zoom.us/j/123' } + let(:old_description) { 'an issue description' } + + it 'creates a zoom_link_added notification' do + expect(SystemNoteService).to receive(:zoom_link_added).with(issue, project, user) + expect(SystemNoteService).not_to receive(:zoom_link_removed) + + subject.execute + end + end + + context 'when the zoom link has been removed from the description' do + let(:description) { 'a changed issue description' } + let(:old_description) { 'an issue description https://zoom.us/j/123' } + + it 'creates a zoom_link_removed notification' do + expect(SystemNoteService).not_to receive(:zoom_link_added).with(issue, project, user) + expect(SystemNoteService).to receive(:zoom_link_removed) + + subject.execute + end + end + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index a44b5069ade..6994b6687fc 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -3,6 +3,7 @@ SimpleCovEnv.start! ENV["RAILS_ENV"] = 'test' ENV["IN_MEMORY_APPLICATION_SETTINGS"] = 'true' +ENV["RSPEC_ALLOW_INVALID_URLS"] = 'true' require File.expand_path('../config/environment', __dir__) require 'rspec/rails' @@ -258,14 +259,6 @@ RSpec.configure do |config| Gitlab::CurrentSettings.clear_in_memory_application_settings! end - config.around(:each, :nested_groups) do |example| - example.run if Group.supports_nested_objects? - end - - config.around(:each, :postgresql) do |example| - example.run if Gitlab::Database.postgresql? - end - # This makes sure the `ApplicationController#can?` method is stubbed with the # original implementation for all view specs. config.before(:each, type: :view) do diff --git a/spec/support/api/boards_shared_examples.rb b/spec/support/api/boards_shared_examples.rb index 3abb5096a7a..b7aff32460d 100644 --- a/spec/support/api/boards_shared_examples.rb +++ b/spec/support/api/boards_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples_for 'group and project boards' do |route_definition, ee = false| let(:root_url) { route_definition.gsub(":id", board_parent.id.to_s) } diff --git a/spec/support/api/issues_resolving_discussions_shared_examples.rb b/spec/support/api/issues_resolving_discussions_shared_examples.rb index d2d6260dfa8..4c44f1bd103 100644 --- a/spec/support/api/issues_resolving_discussions_shared_examples.rb +++ b/spec/support/api/issues_resolving_discussions_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples 'creating an issue resolving discussions through the API' do it 'creates a new project issue' do expect(response).to have_gitlab_http_status(:created) diff --git a/spec/support/api/members_shared_examples.rb b/spec/support/api/members_shared_examples.rb index 8d910e52eda..603efd4fc75 100644 --- a/spec/support/api/members_shared_examples.rb +++ b/spec/support/api/members_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples 'a 404 response when source is private' do before do source.update_column(:visibility_level, Gitlab::VisibilityLevel::PRIVATE) diff --git a/spec/support/api/milestones_shared_examples.rb b/spec/support/api/milestones_shared_examples.rb index 63b719be03e..d6439f77408 100644 --- a/spec/support/api/milestones_shared_examples.rb +++ b/spec/support/api/milestones_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples_for 'group and project milestones' do |route_definition| let(:resource_route) { "#{route}/#{milestone.id}" } let(:label_1) { create(:label, title: 'label_1', project: project, priority: 1) } diff --git a/spec/support/api/repositories_shared_context.rb b/spec/support/api/repositories_shared_context.rb index f1341804e56..346015106e3 100644 --- a/spec/support/api/repositories_shared_context.rb +++ b/spec/support/api/repositories_shared_context.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_context 'disabled repository' do before do project.project_feature.update!( diff --git a/spec/support/api/schema_matcher.rb b/spec/support/api/schema_matcher.rb index 4cf34d43117..ebbd57c8115 100644 --- a/spec/support/api/schema_matcher.rb +++ b/spec/support/api/schema_matcher.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module SchemaPath def self.expand(schema, dir = nil) if Gitlab.ee? && dir.nil? diff --git a/spec/support/api/scopes/read_user_shared_examples.rb b/spec/support/api/scopes/read_user_shared_examples.rb index 683234264a8..3786a8012f9 100644 --- a/spec/support/api/scopes/read_user_shared_examples.rb +++ b/spec/support/api/scopes/read_user_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples_for 'allows the "read_user" scope' do |api_version| let(:version) { api_version || 'v4' } diff --git a/spec/support/api/time_tracking_shared_examples.rb b/spec/support/api/time_tracking_shared_examples.rb index 15037222630..3bd1b145433 100644 --- a/spec/support/api/time_tracking_shared_examples.rb +++ b/spec/support/api/time_tracking_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples 'an unauthorized API user' do it { is_expected.to eq(403) } end diff --git a/spec/support/banzai/reference_filter_shared_examples.rb b/spec/support/banzai/reference_filter_shared_examples.rb index 476d80f3a93..27765652f28 100644 --- a/spec/support/banzai/reference_filter_shared_examples.rb +++ b/spec/support/banzai/reference_filter_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Specs for reference links containing HTML. # # Requires a reference: diff --git a/spec/support/batch_loader.rb b/spec/support/batch_loader.rb index bb790e660a6..0eb8f279d29 100644 --- a/spec/support/batch_loader.rb +++ b/spec/support/batch_loader.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + RSpec.configure do |config| config.after do BatchLoader::Executor.clear_current diff --git a/spec/support/capybara.rb b/spec/support/capybara.rb index 60990879fe2..8accc5c1df5 100644 --- a/spec/support/capybara.rb +++ b/spec/support/capybara.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # rubocop:disable Style/GlobalVars require 'capybara/rails' require 'capybara/rspec' diff --git a/spec/support/carrierwave.rb b/spec/support/carrierwave.rb index b376822d530..8da55514c78 100644 --- a/spec/support/carrierwave.rb +++ b/spec/support/carrierwave.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + CarrierWave.root = File.expand_path('tmp/tests/public', Rails.root) RSpec.configure do |config| diff --git a/spec/support/chunked_io/chunked_io_helpers.rb b/spec/support/chunked_io/chunked_io_helpers.rb index fec1f951563..278f577f3cb 100644 --- a/spec/support/chunked_io/chunked_io_helpers.rb +++ b/spec/support/chunked_io/chunked_io_helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ChunkedIOHelpers def sample_trace_raw @sample_trace_raw ||= File.read(expand_fixture_path('trace/sample_trace')) diff --git a/spec/support/commit_trailers_spec_helper.rb b/spec/support/commit_trailers_spec_helper.rb index efa317fd2f9..a958e259368 100644 --- a/spec/support/commit_trailers_spec_helper.rb +++ b/spec/support/commit_trailers_spec_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module CommitTrailersSpecHelper extend ActiveSupport::Concern diff --git a/spec/support/controllers/githubish_import_controller_shared_context.rb b/spec/support/controllers/githubish_import_controller_shared_context.rb index e71994edec6..3706178ee34 100644 --- a/spec/support/controllers/githubish_import_controller_shared_context.rb +++ b/spec/support/controllers/githubish_import_controller_shared_context.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_context 'a GitHub-ish import controller' do let(:user) { create(:user) } let(:token) { "asdasd12345" } diff --git a/spec/support/controllers/githubish_import_controller_shared_examples.rb b/spec/support/controllers/githubish_import_controller_shared_examples.rb index 5bb1269a19d..718d9857b18 100644 --- a/spec/support/controllers/githubish_import_controller_shared_examples.rb +++ b/spec/support/controllers/githubish_import_controller_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Specifications for behavior common to all objects with an email attribute. # Takes a list of email-format attributes and requires: # - subject { "the object with a attribute= setter" } @@ -321,7 +323,7 @@ shared_examples 'a GitHub-ish import controller: POST create' do end end - context 'user has chosen an existing nested namespace and name for the project', :postgresql do + context 'user has chosen an existing nested namespace and name for the project' do let(:parent_namespace) { create(:group, name: 'foo') } let(:nested_namespace) { create(:group, name: 'bar', parent: parent_namespace) } let(:test_name) { 'test_name' } @@ -340,7 +342,7 @@ shared_examples 'a GitHub-ish import controller: POST create' do end end - context 'user has chosen a non-existent nested namespaces and name for the project', :postgresql do + context 'user has chosen a non-existent nested namespaces and name for the project' do let(:test_name) { 'test_name' } it 'takes the selected namespace and name' do @@ -371,7 +373,7 @@ shared_examples 'a GitHub-ish import controller: POST create' do end end - context 'user has chosen existent and non-existent nested namespaces and name for the project', :postgresql do + context 'user has chosen existent and non-existent nested namespaces and name for the project' do let(:test_name) { 'test_name' } let!(:parent_namespace) { create(:group, name: 'foo') } diff --git a/spec/support/controllers/ldap_omniauth_callbacks_controller_shared_context.rb b/spec/support/controllers/ldap_omniauth_callbacks_controller_shared_context.rb index a0c77eecb61..d636c1cf6cd 100644 --- a/spec/support/controllers/ldap_omniauth_callbacks_controller_shared_context.rb +++ b/spec/support/controllers/ldap_omniauth_callbacks_controller_shared_context.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' shared_context 'Ldap::OmniauthCallbacksController' do diff --git a/spec/support/controllers/sessionless_auth_controller_shared_examples.rb b/spec/support/controllers/sessionless_auth_controller_shared_examples.rb index 355555d9d19..b5149a0fcb1 100644 --- a/spec/support/controllers/sessionless_auth_controller_shared_examples.rb +++ b/spec/support/controllers/sessionless_auth_controller_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples 'authenticates sessionless user' do |path, format, params| params ||= {} diff --git a/spec/support/cycle_analytics_helpers/test_generation.rb b/spec/support/cycle_analytics_helpers/test_generation.rb index be1c2bc3046..c57abbd96c6 100644 --- a/spec/support/cycle_analytics_helpers/test_generation.rb +++ b/spec/support/cycle_analytics_helpers/test_generation.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # rubocop:disable Metrics/AbcSize # Note: The ABC size is large here because we have a method generating test cases with diff --git a/spec/support/db_cleaner.rb b/spec/support/db_cleaner.rb index 08622dff6d9..041ffa25535 100644 --- a/spec/support/db_cleaner.rb +++ b/spec/support/db_cleaner.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module DbCleaner def delete_from_all_tables!(except: nil) DatabaseCleaner.clean_with(:deletion, cache_tables: false, except: except) diff --git a/spec/support/external_authorization_service_helpers.rb b/spec/support/external_authorization_service_helpers.rb index 79dd9a3d58e..f4214d800cf 100644 --- a/spec/support/external_authorization_service_helpers.rb +++ b/spec/support/external_authorization_service_helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ExternalAuthorizationServiceHelpers def enable_external_authorization_service_check stub_application_setting(external_authorization_service_enabled: true) diff --git a/spec/support/features/discussion_comments_shared_example.rb b/spec/support/features/discussion_comments_shared_example.rb index 7c8e57702ae..5590bf0fb7e 100644 --- a/spec/support/features/discussion_comments_shared_example.rb +++ b/spec/support/features/discussion_comments_shared_example.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples 'thread comments' do |resource_name| let(:form_selector) { '.js-main-target-form' } let(:dropdown_selector) { "#{form_selector} .comment-type-dropdown" } diff --git a/spec/support/features/reportable_note_shared_examples.rb b/spec/support/features/reportable_note_shared_examples.rb index 5d5a0a7b5d2..2f9208e6ed5 100644 --- a/spec/support/features/reportable_note_shared_examples.rb +++ b/spec/support/features/reportable_note_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' shared_examples 'reportable note' do |type| diff --git a/spec/support/features/resolving_discussions_in_issues_shared_examples.rb b/spec/support/features/resolving_discussions_in_issues_shared_examples.rb index 8d0e03134d0..d4f8a87d0d8 100644 --- a/spec/support/features/resolving_discussions_in_issues_shared_examples.rb +++ b/spec/support/features/resolving_discussions_in_issues_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples 'creating an issue for a thread' do it 'shows an issue with the title filled in' do title_field = page.find_field('issue[title]') diff --git a/spec/support/features/rss_shared_examples.rb b/spec/support/features/rss_shared_examples.rb index 0de92aedba5..c97eeba87db 100644 --- a/spec/support/features/rss_shared_examples.rb +++ b/spec/support/features/rss_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples "an autodiscoverable RSS feed with current_user's feed token" do it "has an RSS autodiscovery link tag with current_user's feed token" do expect(page).to have_css("link[type*='atom+xml'][href*='feed_token=#{user.feed_token}']", visible: false) diff --git a/spec/support/features/variable_list_shared_examples.rb b/spec/support/features/variable_list_shared_examples.rb index 01531864c1f..0f8ad2c6536 100644 --- a/spec/support/features/variable_list_shared_examples.rb +++ b/spec/support/features/variable_list_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples 'variable list' do it 'shows list of variables' do page.within('.js-ci-variable-list-section') do diff --git a/spec/support/forgery_protection.rb b/spec/support/forgery_protection.rb index fa87d5fa881..1d6ea013292 100644 --- a/spec/support/forgery_protection.rb +++ b/spec/support/forgery_protection.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ForgeryProtection def with_forgery_protection ActionController::Base.allow_forgery_protection = true diff --git a/spec/support/google_api/cloud_platform_helpers.rb b/spec/support/google_api/cloud_platform_helpers.rb index 2fdbddd40c2..a1328ef0d13 100644 --- a/spec/support/google_api/cloud_platform_helpers.rb +++ b/spec/support/google_api/cloud_platform_helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module GoogleApi module CloudPlatformHelpers def stub_google_api_validate_token diff --git a/spec/support/helpers/api_helpers.rb b/spec/support/helpers/api_helpers.rb index 4a9ce9beb78..aff0f87b6e4 100644 --- a/spec/support/helpers/api_helpers.rb +++ b/spec/support/helpers/api_helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ApiHelpers # Public: Prepend a request path with the path to the API # @@ -30,11 +32,12 @@ module ApiHelpers end if query_string - full_path << (path.index('?') ? '&' : '?') - full_path << query_string - end + separator = path.index('?') ? '&' : '?' - full_path + full_path + separator + query_string + else + full_path + end end def expect_paginated_array_response(items) diff --git a/spec/support/helpers/assets_helpers.rb b/spec/support/helpers/assets_helpers.rb index 09bbf451671..fa24ad9ad2a 100644 --- a/spec/support/helpers/assets_helpers.rb +++ b/spec/support/helpers/assets_helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module AssetsHelpers # In a CI environment the assets are not compiled, as there is a CI job # `compile-assets` that compiles them in the prepare stage for all following diff --git a/spec/support/helpers/bare_repo_operations.rb b/spec/support/helpers/bare_repo_operations.rb index 3f4a4243cb6..099610f087d 100644 --- a/spec/support/helpers/bare_repo_operations.rb +++ b/spec/support/helpers/bare_repo_operations.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'zlib' class BareRepoOperations diff --git a/spec/support/helpers/board_helpers.rb b/spec/support/helpers/board_helpers.rb index b85fde222ea..683ee3e4bf2 100644 --- a/spec/support/helpers/board_helpers.rb +++ b/spec/support/helpers/board_helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module BoardHelpers def click_card(card) within card do diff --git a/spec/support/helpers/capybara_helpers.rb b/spec/support/helpers/capybara_helpers.rb index bcc2df44708..5abbc1e2951 100644 --- a/spec/support/helpers/capybara_helpers.rb +++ b/spec/support/helpers/capybara_helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module CapybaraHelpers # Execute a block a certain number of times before considering it a failure # diff --git a/spec/support/helpers/ci_artifact_metadata_generator.rb b/spec/support/helpers/ci_artifact_metadata_generator.rb index ef638d59d2d..e02501565a9 100644 --- a/spec/support/helpers/ci_artifact_metadata_generator.rb +++ b/spec/support/helpers/ci_artifact_metadata_generator.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # frozen_sting_literal: true # This generates fake CI metadata .gz for testing diff --git a/spec/support/helpers/cookie_helper.rb b/spec/support/helpers/cookie_helper.rb index 5ff7b0b68c9..ea4be12355b 100644 --- a/spec/support/helpers/cookie_helper.rb +++ b/spec/support/helpers/cookie_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Helper for setting cookies in Selenium/WebDriver # module CookieHelper diff --git a/spec/support/helpers/cycle_analytics_helpers.rb b/spec/support/helpers/cycle_analytics_helpers.rb index 100e439ef44..575b2e779c5 100644 --- a/spec/support/helpers/cycle_analytics_helpers.rb +++ b/spec/support/helpers/cycle_analytics_helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module CycleAnalyticsHelpers include GitHelpers diff --git a/spec/support/helpers/database_connection_helpers.rb b/spec/support/helpers/database_connection_helpers.rb index 763329499f0..10ea7b5de91 100644 --- a/spec/support/helpers/database_connection_helpers.rb +++ b/spec/support/helpers/database_connection_helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module DatabaseConnectionHelpers def run_with_new_database_connection pool = ActiveRecord::Base.connection_pool diff --git a/spec/support/helpers/devise_helpers.rb b/spec/support/helpers/devise_helpers.rb index fb2a110422a..70fc6a48414 100644 --- a/spec/support/helpers/devise_helpers.rb +++ b/spec/support/helpers/devise_helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module DeviseHelpers # explicitly tells Devise which mapping to use # this is needed when we are testing a Devise controller bypassing the router diff --git a/spec/support/helpers/drag_to_helper.rb b/spec/support/helpers/drag_to_helper.rb index 6d53ad0b602..6099f87323f 100644 --- a/spec/support/helpers/drag_to_helper.rb +++ b/spec/support/helpers/drag_to_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module DragTo def drag_to(list_from_index: 0, from_index: 0, to_index: 0, list_to_index: 0, selector: '', scrollable: 'body', duration: 1000) evaluate_script("simulateDrag({scrollable: $('#{scrollable}').get(0), duration: #{duration}, from: {el: $('#{selector}').eq(#{list_from_index}).get(0), index: #{from_index}}, to: {el: $('#{selector}').eq(#{list_to_index}).get(0), index: #{to_index}}});") diff --git a/spec/support/helpers/dropzone_helper.rb b/spec/support/helpers/dropzone_helper.rb index fe72d320fcf..a0f261b312e 100644 --- a/spec/support/helpers/dropzone_helper.rb +++ b/spec/support/helpers/dropzone_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module DropzoneHelper # Provides a way to perform `attach_file` for a Dropzone-based file input # diff --git a/spec/support/helpers/email_helpers.rb b/spec/support/helpers/email_helpers.rb index ed049daba80..83ba654fab3 100644 --- a/spec/support/helpers/email_helpers.rb +++ b/spec/support/helpers/email_helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module EmailHelpers def sent_to_user(user, recipients: email_recipients) recipients.count { |to| to == user.notification_email } diff --git a/spec/support/helpers/exclusive_lease_helpers.rb b/spec/support/helpers/exclusive_lease_helpers.rb index 383cc7dee81..77703e20602 100644 --- a/spec/support/helpers/exclusive_lease_helpers.rb +++ b/spec/support/helpers/exclusive_lease_helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ExclusiveLeaseHelpers def stub_exclusive_lease(key = nil, uuid = 'uuid', renew: false, timeout: nil) key ||= instance_of(String) diff --git a/spec/support/helpers/expect_next_instance_of.rb b/spec/support/helpers/expect_next_instance_of.rb index b95046b2b42..749d2cb2a56 100644 --- a/spec/support/helpers/expect_next_instance_of.rb +++ b/spec/support/helpers/expect_next_instance_of.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ExpectNextInstanceOf def expect_next_instance_of(klass, *new_args) receive_new = receive(:new) diff --git a/spec/support/helpers/expect_offense.rb b/spec/support/helpers/expect_offense.rb index 35718ba90c5..76301fe19ff 100644 --- a/spec/support/helpers/expect_offense.rb +++ b/spec/support/helpers/expect_offense.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rubocop/rspec/support' # https://github.com/backus/rubocop-rspec/blob/master/spec/support/expect_offense.rb diff --git a/spec/support/helpers/fake_blob_helpers.rb b/spec/support/helpers/fake_blob_helpers.rb index 801ca8b7412..ef4740638ff 100644 --- a/spec/support/helpers/fake_blob_helpers.rb +++ b/spec/support/helpers/fake_blob_helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module FakeBlobHelpers class FakeBlob include BlobLike diff --git a/spec/support/helpers/fake_migration_classes.rb b/spec/support/helpers/fake_migration_classes.rb index c7766df7a52..6c066b3b199 100644 --- a/spec/support/helpers/fake_migration_classes.rb +++ b/spec/support/helpers/fake_migration_classes.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class FakeRenameReservedPathMigrationV1 < ActiveRecord::Migration[4.2] include Gitlab::Database::RenameReservedPathsMigration::V1 diff --git a/spec/support/helpers/fake_u2f_device.rb b/spec/support/helpers/fake_u2f_device.rb index 22cd8152d77..f765b277175 100644 --- a/spec/support/helpers/fake_u2f_device.rb +++ b/spec/support/helpers/fake_u2f_device.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class FakeU2fDevice attr_reader :name diff --git a/spec/support/helpers/features/branches_helpers.rb b/spec/support/helpers/features/branches_helpers.rb index df88fd425c9..2a50b41cb4e 100644 --- a/spec/support/helpers/features/branches_helpers.rb +++ b/spec/support/helpers/features/branches_helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # These helpers allow you to manipulate with sorting features. # # Usage: diff --git a/spec/support/helpers/features/notes_helpers.rb b/spec/support/helpers/features/notes_helpers.rb index 8a139fafac2..a2d8d71b541 100644 --- a/spec/support/helpers/features/notes_helpers.rb +++ b/spec/support/helpers/features/notes_helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # These helpers allow you to manipulate with notes. # # Usage: diff --git a/spec/support/helpers/features/sorting_helpers.rb b/spec/support/helpers/features/sorting_helpers.rb index 003ecb251fe..a6428bf8573 100644 --- a/spec/support/helpers/features/sorting_helpers.rb +++ b/spec/support/helpers/features/sorting_helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # These helpers allow you to manipulate with sorting features. # # Usage: diff --git a/spec/support/helpers/filter_spec_helper.rb b/spec/support/helpers/filter_spec_helper.rb index 721d359c2ee..95c24d76dcd 100644 --- a/spec/support/helpers/filter_spec_helper.rb +++ b/spec/support/helpers/filter_spec_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Helper methods for Banzai filter specs # # Must be included into specs manually diff --git a/spec/support/helpers/filtered_search_helpers.rb b/spec/support/helpers/filtered_search_helpers.rb index 34ef185ea27..39c818b1763 100644 --- a/spec/support/helpers/filtered_search_helpers.rb +++ b/spec/support/helpers/filtered_search_helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module FilteredSearchHelpers def filtered_search page.find('.filtered-search') diff --git a/spec/support/helpers/fixture_helpers.rb b/spec/support/helpers/fixture_helpers.rb index 611d19f36a0..7b3b8ae5f7a 100644 --- a/spec/support/helpers/fixture_helpers.rb +++ b/spec/support/helpers/fixture_helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module FixtureHelpers def fixture_file(filename, dir: '') return '' if filename.blank? diff --git a/spec/support/helpers/git_http_helpers.rb b/spec/support/helpers/git_http_helpers.rb index c83860d7b51..de8bb9ac8e3 100644 --- a/spec/support/helpers/git_http_helpers.rb +++ b/spec/support/helpers/git_http_helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative 'workhorse_helpers' module GitHttpHelpers diff --git a/spec/support/helpers/gitlab_verify_helpers.rb b/spec/support/helpers/gitlab_verify_helpers.rb index 5df4bf24ec2..9901ce374ed 100644 --- a/spec/support/helpers/gitlab_verify_helpers.rb +++ b/spec/support/helpers/gitlab_verify_helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module GitlabVerifyHelpers def collect_ranges(args = {}) verifier = described_class.new(args.merge(batch_size: 1)) diff --git a/spec/support/helpers/graphql_helpers.rb b/spec/support/helpers/graphql_helpers.rb index ec3c460cd37..ae1b859ae3f 100644 --- a/spec/support/helpers/graphql_helpers.rb +++ b/spec/support/helpers/graphql_helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module GraphqlHelpers MutationDefinition = Struct.new(:query, :variables) diff --git a/spec/support/helpers/import_spec_helper.rb b/spec/support/helpers/import_spec_helper.rb index d4eced724fa..d8fb2ba08af 100644 --- a/spec/support/helpers/import_spec_helper.rb +++ b/spec/support/helpers/import_spec_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'ostruct' # Helper methods for controller specs in the Import namespace diff --git a/spec/support/helpers/input_helper.rb b/spec/support/helpers/input_helper.rb index acbb42274ec..5136f8e9cb8 100644 --- a/spec/support/helpers/input_helper.rb +++ b/spec/support/helpers/input_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # see app/assets/javascripts/test_utils/simulate_input.js module InputHelper diff --git a/spec/support/helpers/inspect_requests.rb b/spec/support/helpers/inspect_requests.rb index 88ddc5c7f6c..4a1d9cb8539 100644 --- a/spec/support/helpers/inspect_requests.rb +++ b/spec/support/helpers/inspect_requests.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative './wait_for_requests' module InspectRequests diff --git a/spec/support/helpers/issue_helpers.rb b/spec/support/helpers/issue_helpers.rb index ffd72515f37..82b954a92e2 100644 --- a/spec/support/helpers/issue_helpers.rb +++ b/spec/support/helpers/issue_helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module IssueHelpers def visit_issues(project, opts = {}) visit project_issues_path project, opts diff --git a/spec/support/helpers/javascript_fixtures_helpers.rb b/spec/support/helpers/javascript_fixtures_helpers.rb index e9129bd263e..7ec65318ec5 100644 --- a/spec/support/helpers/javascript_fixtures_helpers.rb +++ b/spec/support/helpers/javascript_fixtures_helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'action_dispatch/testing/test_request' require 'fileutils' diff --git a/spec/support/helpers/jira_service_helper.rb b/spec/support/helpers/jira_service_helper.rb index 7e955f3d593..57c33c81ea3 100644 --- a/spec/support/helpers/jira_service_helper.rb +++ b/spec/support/helpers/jira_service_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module JiraServiceHelper JIRA_URL = "http://jira.example.net".freeze JIRA_API = JIRA_URL + "/rest/api/2" diff --git a/spec/support/helpers/key_generator_helper.rb b/spec/support/helpers/key_generator_helper.rb index d55d8312c65..59c8eeb3692 100644 --- a/spec/support/helpers/key_generator_helper.rb +++ b/spec/support/helpers/key_generator_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Spec module Support module Helpers @@ -33,7 +35,7 @@ module Spec # Packs string components into an openssh-encoded pubkey. def pack_pubkey_components(strings) - (strings.map { |s| [s.length].pack('N') }).zip(strings).flatten.join + (strings.flat_map { |s| [s.length].pack('N') }).zip(strings).join end end end diff --git a/spec/support/helpers/kubernetes_helpers.rb b/spec/support/helpers/kubernetes_helpers.rb index 278264f3df5..538a5b8ef3c 100644 --- a/spec/support/helpers/kubernetes_helpers.rb +++ b/spec/support/helpers/kubernetes_helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module KubernetesHelpers include Gitlab::Kubernetes diff --git a/spec/support/helpers/ldap_helpers.rb b/spec/support/helpers/ldap_helpers.rb index 66ca5d7f0a3..dce8a3803f5 100644 --- a/spec/support/helpers/ldap_helpers.rb +++ b/spec/support/helpers/ldap_helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module LdapHelpers def ldap_adapter(provider = 'ldapmain', ldap = double(:ldap)) ::Gitlab::Auth::LDAP::Adapter.new(provider, ldap) diff --git a/spec/support/helpers/live_debugger.rb b/spec/support/helpers/live_debugger.rb index 911eb48a8ca..d6091035b59 100644 --- a/spec/support/helpers/live_debugger.rb +++ b/spec/support/helpers/live_debugger.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'io/console' module LiveDebugger diff --git a/spec/support/helpers/login_helpers.rb b/spec/support/helpers/login_helpers.rb index 0cb99b4e087..2b508ee6f2c 100644 --- a/spec/support/helpers/login_helpers.rb +++ b/spec/support/helpers/login_helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative 'devise_helpers' module LoginHelpers diff --git a/spec/support/helpers/markdown_feature.rb b/spec/support/helpers/markdown_feature.rb index 96401379cf0..eea03fb9325 100644 --- a/spec/support/helpers/markdown_feature.rb +++ b/spec/support/helpers/markdown_feature.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # This is a helper class used by the GitLab Markdown feature spec # # Because the feature spec only cares about the output of the Markdown, and the diff --git a/spec/support/helpers/merge_request_diff_helpers.rb b/spec/support/helpers/merge_request_diff_helpers.rb index 3b49d0b3319..49beecc6d4b 100644 --- a/spec/support/helpers/merge_request_diff_helpers.rb +++ b/spec/support/helpers/merge_request_diff_helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module MergeRequestDiffHelpers def click_diff_line(line_holder, diff_side = nil) line = get_line_components(line_holder, diff_side) diff --git a/spec/support/helpers/merge_request_helpers.rb b/spec/support/helpers/merge_request_helpers.rb index 772adff4626..3c359bc9353 100644 --- a/spec/support/helpers/merge_request_helpers.rb +++ b/spec/support/helpers/merge_request_helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module MergeRequestHelpers def visit_merge_requests(project, opts = {}) visit project_merge_requests_path project, opts diff --git a/spec/support/helpers/migrations_helpers.rb b/spec/support/helpers/migrations_helpers.rb index 272b24f7541..2727ab7fb1e 100644 --- a/spec/support/helpers/migrations_helpers.rb +++ b/spec/support/helpers/migrations_helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module MigrationsHelpers def active_record_base ActiveRecord::Base diff --git a/spec/support/helpers/mobile_helpers.rb b/spec/support/helpers/mobile_helpers.rb index 4230d315d9b..94dbd2fb1b7 100644 --- a/spec/support/helpers/mobile_helpers.rb +++ b/spec/support/helpers/mobile_helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module MobileHelpers def resize_screen_xs resize_window(575, 768) diff --git a/spec/support/helpers/note_interaction_helpers.rb b/spec/support/helpers/note_interaction_helpers.rb index 79a0aa174b1..a4322618cd3 100644 --- a/spec/support/helpers/note_interaction_helpers.rb +++ b/spec/support/helpers/note_interaction_helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module NoteInteractionHelpers def open_more_actions_dropdown(note) note_element = find("#note_#{note.id}") diff --git a/spec/support/helpers/notification_helpers.rb b/spec/support/helpers/notification_helpers.rb index 44c2051598c..16ecb338f6e 100644 --- a/spec/support/helpers/notification_helpers.rb +++ b/spec/support/helpers/notification_helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module NotificationHelpers extend self diff --git a/spec/support/helpers/project_forks_helper.rb b/spec/support/helpers/project_forks_helper.rb index bcb11a09b36..b2d22853e4c 100644 --- a/spec/support/helpers/project_forks_helper.rb +++ b/spec/support/helpers/project_forks_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ProjectForksHelper def fork_project(project, user = nil, params = {}) Gitlab::GitalyClient.allow_n_plus_1_calls do diff --git a/spec/support/helpers/prometheus_helpers.rb b/spec/support/helpers/prometheus_helpers.rb index db662836013..7c03746a395 100644 --- a/spec/support/helpers/prometheus_helpers.rb +++ b/spec/support/helpers/prometheus_helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module PrometheusHelpers def prometheus_memory_query(environment_slug) %{avg(container_memory_usage_bytes{container_name!="POD",environment="#{environment_slug}"}) / 2^20} @@ -74,6 +76,14 @@ module PrometheusHelpers WebMock.stub_request(:any, /prometheus.example.com/) end + def stub_any_prometheus_request_with_response(status: 200, headers: {}, body: nil) + stub_any_prometheus_request.to_return({ + status: status, + headers: { 'Content-Type' => 'application/json' }.merge(headers), + body: body || prometheus_values_body.to_json + }) + end + def stub_all_prometheus_requests(environment_slug, body: nil, status: 200) stub_prometheus_request( prometheus_query_with_time_url(prometheus_memory_query(environment_slug), Time.now.utc), diff --git a/spec/support/helpers/query_recorder.rb b/spec/support/helpers/query_recorder.rb index f77b43391dd..d936dc6de41 100644 --- a/spec/support/helpers/query_recorder.rb +++ b/spec/support/helpers/query_recorder.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActiveRecord class QueryRecorder attr_reader :log, :skip_cached, :cached diff --git a/spec/support/helpers/quick_actions_helpers.rb b/spec/support/helpers/quick_actions_helpers.rb index 361190aa352..cb853f5363f 100644 --- a/spec/support/helpers/quick_actions_helpers.rb +++ b/spec/support/helpers/quick_actions_helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module QuickActionsHelpers def write_note(text) Sidekiq::Testing.fake! do diff --git a/spec/support/helpers/rake_helpers.rb b/spec/support/helpers/rake_helpers.rb index 7d8d7750bf3..d8f354a69da 100644 --- a/spec/support/helpers/rake_helpers.rb +++ b/spec/support/helpers/rake_helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module RakeHelpers def run_rake_task(task_name, *args) Rake::Task[task_name].reenable diff --git a/spec/support/helpers/reactive_caching_helpers.rb b/spec/support/helpers/reactive_caching_helpers.rb index 528da37e8cf..aa9d3b3a199 100644 --- a/spec/support/helpers/reactive_caching_helpers.rb +++ b/spec/support/helpers/reactive_caching_helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ReactiveCachingHelpers def reactive_cache_key(subject, *qualifiers) ([subject.class.reactive_cache_key.call(subject)].flatten + qualifiers).join(':') diff --git a/spec/support/helpers/redis_without_keys.rb b/spec/support/helpers/redis_without_keys.rb index 6220167dee6..e030f1028f7 100644 --- a/spec/support/helpers/redis_without_keys.rb +++ b/spec/support/helpers/redis_without_keys.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Redis ForbiddenCommand = Class.new(StandardError) diff --git a/spec/support/helpers/reference_parser_helpers.rb b/spec/support/helpers/reference_parser_helpers.rb index 9f27502aa52..f96a01d15b5 100644 --- a/spec/support/helpers/reference_parser_helpers.rb +++ b/spec/support/helpers/reference_parser_helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ReferenceParserHelpers def empty_html_link Nokogiri::HTML.fragment('<a></a>').children[0] diff --git a/spec/support/helpers/repo_helpers.rb b/spec/support/helpers/repo_helpers.rb index 44d95a029af..ca4d2acbf2c 100644 --- a/spec/support/helpers/repo_helpers.rb +++ b/spec/support/helpers/repo_helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module RepoHelpers extend self diff --git a/spec/support/helpers/routes_helpers.rb b/spec/support/helpers/routes_helpers.rb index c4129606418..2a7cd81cbe3 100644 --- a/spec/support/helpers/routes_helpers.rb +++ b/spec/support/helpers/routes_helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module RoutesHelpers def fake_routes(&block) @routes = @routes.dup diff --git a/spec/support/helpers/search_helpers.rb b/spec/support/helpers/search_helpers.rb index abbbb636d66..815337f8615 100644 --- a/spec/support/helpers/search_helpers.rb +++ b/spec/support/helpers/search_helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module SearchHelpers def select_filter(name) find(:xpath, "//ul[contains(@class, 'search-filter')]//a[contains(.,'#{name}')]").click diff --git a/spec/support/helpers/seed_repo.rb b/spec/support/helpers/seed_repo.rb index 71f1a86b0c1..20738b45129 100644 --- a/spec/support/helpers/seed_repo.rb +++ b/spec/support/helpers/seed_repo.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # This file is generated by generate-seed-repo-rb. Do not edit this file manually. # # Seed repo: diff --git a/spec/support/helpers/select2_helper.rb b/spec/support/helpers/select2_helper.rb index 87672c8896d..9c42c2b0d8b 100644 --- a/spec/support/helpers/select2_helper.rb +++ b/spec/support/helpers/select2_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative 'wait_for_requests' # Select2 ajax programmatic helper diff --git a/spec/support/helpers/selection_helper.rb b/spec/support/helpers/selection_helper.rb index b4725b137b2..a5f9ca76f6e 100644 --- a/spec/support/helpers/selection_helper.rb +++ b/spec/support/helpers/selection_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module SelectionHelper def select_element(selector) find(selector) diff --git a/spec/support/helpers/sorting_helper.rb b/spec/support/helpers/sorting_helper.rb index e505a6b7258..3801d25fb63 100644 --- a/spec/support/helpers/sorting_helper.rb +++ b/spec/support/helpers/sorting_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Helper allows you to sort items # # Params diff --git a/spec/support/helpers/stub_configuration.rb b/spec/support/helpers/stub_configuration.rb index 049702be1f6..c8b2bf040e6 100644 --- a/spec/support/helpers/stub_configuration.rb +++ b/spec/support/helpers/stub_configuration.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'active_support/core_ext/hash/transform_values' require 'active_support/hash_with_indifferent_access' require 'active_support/dependencies' diff --git a/spec/support/helpers/stub_env.rb b/spec/support/helpers/stub_env.rb index 1c2f474a015..8107ffc939f 100644 --- a/spec/support/helpers/stub_env.rb +++ b/spec/support/helpers/stub_env.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Inspired by https://github.com/ljkbennett/stub_env/blob/master/lib/stub_env/helpers.rb module StubENV def stub_env(key_or_hash, value = nil) diff --git a/spec/support/helpers/stub_feature_flags.rb b/spec/support/helpers/stub_feature_flags.rb index 48258692304..6c3efff7262 100644 --- a/spec/support/helpers/stub_feature_flags.rb +++ b/spec/support/helpers/stub_feature_flags.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module StubFeatureFlags # Stub Feature flags with `flag_name: true/false` # diff --git a/spec/support/helpers/stub_gitlab_calls.rb b/spec/support/helpers/stub_gitlab_calls.rb index 4cb3b18df85..badea94352a 100644 --- a/spec/support/helpers/stub_gitlab_calls.rb +++ b/spec/support/helpers/stub_gitlab_calls.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module StubGitlabCalls def stub_gitlab_calls stub_user diff --git a/spec/support/helpers/stub_gitlab_data.rb b/spec/support/helpers/stub_gitlab_data.rb index fa402f35b95..ed518393c03 100644 --- a/spec/support/helpers/stub_gitlab_data.rb +++ b/spec/support/helpers/stub_gitlab_data.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module StubGitlabData def gitlab_ci_yaml File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml')) diff --git a/spec/support/helpers/stub_metrics.rb b/spec/support/helpers/stub_metrics.rb index 64983fdf222..e347955efbb 100644 --- a/spec/support/helpers/stub_metrics.rb +++ b/spec/support/helpers/stub_metrics.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module StubMetrics def authentication_metrics Gitlab::Auth::Activity diff --git a/spec/support/helpers/stub_object_storage.rb b/spec/support/helpers/stub_object_storage.rb index d31f9908714..e5b8bb712bb 100644 --- a/spec/support/helpers/stub_object_storage.rb +++ b/spec/support/helpers/stub_object_storage.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module StubObjectStorage def stub_object_storage_uploader( config:, diff --git a/spec/support/helpers/stub_requests.rb b/spec/support/helpers/stub_requests.rb index 5cad35282c0..473f07dd413 100644 --- a/spec/support/helpers/stub_requests.rb +++ b/spec/support/helpers/stub_requests.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module StubRequests IP_ADDRESS_STUB = '8.8.8.9'.freeze @@ -26,6 +28,19 @@ module StubRequests .and_return([addr]) end + def stub_all_dns(url, ip_address:) + url = URI(url) + port = 80 # arbitarily chosen, does not matter as we are not going to connect + socket = Socket.sockaddr_in(port, ip_address) + addr = Addrinfo.new(socket) + + # See Gitlab::UrlBlocker + allow(Addrinfo).to receive(:getaddrinfo).and_call_original + allow(Addrinfo).to receive(:getaddrinfo) + .with(url.hostname, anything, nil, :STREAM) + .and_return([addr]) + end + def stubbed_hostname(url, hostname: IP_ADDRESS_STUB) url = parse_url(url) url.hostname = hostname diff --git a/spec/support/helpers/stub_worker.rb b/spec/support/helpers/stub_worker.rb index 58b7ee93dff..cac839ed5fe 100644 --- a/spec/support/helpers/stub_worker.rb +++ b/spec/support/helpers/stub_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Inspired by https://github.com/ljkbennett/stub_env/blob/master/lib/stub_env/helpers.rb module StubWorker def stub_worker(queue:) diff --git a/spec/support/helpers/terms_helper.rb b/spec/support/helpers/terms_helper.rb index a00ec14138b..a61bae18f9a 100644 --- a/spec/support/helpers/terms_helper.rb +++ b/spec/support/helpers/terms_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module TermsHelper def enforce_terms stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false') diff --git a/spec/support/helpers/test_env.rb b/spec/support/helpers/test_env.rb index b062631b995..a4acf76e1a3 100644 --- a/spec/support/helpers/test_env.rb +++ b/spec/support/helpers/test_env.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rspec/mocks' require 'toml-rb' diff --git a/spec/support/helpers/upload_helpers.rb b/spec/support/helpers/upload_helpers.rb index 5eead80c935..60e14a8673b 100644 --- a/spec/support/helpers/upload_helpers.rb +++ b/spec/support/helpers/upload_helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'fileutils' module UploadHelpers diff --git a/spec/support/helpers/wait_for_requests.rb b/spec/support/helpers/wait_for_requests.rb index 45b9faa0fea..3bb2f7c5b51 100644 --- a/spec/support/helpers/wait_for_requests.rb +++ b/spec/support/helpers/wait_for_requests.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module WaitForRequests extend self diff --git a/spec/support/helpers/wait_helpers.rb b/spec/support/helpers/wait_helpers.rb index 7e8e25798e8..a8c4408db59 100644 --- a/spec/support/helpers/wait_helpers.rb +++ b/spec/support/helpers/wait_helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module WaitHelpers extend self diff --git a/spec/support/helpers/wiki_helpers.rb b/spec/support/helpers/wiki_helpers.rb index 8165403cb60..06cea728b42 100644 --- a/spec/support/helpers/wiki_helpers.rb +++ b/spec/support/helpers/wiki_helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module WikiHelpers extend self diff --git a/spec/support/helpers/workhorse_helpers.rb b/spec/support/helpers/workhorse_helpers.rb index ef1f9f68671..4488e5f227e 100644 --- a/spec/support/helpers/workhorse_helpers.rb +++ b/spec/support/helpers/workhorse_helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module WorkhorseHelpers extend self diff --git a/spec/support/http_io/http_io_helpers.rb b/spec/support/http_io/http_io_helpers.rb index 42144870eb5..0193db81fa9 100644 --- a/spec/support/http_io/http_io_helpers.rb +++ b/spec/support/http_io/http_io_helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module HttpIOHelpers def stub_remote_url_206(url, file_path) WebMock.stub_request(:get, url) diff --git a/spec/support/import_export/common_util.rb b/spec/support/import_export/common_util.rb index 2542a59bb00..ac6840dbcfc 100644 --- a/spec/support/import_export/common_util.rb +++ b/spec/support/import_export/common_util.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ImportExport module CommonUtil def setup_symlink(tmpdir, symlink_name) diff --git a/spec/support/import_export/configuration_helper.rb b/spec/support/import_export/configuration_helper.rb index b4164cff922..122df7f27f0 100644 --- a/spec/support/import_export/configuration_helper.rb +++ b/spec/support/import_export/configuration_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ConfigurationHelper # Returns a list of models from hashes/arrays contained in +project_tree+ def names_from_tree(project_tree) diff --git a/spec/support/import_export/export_file_helper.rb b/spec/support/import_export/export_file_helper.rb index 388b88f0331..f862a9bc1a4 100644 --- a/spec/support/import_export/export_file_helper.rb +++ b/spec/support/import_export/export_file_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require './spec/support/import_export/configuration_helper' module ExportFileHelper diff --git a/spec/support/inspect_squelch.rb b/spec/support/inspect_squelch.rb index 8ee6732370b..90475204889 100644 --- a/spec/support/inspect_squelch.rb +++ b/spec/support/inspect_squelch.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # This class can generate a lot of output if it fails, # so squelch the instance variable output. class ActiveSupport::Cache::NullStore diff --git a/spec/support/issuables_requiring_filter_shared_examples.rb b/spec/support/issuables_requiring_filter_shared_examples.rb index 71bcc82ee58..ee25df00dfb 100644 --- a/spec/support/issuables_requiring_filter_shared_examples.rb +++ b/spec/support/issuables_requiring_filter_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples 'issuables requiring filter' do |action| it "doesn't load any issuables if no filter is set" do expect_any_instance_of(described_class).not_to receive(:issuables_collection) diff --git a/spec/support/json_response.rb b/spec/support/json_response.rb index 43d8ab73dde..55bdce0cfe9 100644 --- a/spec/support/json_response.rb +++ b/spec/support/json_response.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + RSpec.configure do |config| config.include_context 'JSON response', type: :controller config.include_context 'JSON response', type: :request diff --git a/spec/support/matchers/abort_matcher.rb b/spec/support/matchers/abort_matcher.rb index ce1dd140210..64fed2ca069 100644 --- a/spec/support/matchers/abort_matcher.rb +++ b/spec/support/matchers/abort_matcher.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + RSpec::Matchers.define :abort_execution do match do |code_block| @captured_stderr = StringIO.new diff --git a/spec/support/matchers/access_matchers.rb b/spec/support/matchers/access_matchers.rb index e6899e2d23c..c9ff777f604 100644 --- a/spec/support/matchers/access_matchers.rb +++ b/spec/support/matchers/access_matchers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # AccessMatchers # # The custom matchers contained in this module are used to test a user's access diff --git a/spec/support/matchers/access_matchers_for_controller.rb b/spec/support/matchers/access_matchers_for_controller.rb index 429401a5da8..401bf6c196e 100644 --- a/spec/support/matchers/access_matchers_for_controller.rb +++ b/spec/support/matchers/access_matchers_for_controller.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # AccessMatchersForController # # For testing authorize_xxx in controller. diff --git a/spec/support/matchers/background_migrations_matchers.rb b/spec/support/matchers/background_migrations_matchers.rb index f4127efc6ae..c38aa7ad6a6 100644 --- a/spec/support/matchers/background_migrations_matchers.rb +++ b/spec/support/matchers/background_migrations_matchers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + RSpec::Matchers.define :be_scheduled_delayed_migration do |delay, *expected| match do |migration| BackgroundMigrationWorker.jobs.any? do |job| diff --git a/spec/support/matchers/be_a_binary_string.rb b/spec/support/matchers/be_a_binary_string.rb index f041ae76167..6195c6c7554 100644 --- a/spec/support/matchers/be_a_binary_string.rb +++ b/spec/support/matchers/be_a_binary_string.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + RSpec::Matchers.define :be_a_binary_string do |_| match do |actual| actual.is_a?(String) && actual.encoding == Encoding.find('ASCII-8BIT') diff --git a/spec/support/matchers/be_like_time.rb b/spec/support/matchers/be_like_time.rb index 1f27390eab7..b449f7a7ffb 100644 --- a/spec/support/matchers/be_like_time.rb +++ b/spec/support/matchers/be_like_time.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + RSpec::Matchers.define :be_like_time do |expected| match do |actual| expect(actual).to be_within(1.second).of(expected) diff --git a/spec/support/matchers/be_url.rb b/spec/support/matchers/be_url.rb index f8096af1b22..7bd0e7fada4 100644 --- a/spec/support/matchers/be_url.rb +++ b/spec/support/matchers/be_url.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + RSpec::Matchers.define :be_url do |_| match do |actual| URI.parse(actual) rescue false diff --git a/spec/support/matchers/be_utf8.rb b/spec/support/matchers/be_utf8.rb index ea806352422..4fa55539a49 100644 --- a/spec/support/matchers/be_utf8.rb +++ b/spec/support/matchers/be_utf8.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + RSpec::Matchers.define :be_utf8 do |_| match do |actual| actual.is_a?(String) && actual.encoding == Encoding.find('UTF-8') diff --git a/spec/support/matchers/be_valid_commit.rb b/spec/support/matchers/be_valid_commit.rb index 3696e4d5f03..b59339de622 100644 --- a/spec/support/matchers/be_valid_commit.rb +++ b/spec/support/matchers/be_valid_commit.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + RSpec::Matchers.define :be_valid_commit do match do |actual| actual && diff --git a/spec/support/matchers/disallow_request_matchers.rb b/spec/support/matchers/disallow_request_matchers.rb index db4d90e4fd0..a161e3660cd 100644 --- a/spec/support/matchers/disallow_request_matchers.rb +++ b/spec/support/matchers/disallow_request_matchers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + RSpec::Matchers.define :disallow_request do match do |middleware| alert = middleware.env['rack.session'].to_hash diff --git a/spec/support/matchers/exceed_query_limit.rb b/spec/support/matchers/exceed_query_limit.rb index cd042401f3a..40cf85eb8e5 100644 --- a/spec/support/matchers/exceed_query_limit.rb +++ b/spec/support/matchers/exceed_query_limit.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ExceedQueryLimitHelpers def with_threshold(threshold) @threshold = threshold diff --git a/spec/support/matchers/execute_check.rb b/spec/support/matchers/execute_check.rb index 7232fad52fb..d3c0751f0dc 100644 --- a/spec/support/matchers/execute_check.rb +++ b/spec/support/matchers/execute_check.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + RSpec::Matchers.define :execute_check do |expected| match do |actual| expect(actual).to eq(SystemCheck) diff --git a/spec/support/matchers/gitaly_matchers.rb b/spec/support/matchers/gitaly_matchers.rb index 933ed22b5d0..c2b3ebe3422 100644 --- a/spec/support/matchers/gitaly_matchers.rb +++ b/spec/support/matchers/gitaly_matchers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + RSpec::Matchers.define :gitaly_request_with_path do |storage_name, relative_path| match do |actual| repository = actual.repository diff --git a/spec/support/matchers/gitlab_git_matchers.rb b/spec/support/matchers/gitlab_git_matchers.rb index c840cd4bf2d..aea1603db05 100644 --- a/spec/support/matchers/gitlab_git_matchers.rb +++ b/spec/support/matchers/gitlab_git_matchers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + RSpec::Matchers.define :gitlab_git_repository_with do |values| match do |actual| actual.is_a?(Gitlab::Git::Repository) && diff --git a/spec/support/matchers/graphql_matchers.rb b/spec/support/matchers/graphql_matchers.rb index 7894484f590..4d48b4b5389 100644 --- a/spec/support/matchers/graphql_matchers.rb +++ b/spec/support/matchers/graphql_matchers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + RSpec::Matchers.define :require_graphql_authorizations do |*expected| match do |field| expect(field.metadata[:authorize]).to eq(*expected) diff --git a/spec/support/matchers/have_emoji.rb b/spec/support/matchers/have_emoji.rb index 23fb8e9c1c4..273bd0b7f40 100644 --- a/spec/support/matchers/have_emoji.rb +++ b/spec/support/matchers/have_emoji.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + RSpec::Matchers.define :have_emoji do |emoji_name| match do |actual| expect(actual).to have_selector("gl-emoji[data-name='#{emoji_name}']") diff --git a/spec/support/matchers/have_gitlab_http_status.rb b/spec/support/matchers/have_gitlab_http_status.rb index e7e418cdde4..13a64a58218 100644 --- a/spec/support/matchers/have_gitlab_http_status.rb +++ b/spec/support/matchers/have_gitlab_http_status.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + RSpec::Matchers.define :have_gitlab_http_status do |expected| match do |actual| expect(actual).to have_http_status(expected) diff --git a/spec/support/matchers/have_issuable_counts.rb b/spec/support/matchers/have_issuable_counts.rb index 92cf3de5448..049cfc022fb 100644 --- a/spec/support/matchers/have_issuable_counts.rb +++ b/spec/support/matchers/have_issuable_counts.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + RSpec::Matchers.define :have_issuable_counts do |opts| expected_counts = opts.map do |state, count| "#{state.to_s.humanize} #{count}" diff --git a/spec/support/matchers/include_module.rb b/spec/support/matchers/include_module.rb index 0a78af1e90e..9b6970cf061 100644 --- a/spec/support/matchers/include_module.rb +++ b/spec/support/matchers/include_module.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + RSpec::Matchers.define :include_module do |expected| match do described_class.included_modules.include?(expected) diff --git a/spec/support/matchers/issuable_matchers.rb b/spec/support/matchers/issuable_matchers.rb index 62f510b0fbd..743f0b8c932 100644 --- a/spec/support/matchers/issuable_matchers.rb +++ b/spec/support/matchers/issuable_matchers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + RSpec::Matchers.define :have_header_with_correct_id_and_link do |level, text, id, parent = ".md"| match do |actual| node = find("#{parent} h#{level} a#user-content-#{id}") diff --git a/spec/support/matchers/markdown_matchers.rb b/spec/support/matchers/markdown_matchers.rb index ec4ec6f4038..12e8fa83a60 100644 --- a/spec/support/matchers/markdown_matchers.rb +++ b/spec/support/matchers/markdown_matchers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # MarkdownMatchers # # Custom matchers for our custom HTML::Pipeline filters. These are used to test diff --git a/spec/support/matchers/match_file.rb b/spec/support/matchers/match_file.rb index d1888b3376a..4e522b52912 100644 --- a/spec/support/matchers/match_file.rb +++ b/spec/support/matchers/match_file.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + RSpec::Matchers.define :match_file do |expected| match do |actual| expect(Digest::MD5.hexdigest(actual)).to eq(Digest::MD5.hexdigest(File.read(expected))) diff --git a/spec/support/matchers/match_ids.rb b/spec/support/matchers/match_ids.rb index 1cb6b74acac..7bc41949937 100644 --- a/spec/support/matchers/match_ids.rb +++ b/spec/support/matchers/match_ids.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + RSpec::Matchers.define :match_ids do |*expected| match do |actual| actual_ids = map_ids(actual) diff --git a/spec/support/matchers/metric_counter_matcher.rb b/spec/support/matchers/metric_counter_matcher.rb index 22d5cd17e3f..f0d52b9b149 100644 --- a/spec/support/matchers/metric_counter_matcher.rb +++ b/spec/support/matchers/metric_counter_matcher.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + RSpec::Matchers.define :increment do |counter| match do |adapter| expect(adapter.send(counter)) diff --git a/spec/support/matchers/navigation_matcher.rb b/spec/support/matchers/navigation_matcher.rb index 63f59b9654c..ad73c96031e 100644 --- a/spec/support/matchers/navigation_matcher.rb +++ b/spec/support/matchers/navigation_matcher.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + RSpec::Matchers.define :have_active_navigation do |expected| match do |page| expect(page).to have_selector('.sidebar-top-level-items > li.active', count: 1) diff --git a/spec/support/matchers/pagination_matcher.rb b/spec/support/matchers/pagination_matcher.rb index 9a7697e2bfc..a3e9c3b8474 100644 --- a/spec/support/matchers/pagination_matcher.rb +++ b/spec/support/matchers/pagination_matcher.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + RSpec::Matchers.define :include_pagination_headers do |expected| match do |actual| expect(actual.headers).to include('X-Total', 'X-Total-Pages', 'X-Per-Page', 'X-Page', 'X-Next-Page', 'X-Prev-Page', 'Link') diff --git a/spec/support/matchers/query_matcher.rb b/spec/support/matchers/query_matcher.rb index bb0feca7c43..3e47fe241bc 100644 --- a/spec/support/matchers/query_matcher.rb +++ b/spec/support/matchers/query_matcher.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + RSpec::Matchers.define :make_queries_matching do |matcher, expected_count = nil| supports_block_expectations diff --git a/spec/support/matchers/satisfy_matchers.rb b/spec/support/matchers/satisfy_matchers.rb index 585915bac93..dd1920ee2b2 100644 --- a/spec/support/matchers/satisfy_matchers.rb +++ b/spec/support/matchers/satisfy_matchers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # These matchers are a syntactic hack to provide more readable expectations for # an Enumerable object. # diff --git a/spec/support/matchers/security_header_matcher.rb b/spec/support/matchers/security_header_matcher.rb index f8518d13ebb..760b1fddd06 100644 --- a/spec/support/matchers/security_header_matcher.rb +++ b/spec/support/matchers/security_header_matcher.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + RSpec::Matchers.define :include_security_headers do |expected| match do |actual| expect(actual.headers).to include('X-Content-Type-Options') diff --git a/spec/support/migrations_helpers/track_untracked_uploads_helpers.rb b/spec/support/migrations_helpers/track_untracked_uploads_helpers.rb index 016bcfa9b1b..656be3b6d4d 100644 --- a/spec/support/migrations_helpers/track_untracked_uploads_helpers.rb +++ b/spec/support/migrations_helpers/track_untracked_uploads_helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module MigrationsHelpers module TrackUntrackedUploadsHelpers PUBLIC_DIR = File.join(Rails.root, 'tmp', 'tests', 'public') diff --git a/spec/support/omni_auth.rb b/spec/support/omni_auth.rb index 0b1af4052ff..64aa3855a6f 100644 --- a/spec/support/omni_auth.rb +++ b/spec/support/omni_auth.rb @@ -1 +1,3 @@ +# frozen_string_literal: true + OmniAuth.config.test_mode = true diff --git a/spec/support/prometheus/additional_metrics_shared_examples.rb b/spec/support/prometheus/additional_metrics_shared_examples.rb index de21e808932..82582630dee 100644 --- a/spec/support/prometheus/additional_metrics_shared_examples.rb +++ b/spec/support/prometheus/additional_metrics_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + RSpec.shared_examples 'additional metrics query' do include Prometheus::MetricBuilders diff --git a/spec/support/prometheus/metric_builders.rb b/spec/support/prometheus/metric_builders.rb index c8d056d3fc8..512e32a44d0 100644 --- a/spec/support/prometheus/metric_builders.rb +++ b/spec/support/prometheus/metric_builders.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Prometheus module MetricBuilders def simple_query(suffix = 'a', **opts) diff --git a/spec/support/protected_tags/access_control_ce_shared_examples.rb b/spec/support/protected_tags/access_control_ce_shared_examples.rb index 71eec9f3217..8666c19481c 100644 --- a/spec/support/protected_tags/access_control_ce_shared_examples.rb +++ b/spec/support/protected_tags/access_control_ce_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + RSpec.shared_examples "protected tags > access control > CE" do ProtectedRefAccess::HUMAN_ACCESS_LEVELS.each do |(access_type_id, access_type_name)| it "allows creating protected tags that #{access_type_name} can create" do diff --git a/spec/support/redis/redis_helpers.rb b/spec/support/redis/redis_helpers.rb index 0457e8487d8..7c571738a01 100644 --- a/spec/support/redis/redis_helpers.rb +++ b/spec/support/redis/redis_helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module RedisHelpers # config/README.md diff --git a/spec/support/redis/redis_shared_examples.rb b/spec/support/redis/redis_shared_examples.rb index 6aa59960092..7e47cdae866 100644 --- a/spec/support/redis/redis_shared_examples.rb +++ b/spec/support/redis/redis_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + RSpec.shared_examples "redis_shared_examples" do include StubENV diff --git a/spec/support/rspec.rb b/spec/support/rspec.rb index b38c5dfe60b..1c9f9e5161e 100644 --- a/spec/support/rspec.rb +++ b/spec/support/rspec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative "helpers/stub_configuration" require_relative "helpers/stub_metrics" require_relative "helpers/stub_object_storage" diff --git a/spec/support/seed.rb b/spec/support/seed.rb index bea2e9c3044..36cb819763b 100644 --- a/spec/support/seed.rb +++ b/spec/support/seed.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + RSpec.configure do |config| config.include SeedHelper, :seed_helper diff --git a/spec/support/services/clusters/create_service_shared.rb b/spec/support/services/clusters/create_service_shared.rb index b0bf942aa09..6ec8750ce87 100644 --- a/spec/support/services/clusters/create_service_shared.rb +++ b/spec/support/services/clusters/create_service_shared.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_context 'valid cluster create params' do let(:params) do { diff --git a/spec/support/services/issuable_create_service_slash_commands_shared_examples.rb b/spec/support/services/issuable_create_service_slash_commands_shared_examples.rb index 8b4cffaac19..4c3644e6724 100644 --- a/spec/support/services/issuable_create_service_slash_commands_shared_examples.rb +++ b/spec/support/services/issuable_create_service_slash_commands_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Specifications for behavior common to all objects with executable attributes. # It can take a `default_params`. diff --git a/spec/support/services/issuable_update_service_shared_examples.rb b/spec/support/services/issuable_update_service_shared_examples.rb index ffbce6c42bf..5e5acd0e40a 100644 --- a/spec/support/services/issuable_update_service_shared_examples.rb +++ b/spec/support/services/issuable_update_service_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples 'issuable update service' do def update_issuable(opts) described_class.new(project, user, opts).execute(open_issuable) diff --git a/spec/support/services/migrate_to_ghost_user_service_shared_examples.rb b/spec/support/services/migrate_to_ghost_user_service_shared_examples.rb index 1284415da1f..65236f13e27 100644 --- a/spec/support/services/migrate_to_ghost_user_service_shared_examples.rb +++ b/spec/support/services/migrate_to_ghost_user_service_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "spec_helper" shared_examples "migrating a deleted user's associated records to the ghost user" do |record_class, fields| diff --git a/spec/support/setup_builds_storage.rb b/spec/support/setup_builds_storage.rb index 1d2a4856724..bbe442f07b0 100644 --- a/spec/support/setup_builds_storage.rb +++ b/spec/support/setup_builds_storage.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + RSpec.configure do |config| def builds_path Rails.root.join('tmp/tests/builds') diff --git a/spec/support/shared_contexts/email_shared_context.rb b/spec/support/shared_contexts/email_shared_context.rb index 4f5d53f9317..b4d061a8215 100644 --- a/spec/support/shared_contexts/email_shared_context.rb +++ b/spec/support/shared_contexts/email_shared_context.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_context :email_shared_context do let(:mail_key) { "59d8df8370b7e95c5a49fbf86aeb2c93" } let(:receiver) { Gitlab::Email::Receiver.new(email_raw) } diff --git a/spec/support/shared_contexts/finders/group_projects_finder_shared_contexts.rb b/spec/support/shared_contexts/finders/group_projects_finder_shared_contexts.rb index a0d994c4d8d..38f6011646e 100644 --- a/spec/support/shared_contexts/finders/group_projects_finder_shared_contexts.rb +++ b/spec/support/shared_contexts/finders/group_projects_finder_shared_contexts.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' RSpec.shared_context 'GroupProjectsFinder context' do diff --git a/spec/support/shared_contexts/finders/issues_finder_shared_contexts.rb b/spec/support/shared_contexts/finders/issues_finder_shared_contexts.rb index b8a9554f55f..26ab6fbd400 100644 --- a/spec/support/shared_contexts/finders/issues_finder_shared_contexts.rb +++ b/spec/support/shared_contexts/finders/issues_finder_shared_contexts.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' RSpec.shared_context 'IssuesFinder context' do diff --git a/spec/support/shared_contexts/finders/merge_requests_finder_shared_contexts.rb b/spec/support/shared_contexts/finders/merge_requests_finder_shared_contexts.rb index ab6687f1d07..ef1e65d2577 100644 --- a/spec/support/shared_contexts/finders/merge_requests_finder_shared_contexts.rb +++ b/spec/support/shared_contexts/finders/merge_requests_finder_shared_contexts.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' RSpec.shared_context 'MergeRequestsFinder multiple projects with merge requests context' do diff --git a/spec/support/shared_contexts/finders/users_finder_shared_contexts.rb b/spec/support/shared_contexts/finders/users_finder_shared_contexts.rb index 9e1f89ee0ed..d6404b2ee4b 100644 --- a/spec/support/shared_contexts/finders/users_finder_shared_contexts.rb +++ b/spec/support/shared_contexts/finders/users_finder_shared_contexts.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' RSpec.shared_context 'UsersFinder#execute filter by project context' do diff --git a/spec/support/shared_contexts/json_response_shared_context.rb b/spec/support/shared_contexts/json_response_shared_context.rb index df5fc288089..bd37c97ed35 100644 --- a/spec/support/shared_contexts/json_response_shared_context.rb +++ b/spec/support/shared_contexts/json_response_shared_context.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_context 'JSON response' do let(:json_response) { JSON.parse(response.body) } end diff --git a/spec/support/shared_contexts/merge_requests_allowing_collaboration.rb b/spec/support/shared_contexts/merge_requests_allowing_collaboration.rb index 05424d08b9d..276ebf973c8 100644 --- a/spec/support/shared_contexts/merge_requests_allowing_collaboration.rb +++ b/spec/support/shared_contexts/merge_requests_allowing_collaboration.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_context 'merge request allowing collaboration' do include ProjectForksHelper diff --git a/spec/support/shared_contexts/policies/group_policy_shared_context.rb b/spec/support/shared_contexts/policies/group_policy_shared_context.rb index 74389c4d82b..c11725c63d2 100644 --- a/spec/support/shared_contexts/policies/group_policy_shared_context.rb +++ b/spec/support/shared_contexts/policies/group_policy_shared_context.rb @@ -31,7 +31,7 @@ RSpec.shared_context 'GroupPolicy context' do :admin_group_member, :change_visibility_level, :set_note_created_at, - (Gitlab::Database.postgresql? ? :create_subgroup : nil) + :create_subgroup ].compact end diff --git a/spec/support/shared_contexts/services_shared_context.rb b/spec/support/shared_contexts/services_shared_context.rb index 0c3a24d206f..4d176ab5fca 100644 --- a/spec/support/shared_contexts/services_shared_context.rb +++ b/spec/support/shared_contexts/services_shared_context.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + Service.available_services_names.each do |service| shared_context service do let(:dashed_service) { service.dasherize } diff --git a/spec/support/shared_contexts/url_shared_context.rb b/spec/support/shared_contexts/url_shared_context.rb index 1b1f67daac3..560cd500ecd 100644 --- a/spec/support/shared_contexts/url_shared_context.rb +++ b/spec/support/shared_contexts/url_shared_context.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_context 'invalid urls' do let(:urls_with_CRLF) do ["http://127.0.0.1:333/pa\rth", diff --git a/spec/support/shared_examples/application_setting_examples.rb b/spec/support/shared_examples/application_setting_examples.rb index e7ec24c5b7e..2c600785ad3 100644 --- a/spec/support/shared_examples/application_setting_examples.rb +++ b/spec/support/shared_examples/application_setting_examples.rb @@ -1,58 +1,54 @@ # frozen_string_literal: true -RSpec.shared_examples 'application settings examples' do - context 'restricted signup domains' do - it 'sets single domain' do - setting.domain_whitelist_raw = 'example.com' - expect(setting.domain_whitelist).to eq(['example.com']) - end +RSpec.shared_examples 'string of domains' do |attribute| + it 'sets single domain' do + setting.method("#{attribute}_raw=").call('example.com') + expect(setting.method(attribute).call).to eq(['example.com']) + end - it 'sets multiple domains with spaces' do - setting.domain_whitelist_raw = 'example.com *.example.com' - expect(setting.domain_whitelist).to eq(['example.com', '*.example.com']) - end + it 'sets multiple domains with spaces' do + setting.method("#{attribute}_raw=").call('example.com *.example.com') + expect(setting.method(attribute).call).to eq(['example.com', '*.example.com']) + end - it 'sets multiple domains with newlines and a space' do - setting.domain_whitelist_raw = "example.com\n *.example.com" - expect(setting.domain_whitelist).to eq(['example.com', '*.example.com']) - end + it 'sets multiple domains with newlines and a space' do + setting.method("#{attribute}_raw=").call("example.com\n *.example.com") + expect(setting.method(attribute).call).to eq(['example.com', '*.example.com']) + end - it 'sets multiple domains with commas' do - setting.domain_whitelist_raw = "example.com, *.example.com" - expect(setting.domain_whitelist).to eq(['example.com', '*.example.com']) - end + it 'sets multiple domains with commas' do + setting.method("#{attribute}_raw=").call("example.com, *.example.com") + expect(setting.method(attribute).call).to eq(['example.com', '*.example.com']) end - context 'blacklisted signup domains' do - it 'sets single domain' do - setting.domain_blacklist_raw = 'example.com' - expect(setting.domain_blacklist).to contain_exactly('example.com') - end + it 'sets multiple domains with semicolon' do + setting.method("#{attribute}_raw=").call("example.com; *.example.com") + expect(setting.method(attribute).call).to contain_exactly('example.com', '*.example.com') + end - it 'sets multiple domains with spaces' do - setting.domain_blacklist_raw = 'example.com *.example.com' - expect(setting.domain_blacklist).to contain_exactly('example.com', '*.example.com') - end + it 'sets multiple domains with mixture of everything' do + setting.method("#{attribute}_raw=").call("example.com; *.example.com\n test.com\sblock.com yes.com") + expect(setting.method(attribute).call).to contain_exactly('example.com', '*.example.com', 'test.com', 'block.com', 'yes.com') + end - it 'sets multiple domains with newlines and a space' do - setting.domain_blacklist_raw = "example.com\n *.example.com" - expect(setting.domain_blacklist).to contain_exactly('example.com', '*.example.com') - end + it 'removes duplicates' do + setting.method("#{attribute}_raw=").call("example.com; example.com; 127.0.0.1; 127.0.0.1") + expect(setting.method(attribute).call).to contain_exactly('example.com', '127.0.0.1') + end - it 'sets multiple domains with commas' do - setting.domain_blacklist_raw = "example.com, *.example.com" - expect(setting.domain_blacklist).to contain_exactly('example.com', '*.example.com') - end + it 'does not fail with garbage values' do + setting.method("#{attribute}_raw=").call("example;34543:garbage:fdh5654;") + expect(setting.method(attribute).call).to contain_exactly('example', '34543:garbage:fdh5654') + end +end - it 'sets multiple domains with semicolon' do - setting.domain_blacklist_raw = "example.com; *.example.com" - expect(setting.domain_blacklist).to contain_exactly('example.com', '*.example.com') - end +RSpec.shared_examples 'application settings examples' do + context 'restricted signup domains' do + it_behaves_like 'string of domains', :domain_whitelist + end - it 'sets multiple domains with mixture of everything' do - setting.domain_blacklist_raw = "example.com; *.example.com\n test.com\sblock.com yes.com" - expect(setting.domain_blacklist).to contain_exactly('example.com', '*.example.com', 'test.com', 'block.com', 'yes.com') - end + context 'blacklisted signup domains' do + it_behaves_like 'string of domains', :domain_blacklist it 'sets multiple domain with file' do setting.domain_blacklist_file = File.open(Rails.root.join('spec/fixtures/', 'domain_blacklist.txt')) @@ -60,6 +56,27 @@ RSpec.shared_examples 'application settings examples' do end end + context 'outbound_local_requests_whitelist' do + it_behaves_like 'string of domains', :outbound_local_requests_whitelist + end + + context 'outbound_local_requests_whitelist_arrays' do + it 'separates the IPs and domains' do + setting.outbound_local_requests_whitelist = [ + '192.168.1.1', '127.0.0.0/28', 'www.example.com', 'example.com', + '::ffff:a00:2', '1:0:0:0:0:0:0:0/124', 'subdomain.example.com' + ] + + ip_whitelist = [ + IPAddr.new('192.168.1.1'), IPAddr.new('127.0.0.0/8'), + IPAddr.new('::ffff:a00:2'), IPAddr.new('1:0:0:0:0:0:0:0/124') + ] + domain_whitelist = ['www.example.com', 'example.com', 'subdomain.example.com'] + + expect(setting.outbound_local_requests_whitelist_arrays).to contain_exactly(ip_whitelist, domain_whitelist) + end + end + describe 'usage ping settings' do context 'when the usage ping is disabled in gitlab.yml' do before do diff --git a/spec/support/shared_examples/chat_slash_commands_shared_examples.rb b/spec/support/shared_examples/chat_slash_commands_shared_examples.rb index dc97a39f051..82975027e5b 100644 --- a/spec/support/shared_examples/chat_slash_commands_shared_examples.rb +++ b/spec/support/shared_examples/chat_slash_commands_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + RSpec.shared_examples 'chat slash commands service' do describe "Associations" do it { is_expected.to respond_to :token } diff --git a/spec/support/shared_examples/ci_trace_shared_examples.rb b/spec/support/shared_examples/ci_trace_shared_examples.rb index 68c2b6e10e2..6fd4b14d51d 100644 --- a/spec/support/shared_examples/ci_trace_shared_examples.rb +++ b/spec/support/shared_examples/ci_trace_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples_for 'common trace features' do describe '#html' do before do diff --git a/spec/support/shared_examples/common_system_notes_examples.rb b/spec/support/shared_examples/common_system_notes_examples.rb index da5a4f3e319..75f93a32d78 100644 --- a/spec/support/shared_examples/common_system_notes_examples.rb +++ b/spec/support/shared_examples/common_system_notes_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples 'system note creation' do |update_params, note_text| subject { described_class.new(project, user).execute(issuable, old_labels: []) } diff --git a/spec/support/shared_examples/controllers/external_authorization_service_shared_examples.rb b/spec/support/shared_examples/controllers/external_authorization_service_shared_examples.rb index 8dd78fd0a25..2faa0cf8c1c 100644 --- a/spec/support/shared_examples/controllers/external_authorization_service_shared_examples.rb +++ b/spec/support/shared_examples/controllers/external_authorization_service_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' shared_examples 'disabled when using an external authorization service' do diff --git a/spec/support/shared_examples/controllers/issuable_notes_filter_shared_examples.rb b/spec/support/shared_examples/controllers/issuable_notes_filter_shared_examples.rb index f4b02dc5350..fb22498f84f 100644 --- a/spec/support/shared_examples/controllers/issuable_notes_filter_shared_examples.rb +++ b/spec/support/shared_examples/controllers/issuable_notes_filter_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples 'issuable notes filter' do let(:params) do if issuable_parent.is_a?(Project) diff --git a/spec/support/shared_examples/controllers/set_sort_order_from_user_preference_shared_examples.rb b/spec/support/shared_examples/controllers/set_sort_order_from_user_preference_shared_examples.rb index eb051166a69..1cd14ea2251 100644 --- a/spec/support/shared_examples/controllers/set_sort_order_from_user_preference_shared_examples.rb +++ b/spec/support/shared_examples/controllers/set_sort_order_from_user_preference_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples 'set sort order from user preference' do describe '#set_sort_order_from_user_preference' do # There is no issuable_sorting_field defined in any CE controllers yet, diff --git a/spec/support/shared_examples/controllers/todos_shared_examples.rb b/spec/support/shared_examples/controllers/todos_shared_examples.rb index bafd9bac8d0..f3f9abb7da2 100644 --- a/spec/support/shared_examples/controllers/todos_shared_examples.rb +++ b/spec/support/shared_examples/controllers/todos_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples 'todos actions' do context 'when authorized' do before do diff --git a/spec/support/shared_examples/controllers/uploads_actions_shared_examples.rb b/spec/support/shared_examples/controllers/uploads_actions_shared_examples.rb index 59708173716..39d13cccb13 100644 --- a/spec/support/shared_examples/controllers/uploads_actions_shared_examples.rb +++ b/spec/support/shared_examples/controllers/uploads_actions_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples 'handle uploads' do let(:user) { create(:user) } let(:jpg) { fixture_file_upload('spec/fixtures/rails_sample.jpg', 'image/jpg') } @@ -74,6 +76,16 @@ shared_examples 'handle uploads' do UploadService.new(model, jpg, uploader_class).execute end + context 'when accessing a specific upload via different model' do + it 'responds with status 404' do + params.merge!(other_params) + + show_upload + + expect(response).to have_gitlab_http_status(404) + end + end + context "when the model is public" do before do model.update_attribute(:visibility_level, Gitlab::VisibilityLevel::PUBLIC) diff --git a/spec/support/shared_examples/controllers/variables_shared_examples.rb b/spec/support/shared_examples/controllers/variables_shared_examples.rb index e80722857ec..78666e677ef 100644 --- a/spec/support/shared_examples/controllers/variables_shared_examples.rb +++ b/spec/support/shared_examples/controllers/variables_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples 'GET #show lists all variables' do it 'renders the variables as json' do subject diff --git a/spec/support/shared_examples/dirty_submit_form_shared_examples.rb b/spec/support/shared_examples/dirty_submit_form_shared_examples.rb index 4e45e2921e7..60c8899d349 100644 --- a/spec/support/shared_examples/dirty_submit_form_shared_examples.rb +++ b/spec/support/shared_examples/dirty_submit_form_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples 'dirty submit form' do |selector_args| selectors = selector_args.is_a?(Array) ? selector_args : [selector_args] diff --git a/spec/support/shared_examples/email_format_shared_examples.rb b/spec/support/shared_examples/email_format_shared_examples.rb index b924a208e71..22d6c2b38e3 100644 --- a/spec/support/shared_examples/email_format_shared_examples.rb +++ b/spec/support/shared_examples/email_format_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Specifications for behavior common to all objects with an email attribute. # Takes a list of email-format attributes and requires: # - subject { "the object with a attribute= setter" } diff --git a/spec/support/shared_examples/fast_destroy_all.rb b/spec/support/shared_examples/fast_destroy_all.rb index a8079b6d864..a64259c03f2 100644 --- a/spec/support/shared_examples/fast_destroy_all.rb +++ b/spec/support/shared_examples/fast_destroy_all.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples_for 'fast destroyable' do describe 'Forbid #destroy and #destroy_all' do it 'does not delete database rows and associted external data' do diff --git a/spec/support/shared_examples/features/comments_on_merge_request_files_shared_examples.rb b/spec/support/shared_examples/features/comments_on_merge_request_files_shared_examples.rb index 2b36955a3c4..f24e47f4638 100644 --- a/spec/support/shared_examples/features/comments_on_merge_request_files_shared_examples.rb +++ b/spec/support/shared_examples/features/comments_on_merge_request_files_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples 'comment on merge request file' do it 'adds a comment' do click_diff_line(find("[id='#{sample_commit.line_code}']")) diff --git a/spec/support/shared_examples/features/creatable_merge_request_shared_examples.rb b/spec/support/shared_examples/features/creatable_merge_request_shared_examples.rb index ec1b1754cf0..c0db4cdde72 100644 --- a/spec/support/shared_examples/features/creatable_merge_request_shared_examples.rb +++ b/spec/support/shared_examples/features/creatable_merge_request_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + RSpec.shared_examples 'a creatable merge request' do include WaitForRequests diff --git a/spec/support/shared_examples/features/editable_merge_request_shared_examples.rb b/spec/support/shared_examples/features/editable_merge_request_shared_examples.rb index a6121fcc50a..964c80007b0 100644 --- a/spec/support/shared_examples/features/editable_merge_request_shared_examples.rb +++ b/spec/support/shared_examples/features/editable_merge_request_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + RSpec.shared_examples 'an editable merge request' do it 'updates merge request', :js do find('.js-assignee-search').click diff --git a/spec/support/shared_examples/features/issuable_sidebar_shared_examples.rb b/spec/support/shared_examples/features/issuable_sidebar_shared_examples.rb index 96c821b26f7..09a48533ee3 100644 --- a/spec/support/shared_examples/features/issuable_sidebar_shared_examples.rb +++ b/spec/support/shared_examples/features/issuable_sidebar_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples 'issue sidebar stays collapsed on mobile' do before do resize_screen_xs diff --git a/spec/support/shared_examples/features/issuables_user_dropdown_behaviors_shared_examples.rb b/spec/support/shared_examples/features/issuables_user_dropdown_behaviors_shared_examples.rb index c92c7f603d6..63ed37cde03 100644 --- a/spec/support/shared_examples/features/issuables_user_dropdown_behaviors_shared_examples.rb +++ b/spec/support/shared_examples/features/issuables_user_dropdown_behaviors_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples 'issuable user dropdown behaviors' do include FilteredSearchHelpers diff --git a/spec/support/shared_examples/features/master_manages_access_requests_shared_example.rb b/spec/support/shared_examples/features/master_manages_access_requests_shared_example.rb index d87e5fcaa88..8e1d24c4be2 100644 --- a/spec/support/shared_examples/features/master_manages_access_requests_shared_example.rb +++ b/spec/support/shared_examples/features/master_manages_access_requests_shared_example.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + RSpec.shared_examples 'Maintainer manages access requests' do let(:user) { create(:user) } let(:maintainer) { create(:user) } diff --git a/spec/support/shared_examples/features/project_features_apply_to_issuables_shared_examples.rb b/spec/support/shared_examples/features/project_features_apply_to_issuables_shared_examples.rb index 64c3b80136d..51559c0b110 100644 --- a/spec/support/shared_examples/features/project_features_apply_to_issuables_shared_examples.rb +++ b/spec/support/shared_examples/features/project_features_apply_to_issuables_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples 'project features apply to issuables' do |klass| let(:described_class) { klass } diff --git a/spec/support/shared_examples/features/protected_branches_access_control_ce.rb b/spec/support/shared_examples/features/protected_branches_access_control_ce.rb index a8f2c2e7a5a..db83d6f0793 100644 --- a/spec/support/shared_examples/features/protected_branches_access_control_ce.rb +++ b/spec/support/shared_examples/features/protected_branches_access_control_ce.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples "protected branches > access control > CE" do ProtectedRefAccess::HUMAN_ACCESS_LEVELS.each do |(access_type_id, access_type_name)| it "allows creating protected branches that #{access_type_name} can push to" do @@ -6,7 +8,7 @@ shared_examples "protected branches > access control > CE" do set_protected_branch_name('master') find(".js-allowed-to-merge").click - within('.qa-allowed-to-merge-dropdown') do + within('.rspec-allowed-to-merge-dropdown') do expect(first("li")).to have_content("Roles") find(:link, 'No one').click end @@ -32,13 +34,13 @@ shared_examples "protected branches > access control > CE" do set_protected_branch_name('master') find(".js-allowed-to-merge").click - within('.qa-allowed-to-merge-dropdown') do + within('.rspec-allowed-to-merge-dropdown') do expect(first("li")).to have_content("Roles") find(:link, 'No one').click end find(".js-allowed-to-push").click - within('.qa-allowed-to-push-dropdown') do + within('.rspec-allowed-to-push-dropdown') do expect(first("li")).to have_content("Roles") find(:link, 'No one').click end @@ -78,7 +80,7 @@ shared_examples "protected branches > access control > CE" do end find(".js-allowed-to-push").click - within('.qa-allowed-to-push-dropdown') do + within('.rspec-allowed-to-push-dropdown') do expect(first("li")).to have_content("Roles") find(:link, 'No one').click end @@ -95,13 +97,13 @@ shared_examples "protected branches > access control > CE" do set_protected_branch_name('master') find(".js-allowed-to-merge").click - within('.qa-allowed-to-merge-dropdown') do + within('.rspec-allowed-to-merge-dropdown') do expect(first("li")).to have_content("Roles") find(:link, 'No one').click end find(".js-allowed-to-push").click - within('.qa-allowed-to-push-dropdown') do + within('.rspec-allowed-to-push-dropdown') do expect(first("li")).to have_content("Roles") find(:link, 'No one').click end diff --git a/spec/support/shared_examples/features/search_shared_examples.rb b/spec/support/shared_examples/features/search_shared_examples.rb index 25ebbf011d5..e27d6700cbf 100644 --- a/spec/support/shared_examples/features/search_shared_examples.rb +++ b/spec/support/shared_examples/features/search_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples 'top right search form' do it 'does not show top right search form' do expect(page).not_to have_selector('.search') diff --git a/spec/support/shared_examples/file_finder.rb b/spec/support/shared_examples/file_finder.rb index 0dc351b5149..984a06ccd1a 100644 --- a/spec/support/shared_examples/file_finder.rb +++ b/spec/support/shared_examples/file_finder.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples 'file finder' do let(:query) { 'files' } let(:search_results) { subject.find(query) } diff --git a/spec/support/shared_examples/finders/finder_with_external_authorization_enabled.rb b/spec/support/shared_examples/finders/finder_with_external_authorization_enabled.rb index d7e17cc0b70..b8b0079e36d 100644 --- a/spec/support/shared_examples/finders/finder_with_external_authorization_enabled.rb +++ b/spec/support/shared_examples/finders/finder_with_external_authorization_enabled.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' shared_examples 'a finder with external authorization service' do diff --git a/spec/support/shared_examples/gitlab_verify.rb b/spec/support/shared_examples/gitlab_verify.rb index 560913ca92f..721ea3b4c88 100644 --- a/spec/support/shared_examples/gitlab_verify.rb +++ b/spec/support/shared_examples/gitlab_verify.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + RSpec.shared_examples 'Gitlab::Verify::BatchVerifier subclass' do describe 'batching' do let(:first_batch) { objects[0].id..objects[0].id } diff --git a/spec/support/shared_examples/graphql/issuable_state_shared_examples.rb b/spec/support/shared_examples/graphql/issuable_state_shared_examples.rb index 713f0a879c1..145c476c7f7 100644 --- a/spec/support/shared_examples/graphql/issuable_state_shared_examples.rb +++ b/spec/support/shared_examples/graphql/issuable_state_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + RSpec.shared_examples 'issuable state' do it 'exposes all the existing issuable states' do expect(described_class.values.keys).to include(*%w[opened closed locked]) diff --git a/spec/support/shared_examples/group_members_shared_example.rb b/spec/support/shared_examples/group_members_shared_example.rb index 547c83c7955..4f7d496741d 100644 --- a/spec/support/shared_examples/group_members_shared_example.rb +++ b/spec/support/shared_examples/group_members_shared_example.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + RSpec.shared_examples 'members and requesters associations' do describe '#members_and_requesters' do it 'includes members and requesters' do diff --git a/spec/support/shared_examples/helm_generated_script.rb b/spec/support/shared_examples/helm_generated_script.rb index 01bee603274..17f495ebe46 100644 --- a/spec/support/shared_examples/helm_generated_script.rb +++ b/spec/support/shared_examples/helm_generated_script.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples 'helm commands' do describe '#generate_script' do let(:helm_setup) do diff --git a/spec/support/shared_examples/issuable_shared_examples.rb b/spec/support/shared_examples/issuable_shared_examples.rb index d97b21f71cd..3460a8ba297 100644 --- a/spec/support/shared_examples/issuable_shared_examples.rb +++ b/spec/support/shared_examples/issuable_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples 'cache counters invalidator' do it 'invalidates counter cache for assignees' do expect_any_instance_of(User).to receive(:invalidate_merge_request_cache_counts) diff --git a/spec/support/shared_examples/issuables_list_metadata_shared_examples.rb b/spec/support/shared_examples/issuables_list_metadata_shared_examples.rb index 244f4766a84..52d90b5f183 100644 --- a/spec/support/shared_examples/issuables_list_metadata_shared_examples.rb +++ b/spec/support/shared_examples/issuables_list_metadata_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples 'issuables list meta-data' do |issuable_type, action = nil| include ProjectForksHelper diff --git a/spec/support/shared_examples/issue_tracker_service_shared_example.rb b/spec/support/shared_examples/issue_tracker_service_shared_example.rb index a6ab03cb808..0a483fd30ba 100644 --- a/spec/support/shared_examples/issue_tracker_service_shared_example.rb +++ b/spec/support/shared_examples/issue_tracker_service_shared_example.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + RSpec.shared_examples 'issue tracker service URL attribute' do |url_attr| it { is_expected.to allow_value('https://example.com').for(url_attr) } diff --git a/spec/support/shared_examples/ldap_shared_examples.rb b/spec/support/shared_examples/ldap_shared_examples.rb index 52c34e78965..0a70ce7ea0c 100644 --- a/spec/support/shared_examples/ldap_shared_examples.rb +++ b/spec/support/shared_examples/ldap_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples_for 'normalizes a DN' do using RSpec::Parameterized::TableSyntax diff --git a/spec/support/shared_examples/legacy_path_redirect_shared_examples.rb b/spec/support/shared_examples/legacy_path_redirect_shared_examples.rb index f326e502092..22e5698825d 100644 --- a/spec/support/shared_examples/legacy_path_redirect_shared_examples.rb +++ b/spec/support/shared_examples/legacy_path_redirect_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples 'redirecting a legacy path' do |source, target| include RSpec::Rails::RequestExampleGroup diff --git a/spec/support/shared_examples/lib/gitlab/background_migration/backfill_project_repositories_examples.rb b/spec/support/shared_examples/lib/gitlab/background_migration/backfill_project_repositories_examples.rb index dcf7c1a90c2..2cbc0c2bdf2 100644 --- a/spec/support/shared_examples/lib/gitlab/background_migration/backfill_project_repositories_examples.rb +++ b/spec/support/shared_examples/lib/gitlab/background_migration/backfill_project_repositories_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples 'backfill migration for project repositories' do |storage| describe '#perform' do let(:storage_versions) { storage == :legacy ? [nil, 0] : [1, 2] } diff --git a/spec/support/shared_examples/lib/gitlab/usage_data_counters/a_redis_counter.rb b/spec/support/shared_examples/lib/gitlab/usage_data_counters/a_redis_counter.rb new file mode 100644 index 00000000000..91bf804978d --- /dev/null +++ b/spec/support/shared_examples/lib/gitlab/usage_data_counters/a_redis_counter.rb @@ -0,0 +1,57 @@ +# frozen_string_literal: true + +shared_examples 'a redis usage counter' do |thing, event| + describe ".count(#{event})", :clean_gitlab_redis_shared_state do + it "increments the #{thing} #{event} counter by 1" do + expect do + described_class.count(event) + end.to change { described_class.read(event) }.by 1 + end + end + + describe ".read(#{event})", :clean_gitlab_redis_shared_state do + event_count = 5 + + it "returns the total number of #{event} events" do + event_count.times do + described_class.count(event) + end + + expect(described_class.read(event)).to eq(event_count) + end + end +end + +shared_examples 'a redis usage counter with totals' do |prefix, events| + describe 'totals', :clean_gitlab_redis_shared_state do + before do + events.each do |k, n| + n.times do + described_class.count(k) + end + end + end + + let(:expected_totals) do + events.transform_keys { |k| "#{prefix}_#{k}".to_sym } + end + + it 'can report all totals' do + expect(described_class.totals).to include(expected_totals) + end + end + + # Override these let-bindings to adjust the unknown events tests + let(:unknown_event) { described_class::UnknownEvent } + let(:bad_event) { :wibble } + + describe 'unknown events' do + it 'cannot increment' do + expect { described_class.count(bad_event) }.to raise_error unknown_event + end + + it 'cannot read' do + expect { described_class.read(bad_event) }.to raise_error unknown_event + end + end +end diff --git a/spec/support/shared_examples/malicious_regexp_shared_examples.rb b/spec/support/shared_examples/malicious_regexp_shared_examples.rb index a86050e2cf2..96c02260d53 100644 --- a/spec/support/shared_examples/malicious_regexp_shared_examples.rb +++ b/spec/support/shared_examples/malicious_regexp_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'timeout' shared_examples 'malicious regexp' do diff --git a/spec/support/shared_examples/mentionable_shared_examples.rb b/spec/support/shared_examples/mentionable_shared_examples.rb index fea52c2eeb2..93a8c4709a6 100644 --- a/spec/support/shared_examples/mentionable_shared_examples.rb +++ b/spec/support/shared_examples/mentionable_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Specifications for behavior common to all Mentionable implementations. # Requires a shared context containing: # - subject { "the mentionable implementation" } diff --git a/spec/support/shared_examples/milestone_tabs_examples.rb b/spec/support/shared_examples/milestone_tabs_examples.rb index 8b757586941..bda4b978737 100644 --- a/spec/support/shared_examples/milestone_tabs_examples.rb +++ b/spec/support/shared_examples/milestone_tabs_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples 'milestone tabs' do def go(path, extra_params = {}) params = diff --git a/spec/support/shared_examples/models/atomic_internal_id_shared_examples.rb b/spec/support/shared_examples/models/atomic_internal_id_shared_examples.rb index a248f60d23e..b837ca87256 100644 --- a/spec/support/shared_examples/models/atomic_internal_id_shared_examples.rb +++ b/spec/support/shared_examples/models/atomic_internal_id_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' shared_examples_for 'AtomicInternalId' do |validate_presence: true| diff --git a/spec/support/shared_examples/models/chat_service_shared_examples.rb b/spec/support/shared_examples/models/chat_service_shared_examples.rb index 0a302e7d030..b6a3d50d14a 100644 --- a/spec/support/shared_examples/models/chat_service_shared_examples.rb +++ b/spec/support/shared_examples/models/chat_service_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "spec_helper" shared_examples_for "chat service" do |service_name| @@ -220,7 +222,8 @@ shared_examples_for "chat service" do |service_name| context "with not default branch" do let(:pipeline) do - create(:ci_pipeline, project: project, status: "failed", ref: "not-the-default-branch") + create(:ci_pipeline, :failed, project: project, + sha: project.commit.sha, ref: "not-the-default-branch") end context "when notify_only_default_branch enabled" do diff --git a/spec/support/shared_examples/models/cluster_application_core_shared_examples.rb b/spec/support/shared_examples/models/cluster_application_core_shared_examples.rb index d6490a808ce..8e58cc7ba22 100644 --- a/spec/support/shared_examples/models/cluster_application_core_shared_examples.rb +++ b/spec/support/shared_examples/models/cluster_application_core_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples 'cluster application core specs' do |application_name| it { is_expected.to belong_to(:cluster) } it { is_expected.to validate_presence_of(:cluster) } diff --git a/spec/support/shared_examples/models/cluster_application_helm_cert_examples.rb b/spec/support/shared_examples/models/cluster_application_helm_cert_examples.rb index bd3661471f8..7ddb3b11c85 100644 --- a/spec/support/shared_examples/models/cluster_application_helm_cert_examples.rb +++ b/spec/support/shared_examples/models/cluster_application_helm_cert_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples 'cluster application helm specs' do |application_name| let(:application) { create(application_name) } diff --git a/spec/support/shared_examples/models/cluster_application_status_shared_examples.rb b/spec/support/shared_examples/models/cluster_application_status_shared_examples.rb index 4525c03837f..5341aacb445 100644 --- a/spec/support/shared_examples/models/cluster_application_status_shared_examples.rb +++ b/spec/support/shared_examples/models/cluster_application_status_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples 'cluster application status specs' do |application_name| describe '#status' do let(:cluster) { create(:cluster, :provided_by_gcp) } diff --git a/spec/support/shared_examples/models/issuable_hook_data_shared_examples.rb b/spec/support/shared_examples/models/issuable_hook_data_shared_examples.rb index a4762b68858..7ea2bb265cc 100644 --- a/spec/support/shared_examples/models/issuable_hook_data_shared_examples.rb +++ b/spec/support/shared_examples/models/issuable_hook_data_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # This shared example requires a `builder` and `user` variable shared_examples 'issuable hook data' do |kind| let(:data) { builder.build(user: user) } diff --git a/spec/support/shared_examples/models/members_notifications_shared_example.rb b/spec/support/shared_examples/models/members_notifications_shared_example.rb index ef5cea3f2a5..050d710f1de 100644 --- a/spec/support/shared_examples/models/members_notifications_shared_example.rb +++ b/spec/support/shared_examples/models/members_notifications_shared_example.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + RSpec.shared_examples 'members notifications' do |entity_type| let(:notification_service) { double('NotificationService').as_null_object } diff --git a/spec/support/shared_examples/models/project_hook_data_shared_examples.rb b/spec/support/shared_examples/models/project_hook_data_shared_examples.rb index f0264878811..03d10c10e3c 100644 --- a/spec/support/shared_examples/models/project_hook_data_shared_examples.rb +++ b/spec/support/shared_examples/models/project_hook_data_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples 'project hook data with deprecateds' do |project_key: :project| it 'contains project data' do expect(data[project_key][:name]).to eq(project.name) diff --git a/spec/support/shared_examples/models/with_uploads_shared_examples.rb b/spec/support/shared_examples/models/with_uploads_shared_examples.rb index 43033a2d256..eb1ade03017 100644 --- a/spec/support/shared_examples/models/with_uploads_shared_examples.rb +++ b/spec/support/shared_examples/models/with_uploads_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' shared_examples_for 'model with uploads' do |supports_fileuploads| diff --git a/spec/support/shared_examples/notify_shared_examples.rb b/spec/support/shared_examples/notify_shared_examples.rb index 4452b1c82cb..ca031df000e 100644 --- a/spec/support/shared_examples/notify_shared_examples.rb +++ b/spec/support/shared_examples/notify_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_context 'gitlab email notification' do set(:group) { create(:group) } set(:subgroup) { create(:group, parent: group) } @@ -50,7 +52,7 @@ shared_examples 'an email sent to a user' do it 'is sent to user\'s group notification email' do group_notification_email = 'user+group@example.com' - create(:notification_setting, user: recipient, source: project.group, notification_email: group_notification_email) + create(:notification_setting, user: recipient, source: group, notification_email: group_notification_email) expect(subject).to deliver_to(group_notification_email) end diff --git a/spec/support/shared_examples/position_formatters.rb b/spec/support/shared_examples/position_formatters.rb index ffc9456dbc7..30b6b8d24f0 100644 --- a/spec/support/shared_examples/position_formatters.rb +++ b/spec/support/shared_examples/position_formatters.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples_for "position formatter" do let(:formatter) { described_class.new(attrs) } diff --git a/spec/support/shared_examples/project_latest_successful_build_for_examples.rb b/spec/support/shared_examples/project_latest_successful_build_for_examples.rb new file mode 100644 index 00000000000..a9bd23e9fc9 --- /dev/null +++ b/spec/support/shared_examples/project_latest_successful_build_for_examples.rb @@ -0,0 +1,63 @@ +# frozen_string_literal: true + +shared_examples 'latest successful build for sha or ref' do + context 'with many builds' do + let(:other_pipeline) { create_pipeline(project) } + let(:other_build) { create_build(other_pipeline, 'test') } + let(:build_name) { other_build.name } + + before do + pipeline1 = create_pipeline(project) + pipeline2 = create_pipeline(project) + create_build(pipeline1, 'test') + create_build(pipeline1, 'test2') + create_build(pipeline2, 'test2') + end + + it 'gives the latest builds from latest pipeline' do + expect(subject).to eq(other_build) + end + end + + context 'with succeeded pipeline' do + let!(:build) { create_build } + let(:build_name) { build.name } + + context 'standalone pipeline' do + it 'returns builds for ref for default_branch' do + expect(subject).to eq(build) + end + + context 'with nonexistent build' do + let(:build_name) { 'TAIL' } + + it 'returns empty relation if the build cannot be found' do + expect(subject).to be_nil + end + end + end + + context 'with some pending pipeline' do + before do + create_build(create_pipeline(project, 'pending')) + end + + it 'gives the latest build from latest pipeline' do + expect(subject).to eq(build) + end + end + end + + context 'with pending pipeline' do + let!(:pending_build) { create_build(pipeline) } + let(:build_name) { pending_build.name } + + before do + pipeline.update(status: 'pending') + end + + it 'returns empty relation' do + expect(subject).to be_nil + end + end +end diff --git a/spec/support/shared_examples/quick_actions/commit/tag_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/commit/tag_quick_action_shared_examples.rb index b337a1c18d8..f5a86e4dc2c 100644 --- a/spec/support/shared_examples/quick_actions/commit/tag_quick_action_shared_examples.rb +++ b/spec/support/shared_examples/quick_actions/commit/tag_quick_action_shared_examples.rb @@ -5,7 +5,7 @@ shared_examples 'tag quick action' do it 'tags this commit' do add_note("/tag #{tag_name} #{tag_message}") - expect(page).to have_content 'Commands applied' + expect(page).to have_content %{Tagged this commit to #{tag_name} with "#{tag_message}".} expect(page).to have_content "tagged commit #{truncated_commit_sha}" expect(page).to have_content tag_name diff --git a/spec/support/shared_examples/quick_actions/issuable/close_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/close_quick_action_shared_examples.rb index a79a61bc708..6e7eb78261a 100644 --- a/spec/support/shared_examples/quick_actions/issuable/close_quick_action_shared_examples.rb +++ b/spec/support/shared_examples/quick_actions/issuable/close_quick_action_shared_examples.rb @@ -68,7 +68,7 @@ shared_examples 'close quick action' do |issuable_type| it "does not close the #{issuable_type}" do add_note('/close') - expect(page).not_to have_content 'Commands applied' + expect(page).not_to have_content "Closed this #{issuable.to_ability_name.humanize(capitalize: false)}." expect(issuable).to be_open end end diff --git a/spec/support/shared_examples/quick_actions/issue/create_merge_request_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issue/create_merge_request_quick_action_shared_examples.rb index 34dba5dbc31..3e9ee9a633f 100644 --- a/spec/support/shared_examples/quick_actions/issue/create_merge_request_quick_action_shared_examples.rb +++ b/spec/support/shared_examples/quick_actions/issue/create_merge_request_quick_action_shared_examples.rb @@ -2,8 +2,14 @@ shared_examples 'create_merge_request quick action' do context 'create a merge request starting from an issue' do - def expect_mr_quickaction(success) - expect(page).to have_content 'Commands applied' + def expect_mr_quickaction(success, branch_name = nil) + command_message = if branch_name + "Created branch '#{branch_name}' and a merge request to resolve this issue" + else + "Created a branch and a merge request to resolve this issue" + end + + expect(page).to have_content command_message if success expect(page).to have_content 'created merge request' @@ -13,19 +19,21 @@ shared_examples 'create_merge_request quick action' do end it "doesn't create a merge request when the branch name is invalid" do - add_note("/create_merge_request invalid branch name") + branch_name = 'invalid branch name' + add_note("/create_merge_request #{branch_name}") wait_for_requests - expect_mr_quickaction(false) + expect_mr_quickaction(false, branch_name) end it "doesn't create a merge request when a branch with that name already exists" do - add_note("/create_merge_request feature") + branch_name = 'feature' + add_note("/create_merge_request #{branch_name}") wait_for_requests - expect_mr_quickaction(false) + expect_mr_quickaction(false, branch_name) end it 'creates a new merge request using issue iid and title as branch name when the branch name is empty' do @@ -46,7 +54,7 @@ shared_examples 'create_merge_request quick action' do branch_name = '1-feature' add_note("/create_merge_request #{branch_name}") - expect_mr_quickaction(true) + expect_mr_quickaction(true, branch_name) created_mr = project.merge_requests.last expect(created_mr.source_branch).to eq(branch_name) diff --git a/spec/support/shared_examples/quick_actions/issue/duplicate_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issue/duplicate_quick_action_shared_examples.rb index 633c7135fbc..3834b8b2b87 100644 --- a/spec/support/shared_examples/quick_actions/issue/duplicate_quick_action_shared_examples.rb +++ b/spec/support/shared_examples/quick_actions/issue/duplicate_quick_action_shared_examples.rb @@ -9,7 +9,6 @@ shared_examples 'duplicate quick action' do add_note("/duplicate ##{original_issue.to_reference}") expect(page).not_to have_content "/duplicate #{original_issue.to_reference}" - expect(page).to have_content 'Commands applied' expect(page).to have_content "marked this issue as a duplicate of #{original_issue.to_reference}" expect(issue.reload).to be_closed @@ -28,7 +27,6 @@ shared_examples 'duplicate quick action' do it 'does not create a note, and does not mark the issue as a duplicate' do add_note("/duplicate ##{original_issue.to_reference}") - expect(page).not_to have_content 'Commands applied' expect(page).not_to have_content "marked this issue as a duplicate of #{original_issue.to_reference}" expect(issue.reload).to be_open diff --git a/spec/support/shared_examples/quick_actions/issue/move_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issue/move_quick_action_shared_examples.rb index a0b0d888769..85682b4919d 100644 --- a/spec/support/shared_examples/quick_actions/issue/move_quick_action_shared_examples.rb +++ b/spec/support/shared_examples/quick_actions/issue/move_quick_action_shared_examples.rb @@ -12,7 +12,7 @@ shared_examples 'move quick action' do it 'moves the issue' do add_note("/move #{target_project.full_path}") - expect(page).to have_content 'Commands applied' + expect(page).to have_content "Moved this issue to #{target_project.full_path}." expect(issue.reload).to be_closed visit project_issue_path(target_project, issue) @@ -29,7 +29,7 @@ shared_examples 'move quick action' do wait_for_requests - expect(page).to have_content 'Commands applied' + expect(page).to have_content "Moved this issue to #{project_unauthorized.full_path}." expect(issue.reload).to be_open end end @@ -40,7 +40,7 @@ shared_examples 'move quick action' do wait_for_requests - expect(page).to have_content 'Commands applied' + expect(page).to have_content "Move this issue failed because target project doesn't exists" expect(issue.reload).to be_open end end @@ -56,7 +56,7 @@ shared_examples 'move quick action' do shared_examples 'applies the commands to issues in both projects, target and source' do it "applies quick actions" do - expect(page).to have_content 'Commands applied' + expect(page).to have_content "Moved this issue to #{target_project.full_path}." expect(issue.reload).to be_closed visit project_issue_path(target_project, issue) diff --git a/spec/support/shared_examples/quick_actions/merge_request/merge_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/merge_request/merge_quick_action_shared_examples.rb index c454ddc4bba..ac7c17915de 100644 --- a/spec/support/shared_examples/quick_actions/merge_request/merge_quick_action_shared_examples.rb +++ b/spec/support/shared_examples/quick_actions/merge_request/merge_quick_action_shared_examples.rb @@ -10,7 +10,7 @@ shared_examples 'merge quick action' do it 'merges the MR' do add_note("/merge") - expect(page).to have_content 'Commands applied' + expect(page).to have_content 'Scheduled to merge this merge request when the pipeline succeeds.' expect(merge_request.reload).to be_merged end diff --git a/spec/support/shared_examples/reference_parser_shared_examples.rb b/spec/support/shared_examples/reference_parser_shared_examples.rb index baf8bcc04b8..d903c0f10e0 100644 --- a/spec/support/shared_examples/reference_parser_shared_examples.rb +++ b/spec/support/shared_examples/reference_parser_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + RSpec.shared_examples "referenced feature visibility" do |*related_features| let(:feature_fields) do related_features.map { |feature| (feature + "_access_level").to_sym } diff --git a/spec/support/shared_examples/relative_positioning_shared_examples.rb b/spec/support/shared_examples/relative_positioning_shared_examples.rb new file mode 100644 index 00000000000..5ee62644c54 --- /dev/null +++ b/spec/support/shared_examples/relative_positioning_shared_examples.rb @@ -0,0 +1,253 @@ +# frozen_string_literal: true + +RSpec.shared_examples "a class that supports relative positioning" do + let(:item1) { create(factory, default_params) } + let(:item2) { create(factory, default_params) } + let(:new_item) { create(factory, default_params) } + + def create_item(params) + create(factory, params.merge(default_params)) + end + + describe '.move_to_end' do + it 'moves the object to the end' do + item1.update(relative_position: 5) + item2.update(relative_position: 15) + + described_class.move_to_end([item1, item2]) + + expect(item2.prev_relative_position).to eq item1.relative_position + expect(item1.prev_relative_position).to eq nil + expect(item2.next_relative_position).to eq nil + end + + it 'does not perform any moves if all items have their relative_position set' do + item1.update!(relative_position: 1) + + expect(item1).not_to receive(:save) + + described_class.move_to_end([item1]) + end + end + + describe '#max_relative_position' do + it 'returns maximum position' do + expect(item1.max_relative_position).to eq item2.relative_position + end + end + + describe '#prev_relative_position' do + it 'returns previous position if there is an item above' do + item1.update(relative_position: 5) + item2.update(relative_position: 15) + + expect(item2.prev_relative_position).to eq item1.relative_position + end + + it 'returns nil if there is no item above' do + expect(item1.prev_relative_position).to eq nil + end + end + + describe '#next_relative_position' do + it 'returns next position if there is an item below' do + item1.update(relative_position: 5) + item2.update(relative_position: 15) + + expect(item1.next_relative_position).to eq item2.relative_position + end + + it 'returns nil if there is no item below' do + expect(item2.next_relative_position).to eq nil + end + end + + describe '#move_before' do + it 'moves item before' do + [item2, item1].each(&:move_to_end) + + item1.move_before(item2) + + expect(item1.relative_position).to be < item2.relative_position + end + end + + describe '#move_after' do + it 'moves item after' do + [item1, item2].each(&:move_to_end) + + item1.move_after(item2) + + expect(item1.relative_position).to be > item2.relative_position + end + end + + describe '#move_to_end' do + before do + [item1, item2].each do |item1| + item1.move_to_end && item1.save + end + end + + it 'moves item to the end' do + new_item.move_to_end + + expect(new_item.relative_position).to be > item2.relative_position + end + end + + describe '#shift_after?' do + before do + [item1, item2].each do |item1| + item1.move_to_end && item1.save + end + end + + it 'returns true' do + item1.update(relative_position: item2.relative_position - 1) + + expect(item1.shift_after?).to be_truthy + end + + it 'returns false' do + item1.update(relative_position: item2.relative_position - 2) + + expect(item1.shift_after?).to be_falsey + end + end + + describe '#shift_before?' do + before do + [item1, item2].each do |item1| + item1.move_to_end && item1.save + end + end + + it 'returns true' do + item1.update(relative_position: item2.relative_position + 1) + + expect(item1.shift_before?).to be_truthy + end + + it 'returns false' do + item1.update(relative_position: item2.relative_position + 2) + + expect(item1.shift_before?).to be_falsey + end + end + + describe '#move_between' do + before do + [item1, item2].each do |item1| + item1.move_to_end && item1.save + end + end + + it 'positions item between two other' do + new_item.move_between(item1, item2) + + expect(new_item.relative_position).to be > item1.relative_position + expect(new_item.relative_position).to be < item2.relative_position + end + + it 'positions item between on top' do + new_item.move_between(nil, item1) + + expect(new_item.relative_position).to be < item1.relative_position + end + + it 'positions item between to end' do + new_item.move_between(item2, nil) + + expect(new_item.relative_position).to be > item2.relative_position + end + + it 'positions items even when after and before positions are the same' do + item2.update relative_position: item1.relative_position + + new_item.move_between(item1, item2) + + expect(new_item.relative_position).to be > item1.relative_position + expect(item1.relative_position).to be < item2.relative_position + end + + it 'positions items between other two if distance is 1' do + item2.update relative_position: item1.relative_position + 1 + + new_item.move_between(item1, item2) + + expect(new_item.relative_position).to be > item1.relative_position + expect(item1.relative_position).to be < item2.relative_position + end + + it 'positions item in the middle of other two if distance is big enough' do + item1.update relative_position: 6000 + item2.update relative_position: 10000 + + new_item.move_between(item1, item2) + + expect(new_item.relative_position).to eq(8000) + end + + it 'positions item closer to the middle if we are at the very top' do + item2.update relative_position: 6000 + + new_item.move_between(nil, item2) + + expect(new_item.relative_position).to eq(6000 - RelativePositioning::IDEAL_DISTANCE) + end + + it 'positions item closer to the middle if we are at the very bottom' do + new_item.update relative_position: 1 + item1.update relative_position: 6000 + item2.destroy + + new_item.move_between(item1, nil) + + expect(new_item.relative_position).to eq(6000 + RelativePositioning::IDEAL_DISTANCE) + end + + it 'positions item in the middle of other two if distance is not big enough' do + item1.update relative_position: 100 + item2.update relative_position: 400 + + new_item.move_between(item1, item2) + + expect(new_item.relative_position).to eq(250) + end + + it 'positions item in the middle of other two is there is no place' do + item1.update relative_position: 100 + item2.update relative_position: 101 + + new_item.move_between(item1, item2) + + expect(new_item.relative_position).to be_between(item1.relative_position, item2.relative_position) + end + + it 'uses rebalancing if there is no place' do + item1.update relative_position: 100 + item2.update relative_position: 101 + item3 = create_item(relative_position: 102) + new_item.update relative_position: 103 + + new_item.move_between(item2, item3) + new_item.save! + + expect(new_item.relative_position).to be_between(item2.relative_position, item3.relative_position) + expect(item1.reload.relative_position).not_to eq(100) + end + + it 'positions item right if we pass none-sequential parameters' do + item1.update relative_position: 99 + item2.update relative_position: 101 + item3 = create_item(relative_position: 102) + new_item.update relative_position: 103 + + new_item.move_between(item1, item3) + new_item.save! + + expect(new_item.relative_position).to be(100) + end + end +end diff --git a/spec/support/shared_examples/requests/api/custom_attributes_shared_examples.rb b/spec/support/shared_examples/requests/api/custom_attributes_shared_examples.rb index 8a7fcf856a1..776a0bdd29e 100644 --- a/spec/support/shared_examples/requests/api/custom_attributes_shared_examples.rb +++ b/spec/support/shared_examples/requests/api/custom_attributes_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples 'custom attributes endpoints' do |attributable_name| let!(:custom_attribute1) { attributable.custom_attributes.create key: 'foo', value: 'foo' } let!(:custom_attribute2) { attributable.custom_attributes.create key: 'bar', value: 'bar' } diff --git a/spec/support/shared_examples/requests/api/diff_discussions.rb b/spec/support/shared_examples/requests/api/diff_discussions.rb index 366c2955359..76c6c93964a 100644 --- a/spec/support/shared_examples/requests/api/diff_discussions.rb +++ b/spec/support/shared_examples/requests/api/diff_discussions.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples 'diff discussions API' do |parent_type, noteable_type, id_name| describe "GET /#{parent_type}/:id/#{noteable_type}/:noteable_id/discussions" do it "includes diff discussions" do diff --git a/spec/support/shared_examples/requests/api/discussions.rb b/spec/support/shared_examples/requests/api/discussions.rb index c3132c41f5b..fc72287f265 100644 --- a/spec/support/shared_examples/requests/api/discussions.rb +++ b/spec/support/shared_examples/requests/api/discussions.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples 'discussions API' do |parent_type, noteable_type, id_name, can_reply_to_individual_notes: false| describe "GET /#{parent_type}/:id/#{noteable_type}/:noteable_id/discussions" do it "returns an array of discussions" do diff --git a/spec/support/shared_examples/requests/api/issuable_participants_examples.rb b/spec/support/shared_examples/requests/api/issuable_participants_examples.rb index 96d59e0c472..9fe6288d53f 100644 --- a/spec/support/shared_examples/requests/api/issuable_participants_examples.rb +++ b/spec/support/shared_examples/requests/api/issuable_participants_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples 'issuable participants endpoint' do let(:area) { entity.class.name.underscore.pluralize } diff --git a/spec/support/shared_examples/requests/api/issues/merge_requests_count_shared_examples.rb b/spec/support/shared_examples/requests/api/issues/merge_requests_count_shared_examples.rb index 5f4e178f2e5..90c1ed8d09b 100644 --- a/spec/support/shared_examples/requests/api/issues/merge_requests_count_shared_examples.rb +++ b/spec/support/shared_examples/requests/api/issues/merge_requests_count_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + def get_issue json_response.is_a?(Array) ? json_response.detect {|issue| issue['id'] == target_issue.id} : json_response end diff --git a/spec/support/shared_examples/requests/api/notes.rb b/spec/support/shared_examples/requests/api/notes.rb index 57eefd5ef01..354ae7288b1 100644 --- a/spec/support/shared_examples/requests/api/notes.rb +++ b/spec/support/shared_examples/requests/api/notes.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples 'noteable API' do |parent_type, noteable_type, id_name| describe "GET /#{parent_type}/:id/#{noteable_type}/:noteable_id/notes" do context 'sorting' do diff --git a/spec/support/shared_examples/requests/api/resolvable_discussions.rb b/spec/support/shared_examples/requests/api/resolvable_discussions.rb index 7e2416b23f3..42054a273f3 100644 --- a/spec/support/shared_examples/requests/api/resolvable_discussions.rb +++ b/spec/support/shared_examples/requests/api/resolvable_discussions.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples 'resolvable discussions API' do |parent_type, noteable_type, id_name| describe "PUT /#{parent_type}/:id/#{noteable_type}/:noteable_id/discussions/:discussion_id" do it "resolves discussion if resolved is true" do diff --git a/spec/support/shared_examples/requests/api/status_shared_examples.rb b/spec/support/shared_examples/requests/api/status_shared_examples.rb index ebfc5fed3bb..eebed7e42c1 100644 --- a/spec/support/shared_examples/requests/api/status_shared_examples.rb +++ b/spec/support/shared_examples/requests/api/status_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Specs for status checking. # # Requires an API request: diff --git a/spec/support/shared_examples/requests/graphql_shared_examples.rb b/spec/support/shared_examples/requests/graphql_shared_examples.rb index 04140cad3f0..2a38d56141a 100644 --- a/spec/support/shared_examples/requests/graphql_shared_examples.rb +++ b/spec/support/shared_examples/requests/graphql_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' shared_examples 'a working graphql query' do diff --git a/spec/support/shared_examples/resource_label_events_api.rb b/spec/support/shared_examples/resource_label_events_api.rb new file mode 100644 index 00000000000..945cb8d9f2c --- /dev/null +++ b/spec/support/shared_examples/resource_label_events_api.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +shared_examples 'resource_label_events API' do |parent_type, eventable_type, id_name| + describe "GET /#{parent_type}/:id/#{eventable_type}/:noteable_id/resource_label_events" do + it "returns an array of resource label events" do + get api("/#{parent_type}/#{parent.id}/#{eventable_type}/#{eventable[id_name]}/resource_label_events", user) + + expect(response).to have_gitlab_http_status(200) + expect(response).to include_pagination_headers + expect(json_response).to be_an Array + expect(json_response.first['id']).to eq(event.id) + end + + it "returns a 404 error when eventable id not found" do + get api("/#{parent_type}/#{parent.id}/#{eventable_type}/12345/resource_label_events", user) + + expect(response).to have_gitlab_http_status(404) + end + + it "returns 404 when not authorized" do + parent.update!(visibility_level: Gitlab::VisibilityLevel::PRIVATE) + private_user = create(:user) + + get api("/#{parent_type}/#{parent.id}/#{eventable_type}/#{eventable[id_name]}/resource_label_events", private_user) + + expect(response).to have_gitlab_http_status(404) + end + end + + describe "GET /#{parent_type}/:id/#{eventable_type}/:noteable_id/resource_label_events/:event_id" do + it "returns a resource label event by id" do + get api("/#{parent_type}/#{parent.id}/#{eventable_type}/#{eventable[id_name]}/resource_label_events/#{event.id}", user) + + expect(response).to have_gitlab_http_status(200) + expect(json_response['id']).to eq(event.id) + end + + it "returns a 404 error if resource label event not found" do + get api("/#{parent_type}/#{parent.id}/#{eventable_type}/#{eventable[id_name]}/resource_label_events/12345", user) + + expect(response).to have_gitlab_http_status(404) + end + end +end diff --git a/spec/support/shared_examples/serializers/note_entity_examples.rb b/spec/support/shared_examples/serializers/note_entity_examples.rb index ec208aba2a9..bfcaa2f1bd5 100644 --- a/spec/support/shared_examples/serializers/note_entity_examples.rb +++ b/spec/support/shared_examples/serializers/note_entity_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples 'note entity' do subject { entity.as_json } diff --git a/spec/support/shared_examples/services/boards/boards_create_service.rb b/spec/support/shared_examples/services/boards/boards_create_service.rb index 5bdc04f660f..19818a6091b 100644 --- a/spec/support/shared_examples/services/boards/boards_create_service.rb +++ b/spec/support/shared_examples/services/boards/boards_create_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples 'boards create service' do context 'when parent does not have a board' do it 'creates a new board' do diff --git a/spec/support/shared_examples/services/boards/boards_list_service.rb b/spec/support/shared_examples/services/boards/boards_list_service.rb index e0d5a7c61f2..566e5050f8e 100644 --- a/spec/support/shared_examples/services/boards/boards_list_service.rb +++ b/spec/support/shared_examples/services/boards/boards_list_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples 'boards list service' do context 'when parent does not have a board' do it 'creates a new parent board' do diff --git a/spec/support/shared_examples/services/boards/issues_list_service.rb b/spec/support/shared_examples/services/boards/issues_list_service.rb index 8b879cef084..75733c774ef 100644 --- a/spec/support/shared_examples/services/boards/issues_list_service.rb +++ b/spec/support/shared_examples/services/boards/issues_list_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples 'issues list service' do it 'delegates search to IssuesFinder' do params = { board_id: board.id, id: list1.id } diff --git a/spec/support/shared_examples/services/boards/issues_move_service.rb b/spec/support/shared_examples/services/boards/issues_move_service.rb index 5359831f8f8..d3fa8084185 100644 --- a/spec/support/shared_examples/services/boards/issues_move_service.rb +++ b/spec/support/shared_examples/services/boards/issues_move_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples 'issues move service' do |group| shared_examples 'updating timestamps' do it 'updates updated_at' do diff --git a/spec/support/shared_examples/services/boards/lists_destroy_service.rb b/spec/support/shared_examples/services/boards/lists_destroy_service.rb index 62b6ffe1836..95725078f9d 100644 --- a/spec/support/shared_examples/services/boards/lists_destroy_service.rb +++ b/spec/support/shared_examples/services/boards/lists_destroy_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples 'lists destroy service' do context 'when list type is label' do it 'removes list from board' do diff --git a/spec/support/shared_examples/services/boards/lists_list_service.rb b/spec/support/shared_examples/services/boards/lists_list_service.rb index 0a8220111ab..29784f6da08 100644 --- a/spec/support/shared_examples/services/boards/lists_list_service.rb +++ b/spec/support/shared_examples/services/boards/lists_list_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples 'lists list service' do context 'when the board has a backlog list' do let!(:backlog_list) { create(:backlog_list, board: board) } diff --git a/spec/support/shared_examples/services/boards/lists_move_service.rb b/spec/support/shared_examples/services/boards/lists_move_service.rb index 2cdb968a45d..0b3bfd8e2a8 100644 --- a/spec/support/shared_examples/services/boards/lists_move_service.rb +++ b/spec/support/shared_examples/services/boards/lists_move_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples 'lists move service' do let!(:planning) { create(:list, board: board, position: 0) } let!(:development) { create(:list, board: board, position: 1) } diff --git a/spec/support/shared_examples/services/check_ingress_ip_address_service_shared_examples.rb b/spec/support/shared_examples/services/check_ingress_ip_address_service_shared_examples.rb index 02de47a96dd..1e0ac8b7615 100644 --- a/spec/support/shared_examples/services/check_ingress_ip_address_service_shared_examples.rb +++ b/spec/support/shared_examples/services/check_ingress_ip_address_service_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples 'check ingress ip executions' do |app_name| describe '#execute' do let(:application) { create(app_name, :installed) } diff --git a/spec/support/shared_examples/services/gitlab_projects_import_service_shared_examples.rb b/spec/support/shared_examples/services/gitlab_projects_import_service_shared_examples.rb index b8db35a6ef9..1c3fa5644d3 100644 --- a/spec/support/shared_examples/services/gitlab_projects_import_service_shared_examples.rb +++ b/spec/support/shared_examples/services/gitlab_projects_import_service_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples 'gitlab projects import validations' do context 'with an invalid path' do let(:path) { '/invalid-path/' } diff --git a/spec/support/shared_examples/slack_mattermost_notifications_shared_examples.rb b/spec/support/shared_examples/slack_mattermost_notifications_shared_examples.rb index 36c486dbdd6..8ce94064dc3 100644 --- a/spec/support/shared_examples/slack_mattermost_notifications_shared_examples.rb +++ b/spec/support/shared_examples/slack_mattermost_notifications_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + Dir[Rails.root.join("app/models/project_services/chat_message/*.rb")].each { |f| require f } RSpec.shared_examples 'slack or mattermost notifications' do @@ -452,7 +454,7 @@ RSpec.shared_examples 'slack or mattermost notifications' do context 'only notify for the default branch' do context 'when enabled' do let(:pipeline) do - create(:ci_pipeline, :failed, project: project, ref: 'not-the-default-branch') + create(:ci_pipeline, :failed, project: project, sha: project.commit.sha, ref: 'not-the-default-branch') end before do @@ -470,7 +472,7 @@ RSpec.shared_examples 'slack or mattermost notifications' do context 'when disabled' do let(:pipeline) do - create(:ci_pipeline, :failed, project: project, ref: 'not-the-default-branch') + create(:ci_pipeline, :failed, project: project, sha: project.commit.sha, ref: 'not-the-default-branch') end before do diff --git a/spec/support/shared_examples/snippet_visibility_shared_examples.rb b/spec/support/shared_examples/snippet_visibility_shared_examples.rb index 833c31a57cb..b5321c6db34 100644 --- a/spec/support/shared_examples/snippet_visibility_shared_examples.rb +++ b/spec/support/shared_examples/snippet_visibility_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + RSpec.shared_examples 'snippet visibility' do using RSpec::Parameterized::TableSyntax diff --git a/spec/support/shared_examples/snippets_shared_examples.rb b/spec/support/shared_examples/snippets_shared_examples.rb index 85f0facd5c3..5c35617bd36 100644 --- a/spec/support/shared_examples/snippets_shared_examples.rb +++ b/spec/support/shared_examples/snippets_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # These shared examples expect a `snippets` array of snippets RSpec.shared_examples 'paginated snippets' do |remote: false| it "is limited to #{Snippet.default_per_page} items per page" do diff --git a/spec/support/shared_examples/taskable_shared_examples.rb b/spec/support/shared_examples/taskable_shared_examples.rb index 4a1df1ce380..f04f509f3d2 100644 --- a/spec/support/shared_examples/taskable_shared_examples.rb +++ b/spec/support/shared_examples/taskable_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Specs for task state functionality for issues and merge requests. # # Requires a context containing: diff --git a/spec/support/shared_examples/throttled_touch.rb b/spec/support/shared_examples/throttled_touch.rb index eba990d4037..aaaa590862d 100644 --- a/spec/support/shared_examples/throttled_touch.rb +++ b/spec/support/shared_examples/throttled_touch.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples_for 'throttled touch' do describe '#touch' do it 'updates the updated_at timestamp' do diff --git a/spec/support/shared_examples/unique_ip_check_shared_examples.rb b/spec/support/shared_examples/unique_ip_check_shared_examples.rb index e5c8ac6a004..65d86ddee9e 100644 --- a/spec/support/shared_examples/unique_ip_check_shared_examples.rb +++ b/spec/support/shared_examples/unique_ip_check_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_context 'unique ips sign in limit' do include StubENV before do diff --git a/spec/support/shared_examples/update_invalid_issuable.rb b/spec/support/shared_examples/update_invalid_issuable.rb index 4cb6d001b9b..b7ac08372f9 100644 --- a/spec/support/shared_examples/update_invalid_issuable.rb +++ b/spec/support/shared_examples/update_invalid_issuable.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples 'update invalid issuable' do |klass| let(:params) do { diff --git a/spec/support/shared_examples/updating_mentions_shared_examples.rb b/spec/support/shared_examples/updating_mentions_shared_examples.rb index 5e3f19ba19e..ef385f94cc2 100644 --- a/spec/support/shared_examples/updating_mentions_shared_examples.rb +++ b/spec/support/shared_examples/updating_mentions_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + RSpec.shared_examples 'updating mentions' do |service_class| let(:mentioned_user) { create(:user) } let(:service_class) { service_class } diff --git a/spec/support/shared_examples/uploaders/gitlab_uploader_shared_examples.rb b/spec/support/shared_examples/uploaders/gitlab_uploader_shared_examples.rb index 1190863d88e..9263aaff89a 100644 --- a/spec/support/shared_examples/uploaders/gitlab_uploader_shared_examples.rb +++ b/spec/support/shared_examples/uploaders/gitlab_uploader_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_examples "matches the method pattern" do |method| let(:target) { subject } let(:args) { nil } diff --git a/spec/support/shared_examples/uploaders/object_storage_shared_examples.rb b/spec/support/shared_examples/uploaders/object_storage_shared_examples.rb index 1bd176280c5..5d605dd811b 100644 --- a/spec/support/shared_examples/uploaders/object_storage_shared_examples.rb +++ b/spec/support/shared_examples/uploaders/object_storage_shared_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + shared_context 'with storage' do |store, **stub_params| before do subject.object_store = store diff --git a/spec/support/shared_examples/url_validator_examples.rb b/spec/support/shared_examples/url_validator_examples.rb index 25277ccd9aa..16fceddb605 100644 --- a/spec/support/shared_examples/url_validator_examples.rb +++ b/spec/support/shared_examples/url_validator_examples.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + RSpec.shared_examples 'url validator examples' do |schemes| let(:validator) { described_class.new(attributes: [:link_url], **options) } let!(:badge) { build(:badge, link_url: 'http://www.example.com') } diff --git a/spec/support/sidekiq.rb b/spec/support/sidekiq.rb index d1a765f27b9..585c458a64e 100644 --- a/spec/support/sidekiq.rb +++ b/spec/support/sidekiq.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'sidekiq/testing/inline' # If Sidekiq::Testing.inline! is used, SQL transactions done inside diff --git a/spec/support/stored_repositories.rb b/spec/support/stored_repositories.rb index 55212355daa..95f0f971787 100644 --- a/spec/support/stored_repositories.rb +++ b/spec/support/stored_repositories.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + RSpec.configure do |config| config.before(:each, :broken_storage) do allow(Gitlab::GitalyClient).to receive(:call) do diff --git a/spec/support/test_reports/test_reports_helper.rb b/spec/support/test_reports/test_reports_helper.rb index 6840fb9a860..6ba50c83b25 100644 --- a/spec/support/test_reports/test_reports_helper.rb +++ b/spec/support/test_reports/test_reports_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module TestReportsHelper def create_test_case_rspec_success(name = 'test_spec') Gitlab::Ci::Reports::TestCase.new( diff --git a/spec/support/trace/trace_helpers.rb b/spec/support/trace/trace_helpers.rb index c7802bbcb94..9255715ff71 100644 --- a/spec/support/trace/trace_helpers.rb +++ b/spec/support/trace/trace_helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module TraceHelpers def create_legacy_trace(build, content) File.open(legacy_trace_path(build), 'wb') { |stream| stream.write(content) } diff --git a/spec/support/webmock.rb b/spec/support/webmock.rb index 9ac7e7fc515..32b88edc2df 100644 --- a/spec/support/webmock.rb +++ b/spec/support/webmock.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'webmock' require 'webmock/rspec' diff --git a/spec/tasks/gitlab/update_templates_rake_spec.rb b/spec/tasks/gitlab/update_templates_rake_spec.rb new file mode 100644 index 00000000000..7b17549b8c7 --- /dev/null +++ b/spec/tasks/gitlab/update_templates_rake_spec.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +require 'rake_helper' + +describe 'gitlab:update_project_templates rake task' do + let!(:tmpdir) { Dir.mktmpdir } + + before do + Rake.application.rake_require 'tasks/gitlab/update_templates' + create(:admin) + allow(Gitlab::ProjectTemplate) + .to receive(:archive_directory) + .and_return(Pathname.new(tmpdir)) + end + + after do + FileUtils.rm_rf(tmpdir) + end + + it 'updates valid project templates' do + expect { run_rake_task('gitlab:update_project_templates', ['rails']) } + .to change { Dir.entries(tmpdir) } + .by(['rails.tar.gz']) + end +end diff --git a/spec/uploaders/records_uploads_spec.rb b/spec/uploaders/records_uploads_spec.rb index 42352f9b9f8..6134137d2b7 100644 --- a/spec/uploaders/records_uploads_spec.rb +++ b/spec/uploaders/records_uploads_spec.rb @@ -85,6 +85,27 @@ describe RecordsUploads do expect { existing.reload }.to raise_error(ActiveRecord::RecordNotFound) expect(Upload.count).to eq(1) end + + it 'does not affect other uploads with different model but the same path' do + project = create(:project) + other_project = create(:project) + + uploader = RecordsUploadsExampleUploader.new(other_project) + + upload_for_project = Upload.create!( + path: File.join('uploads', 'rails_sample.jpg'), + size: 512.kilobytes, + model: project, + uploader: uploader.class.to_s + ) + + uploader.store!(upload_fixture('rails_sample.jpg')) + + upload_for_project_fresh = Upload.find(upload_for_project.id) + + expect(upload_for_project).to eq(upload_for_project_fresh) + expect(Upload.count).to eq(2) + end end describe '#destroy_upload callback' do diff --git a/spec/views/groups/edit.html.haml_spec.rb b/spec/views/groups/edit.html.haml_spec.rb index 29e15960fb8..47804411b9d 100644 --- a/spec/views/groups/edit.html.haml_spec.rb +++ b/spec/views/groups/edit.html.haml_spec.rb @@ -35,7 +35,7 @@ describe 'groups/edit.html.haml' do it_behaves_like '"Share with group lock" setting', { disabled: false, checked: false } end - context 'for a subgroup', :nested_groups do + context 'for a subgroup' do let!(:subgroup) { create(:group, parent: root_group) } let(:sub_owner) { create(:user) } let(:test_group) { subgroup } diff --git a/spec/views/layouts/header/_new_dropdown.haml_spec.rb b/spec/views/layouts/header/_new_dropdown.haml_spec.rb index 2e19d0cec26..26e429ac5d0 100644 --- a/spec/views/layouts/header/_new_dropdown.haml_spec.rb +++ b/spec/views/layouts/header/_new_dropdown.haml_spec.rb @@ -28,7 +28,7 @@ describe 'layouts/header/_new_dropdown' do ) end - it 'has a "New subgroup" link', :nested_groups do + it 'has a "New subgroup" link' do render expect(rendered).to have_link( diff --git a/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb b/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb index 2befbcb3370..b627b9dba59 100644 --- a/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb +++ b/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb @@ -21,7 +21,7 @@ describe 'layouts/nav/sidebar/_project' do end end - describe 'container registry tab' do + describe 'packages tab' do before do stub_container_registry_config(enabled: true) @@ -31,24 +31,17 @@ describe 'layouts/nav/sidebar/_project' do .and_return('projects/registry/repositories') end - it 'has both Registry and Repository tabs' do - render - - expect(rendered).to have_text 'Repository' - expect(rendered).to have_text 'Registry' - end - it 'highlights sidebar item and flyout' do render expect(rendered).to have_css('.sidebar-top-level-items > li.active', count: 1) - expect(rendered).to have_css('.is-fly-out-only > li.active', count: 1) + expect(rendered).to have_css('.sidebar-sub-level-items > li.fly-out-top-item.active', count: 1) end it 'highlights container registry tab' do render - expect(rendered).to have_css('.sidebar-top-level-items > li.active', text: 'Registry') + expect(rendered).to have_css('.sidebar-sub-level-items > li:not(.fly-out-top-item).active', text: 'Container Registry') end end diff --git a/spec/views/projects/merge_requests/creations/_new_submit.html.haml_spec.rb b/spec/views/projects/merge_requests/creations/_new_submit.html.haml_spec.rb index 0206928a211..88c4b52b3a6 100644 --- a/spec/views/projects/merge_requests/creations/_new_submit.html.haml_spec.rb +++ b/spec/views/projects/merge_requests/creations/_new_submit.html.haml_spec.rb @@ -12,6 +12,7 @@ describe 'projects/merge_requests/creations/_new_submit.html.haml' do assign(:hidden_commit_count, 0) assign(:total_commit_count, merge_request.commits.count) assign(:project, merge_request.target_project) + assign(:target_project, merge_request.target_project) assign(:mr_presenter, merge_request.present(current_user: merge_request.author)) allow(view).to receive(:can?).and_return(true) diff --git a/spec/views/projects/merge_requests/edit.html.haml_spec.rb b/spec/views/projects/merge_requests/edit.html.haml_spec.rb index 529afa03f9c..0a3a46210ed 100644 --- a/spec/views/projects/merge_requests/edit.html.haml_spec.rb +++ b/spec/views/projects/merge_requests/edit.html.haml_spec.rb @@ -23,6 +23,7 @@ describe 'projects/merge_requests/edit.html.haml' do before do assign(:project, project) + assign(:target_project, project) assign(:merge_request, closed_merge_request) assign(:mr_presenter, closed_merge_request.present(current_user: user)) diff --git a/spec/workers/cluster_configure_worker_spec.rb b/spec/workers/cluster_configure_worker_spec.rb deleted file mode 100644 index 975088f3ee6..00000000000 --- a/spec/workers/cluster_configure_worker_spec.rb +++ /dev/null @@ -1,71 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -describe ClusterConfigureWorker, '#perform' do - let(:worker) { described_class.new } - - shared_examples 'configured cluster' do - it 'creates a namespace' do - expect(Clusters::RefreshService).to receive(:create_or_update_namespaces_for_cluster).with(cluster).once - - worker.perform(cluster.id) - end - end - - shared_examples 'unconfigured cluster' do - it 'does not create a namespace' do - expect(Clusters::RefreshService).not_to receive(:create_or_update_namespaces_for_cluster) - - worker.perform(cluster.id) - end - end - - context 'group cluster' do - let(:cluster) { create(:cluster, :group, :provided_by_gcp) } - let(:group) { cluster.group } - - context 'when group has a project' do - let!(:project) { create(:project, group: group) } - - it_behaves_like 'unconfigured cluster' - end - - context 'when group has project in a sub-group' do - let!(:subgroup) { create(:group, parent: group) } - let!(:project) { create(:project, group: subgroup) } - - it_behaves_like 'unconfigured cluster' - end - end - - context 'when provider type is gcp' do - let!(:cluster) { create(:cluster, :project, :provided_by_gcp) } - - it_behaves_like 'configured cluster' - end - - context 'when provider type is user' do - let!(:cluster) { create(:cluster, :project, :provided_by_user) } - - it_behaves_like 'configured cluster' - end - - context 'when cluster is not managed' do - let(:cluster) { create(:cluster, :not_managed) } - - it 'does not configure the cluster' do - expect(Clusters::RefreshService).not_to receive(:create_or_update_namespaces_for_cluster) - - described_class.new.perform(cluster.id) - end - end - - context 'when cluster does not exist' do - it 'does not provision a cluster' do - expect_any_instance_of(Clusters::Gcp::Kubernetes::CreateOrUpdateNamespaceService).not_to receive(:execute) - - described_class.new.perform(123) - end - end -end diff --git a/spec/workers/cluster_project_configure_worker_spec.rb b/spec/workers/cluster_project_configure_worker_spec.rb deleted file mode 100644 index 2ac9d0f61b4..00000000000 --- a/spec/workers/cluster_project_configure_worker_spec.rb +++ /dev/null @@ -1,14 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -describe ClusterProjectConfigureWorker, '#perform' do - let(:worker) { described_class.new } - let(:cluster) { create(:cluster, :project) } - - it 'configures the cluster' do - expect(Clusters::RefreshService).to receive(:create_or_update_namespaces_for_project) - - described_class.new.perform(cluster.projects.first.id) - end -end diff --git a/vendor/licenses.csv b/vendor/licenses.csv index 0c52cb5a947..0c445aeac88 100644 --- a/vendor/licenses.csv +++ b/vendor/licenses.csv @@ -816,8 +816,6 @@ pbkdf2,3.0.14,MIT peek,1.0.1,MIT peek-gc,0.0.2,MIT peek-mysql2,1.1.0,MIT -peek-pg,1.3.0,MIT -peek-rblineprof,0.2.0,MIT peek-redis,1.2.0,MIT pg,0.18.4,"BSD,ruby,GPL" pify,3.0.0,MIT diff --git a/yarn.lock b/yarn.lock index 7d1ef927e9c..d0e43363977 100644 --- a/yarn.lock +++ b/yarn.lock @@ -996,10 +996,10 @@ resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.67.0.tgz#c7b94eca13b99fd3aaa737fb6dcc0abc41d3c579" integrity sha512-hJOmWEs6RkjzyKkb1vc9wwKGZIBIP0coHkxu/KgOoxhBVudpGk4CH7xJ6UuB2TKpb0SEh5CC1CzRZfBYaFhsaA== -"@gitlab/ui@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-5.7.0.tgz#2ce6b431de262f09b2e1dbe77b047d6e8e1ca41d" - integrity sha512-zOPFNrCGyZrgqa8OXNhtfRg4aQ6pRCpIV2+alq3/4jllYb3HHHH+jIk/ejLrvNe8+fk7LRNSvJEvuInRLqBbEg== +"@gitlab/ui@^5.9.0": + version "5.9.0" + resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-5.9.0.tgz#a38b1b57c365608b100b95969ae7a57ce1707542" + integrity sha512-cgvEPWVerYZNLqkHjg5dd0VhEDBWj8aNoISZCaGOWI9K4yVtpMPVRUv19o/xYm4vUexfFsG9vg9lBgd+4ZU6Yw== dependencies: "@babel/standalone" "^7.0.0" "@gitlab/vue-toasted" "^1.2.1" @@ -2180,10 +2180,10 @@ bfj@^6.1.1: hoopy "^0.1.2" tryer "^1.0.0" -big.js@^3.1.3: - version "3.2.0" - resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e" - integrity sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q== +big.js@^5.2.2: + version "5.2.2" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" + integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== binary-extensions@^1.0.0: version "1.11.0" @@ -2207,10 +2207,10 @@ block-stream@*: dependencies: inherits "~2.0.0" -bluebird@^3.1.1, bluebird@^3.3.0, bluebird@^3.5.1, bluebird@^3.5.3, bluebird@~3.5.0: - version "3.5.3" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.3.tgz#7d01c6f9616c9a51ab0f8c549a79dfe6ec33efa7" - integrity sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw== +bluebird@^3.1.1, bluebird@^3.3.0, bluebird@^3.5.1, bluebird@^3.5.5, bluebird@~3.5.0: + version "3.5.5" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.5.tgz#a8d0afd73251effbbd5fe384a77d73003c17a71f" + integrity sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w== bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: version "4.11.8" @@ -2469,22 +2469,22 @@ bytes@3.0.0: resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg= -cacache@^11.0.2, cacache@^11.2.0: - version "11.3.2" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-11.3.2.tgz#2d81e308e3d258ca38125b676b98b2ac9ce69bfa" - integrity sha512-E0zP4EPGDOaT2chM08Als91eYnf8Z+eH1awwwVsngUmgppfM5jjJ8l3z5vO5p5w/I3LsiXawb1sW0VY65pQABg== +cacache@^11.0.2, cacache@^11.2.0, cacache@^11.3.3: + version "11.3.3" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-11.3.3.tgz#8bd29df8c6a718a6ebd2d010da4d7972ae3bbadc" + integrity sha512-p8WcneCytvzPxhDvYp31PD039vi77I12W+/KfR9S8AZbaiARFBCpsPJS+9uhWfeBfeAtW7o/4vt3MUqLkbY6nA== dependencies: - bluebird "^3.5.3" + bluebird "^3.5.5" chownr "^1.1.1" figgy-pudding "^3.5.1" - glob "^7.1.3" + glob "^7.1.4" graceful-fs "^4.1.15" lru-cache "^5.1.1" mississippi "^3.0.0" mkdirp "^0.5.1" move-concurrently "^1.0.1" promise-inflight "^1.0.1" - rimraf "^2.6.2" + rimraf "^2.6.3" ssri "^6.0.1" unique-filename "^1.1.1" y18n "^4.0.0" @@ -3204,6 +3204,24 @@ copy-to-clipboard@^3.0.8: dependencies: toggle-selection "^1.0.3" +copy-webpack-plugin@^5.0.4: + version "5.0.4" + resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-5.0.4.tgz#c78126f604e24f194c6ec2f43a64e232b5d43655" + integrity sha512-YBuYGpSzoCHSSDGyHy6VJ7SHojKp6WHT4D7ItcQFNAYx2hrwkMe56e97xfVR0/ovDuMTrMffXUiltvQljtAGeg== + dependencies: + cacache "^11.3.3" + find-cache-dir "^2.1.0" + glob-parent "^3.1.0" + globby "^7.1.1" + is-glob "^4.0.1" + loader-utils "^1.2.3" + minimatch "^3.0.4" + normalize-path "^3.0.0" + p-limit "^2.2.0" + schema-utils "^1.0.0" + serialize-javascript "^1.7.0" + webpack-log "^2.0.0" + core-js-compat@^3.1.1: version "3.1.4" resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.1.4.tgz#e4d0c40fbd01e65b1d457980fe4112d4358a7408" @@ -4063,7 +4081,7 @@ diffie-hellman@^5.0.0: miller-rabin "^4.0.0" randombytes "^2.0.0" -dir-glob@^2.2.2: +dir-glob@^2.0.0, dir-glob@^2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-2.2.2.tgz#fa09f0694153c8918b18ba0deafae94769fc50c4" integrity sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw== @@ -5164,13 +5182,13 @@ finalhandler@1.1.1: statuses "~1.4.0" unpipe "~1.0.0" -find-cache-dir@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.0.0.tgz#4c1faed59f45184530fb9d7fa123a4d04a98472d" - integrity sha512-LDUY6V1Xs5eFskUVYtIwatojt6+9xC9Chnlk/jYOOvn3FAFfSaWddxahDGyNHh0b2dMXa6YW2m0tk8TdVaXHlA== +find-cache-dir@^2.0.0, find-cache-dir@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7" + integrity sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ== dependencies: commondir "^1.0.1" - make-dir "^1.0.0" + make-dir "^2.0.0" pkg-dir "^3.0.0" find-root@^1.0.0, find-root@^1.1.0: @@ -5528,7 +5546,7 @@ glob-to-regexp@^0.4.0: resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== -"glob@5 - 7", glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@~7.1.1: +"glob@5 - 7", glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@~7.1.1: version "7.1.4" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A== @@ -5621,6 +5639,18 @@ globby@^6.1.0: pify "^2.0.0" pinkie-promise "^2.0.0" +globby@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/globby/-/globby-7.1.1.tgz#fb2ccff9401f8600945dfada97440cca972b8680" + integrity sha1-+yzP+UAfhgCUXfral0QMypcrhoA= + dependencies: + array-union "^1.0.1" + dir-glob "^2.0.0" + glob "^7.1.2" + ignore "^3.3.5" + pify "^3.0.0" + slash "^1.0.0" + globby@^9.2.0: version "9.2.0" resolved "https://registry.yarnpkg.com/globby/-/globby-9.2.0.tgz#fd029a706c703d29bdd170f4b6db3a3f7a7cb63d" @@ -6120,6 +6150,11 @@ ignore-walk@^3.0.1: dependencies: minimatch "^3.0.4" +ignore@^3.3.5: + version "3.3.10" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043" + integrity sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug== + ignore@^4.0.3, ignore@^4.0.6: version "4.0.6" resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" @@ -6482,10 +6517,10 @@ is-glob@^3.1.0: dependencies: is-extglob "^2.1.0" -is-glob@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.0.tgz#9521c76845cc2610a85203ddf080a958c2ffabc0" - integrity sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A= +is-glob@^4.0.0, is-glob@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" + integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== dependencies: is-extglob "^2.1.1" @@ -7379,10 +7414,12 @@ json5@2.x, json5@^2.1.0: dependencies: minimist "^1.2.0" -json5@^0.5.0: - version "0.5.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" - integrity sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE= +json5@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" + integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== + dependencies: + minimist "^1.2.0" jsonparse@^1.2.0: version "1.3.1" @@ -7682,14 +7719,14 @@ loader-runner@^2.3.0: resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.3.0.tgz#f482aea82d543e07921700d5a46ef26fdac6b8a2" integrity sha1-9IKuqC1UPgeSFwDVpG7yb9rGuKI= -loader-utils@^1.0.0, loader-utils@^1.0.2, loader-utils@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.1.0.tgz#c98aef488bcceda2ffb5e2de646d6a754429f5cd" - integrity sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0= +loader-utils@^1.0.0, loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.2.3.tgz#1ff5dc6911c9f0a062531a4c04b609406108c2c7" + integrity sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA== dependencies: - big.js "^3.1.3" + big.js "^5.2.2" emojis-list "^2.0.0" - json5 "^0.5.0" + json5 "^1.0.1" locate-path@^2.0.0: version "2.0.0" @@ -7862,7 +7899,7 @@ make-dir@^1.0.0, make-dir@^1.3.0: dependencies: pify "^3.0.0" -make-dir@^2.1.0: +make-dir@^2.0.0, make-dir@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== @@ -8340,7 +8377,7 @@ monaco-editor@^0.15.6: resolved "https://registry.yarnpkg.com/monaco-editor/-/monaco-editor-0.15.6.tgz#d63b3b06f86f803464f003b252627c3eb4a09483" integrity sha512-JoU9V9k6KqT9R9Tiw1RTU8ohZ+Xnf9DMg6Ktqqw5hILumwmq7xqa/KLXw513uTUsWbhtnHoSJYYR++u3pkyxJg== -mousetrap@^1.4.6: +mousetrap@1.4.6: version "1.4.6" resolved "https://registry.yarnpkg.com/mousetrap/-/mousetrap-1.4.6.tgz#eaca72e22e56d5b769b7555873b688c3332e390a" integrity sha1-6spy4i5W1bdpt1VYc7aIwzMuOQo= @@ -8956,7 +8993,7 @@ p-limit@^1.1.0: dependencies: p-try "^1.0.0" -p-limit@^2.0.0: +p-limit@^2.0.0, p-limit@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.0.tgz#417c9941e6027a9abcba5092dd2904e255b5fbc2" integrity sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ== @@ -9245,9 +9282,9 @@ pbkdf2@^3.0.3: sha.js "^2.4.8" pdfjs-dist@^2.0.943: - version "2.0.943" - resolved "https://registry.yarnpkg.com/pdfjs-dist/-/pdfjs-dist-2.0.943.tgz#32fb9a2d863df5a1d89521a0b3cd900c16e7edde" - integrity sha512-iLhNcm4XceTHRaSU5o22ZGCm4YpuW5+rf4+BJFH/feBhMQLbCGBry+Jet8Q419QDI4qgARaIQzXuiNrsNWS8Yw== + version "2.1.266" + resolved "https://registry.yarnpkg.com/pdfjs-dist/-/pdfjs-dist-2.1.266.tgz#cded02268b389559e807f410d2a729db62160026" + integrity sha512-Jy7o1wE3NezPxozexSbq4ltuLT0Z21ew/qrEiAEeUZzHxMHGk4DUV1D7RuCXg5vJDvHmjX1YssN+we9QfRRgXQ== dependencies: node-ensure "^0.0.0" worker-loader "^2.0.0" @@ -10542,7 +10579,7 @@ rfdc@^1.1.2: resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.1.2.tgz#e6e72d74f5dc39de8f538f65e00c36c18018e349" integrity sha512-92ktAgvZhBzYTIK0Mja9uen5q5J3NRVMoDkJL2VMwq6SXjVCgqvQeVP2XAaUY6HT+XpQYeLSjb3UoitBryKmdA== -rimraf@2, rimraf@2.6.3, rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.0, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@^2.6.3: +rimraf@2, rimraf@2.6.3, rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.0, rimraf@^2.6.1, rimraf@^2.6.3: version "2.6.3" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== @@ -10760,10 +10797,10 @@ send@0.16.2: range-parser "~1.2.0" statuses "~1.4.0" -serialize-javascript@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.4.0.tgz#7c958514db6ac2443a8abc062dc9f7886a7f6005" - integrity sha1-fJWFFNtqwkQ6irwGLcn3iGp/YAU= +serialize-javascript@^1.4.0, serialize-javascript@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.7.0.tgz#d6e0dfb2a3832a8c94468e6eb1db97e55a192a65" + integrity sha512-ke8UG8ulpFOxO8f8gRYabHQe/ZntKlcig2Mp+8+URDP1D8vJZ0KUt7LYo07q25Z/+JVSgpr/cui9PIp5H6/+nA== serve-index@^1.7.2: version "1.9.1" @@ -10881,6 +10918,11 @@ sisteransi@^1.0.0: resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.0.tgz#77d9622ff909080f1c19e5f4a1df0c1b0a27b88c" integrity sha512-N+z4pHB4AmUv0SjveWRd6q1Nj5w62m5jodv+GD8lvmbY/83T/rpbJGZOnK5T149OldDj4Db07BSv9xY4K6NTPQ== +slash@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" + integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU= + slash@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" |