diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION index a9a7f3fec01..3f667dbcd89 100644 --- a/GITALY_SERVER_VERSION +++ b/GITALY_SERVER_VERSION @@ -1 +1 @@ -0.107.0 +0.108.0 diff --git a/Gemfile b/Gemfile index 93c6115eeec..283886b7187 100644 --- a/Gemfile +++ b/Gemfile @@ -418,7 +418,7 @@ group :ed25519 do end # Gitaly GRPC client -gem 'gitaly-proto', '~> 0.102.0', require: 'gitaly' +gem 'gitaly-proto', '~> 0.103.0', require: 'gitaly' gem 'grpc', '~> 1.11.0' # Locked until https://github.com/google/protobuf/issues/4210 is closed diff --git a/Gemfile.lock b/Gemfile.lock index 8281c1eff9a..13f9212c637 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -282,7 +282,7 @@ GEM gettext_i18n_rails (>= 0.7.1) po_to_json (>= 1.0.0) rails (>= 3.2.0) - gitaly-proto (0.102.0) + gitaly-proto (0.103.0) google-protobuf (~> 3.1) grpc (~> 1.10) github-linguist (5.3.3) @@ -1041,7 +1041,7 @@ DEPENDENCIES gettext (~> 3.2.2) gettext_i18n_rails (~> 1.8.0) gettext_i18n_rails_js (~> 1.3) - gitaly-proto (~> 0.102.0) + gitaly-proto (~> 0.103.0) github-linguist (~> 5.3.3) gitlab-flowdock-git-hook (~> 1.0.1) gitlab-gollum-lib (~> 4.2) diff --git a/Gemfile.rails5.lock b/Gemfile.rails5.lock index 52388f17c7c..3161e4653ee 100644 --- a/Gemfile.rails5.lock +++ b/Gemfile.rails5.lock @@ -285,7 +285,7 @@ GEM gettext_i18n_rails (>= 0.7.1) po_to_json (>= 1.0.0) rails (>= 3.2.0) - gitaly-proto (0.102.0) + gitaly-proto (0.103.0) google-protobuf (~> 3.1) grpc (~> 1.10) github-linguist (5.3.3) @@ -1051,7 +1051,7 @@ DEPENDENCIES gettext (~> 3.2.2) gettext_i18n_rails (~> 1.8.0) gettext_i18n_rails_js (~> 1.3) - gitaly-proto (~> 0.102.0) + gitaly-proto (~> 0.103.0) github-linguist (~> 5.3.3) gitlab-flowdock-git-hook (~> 1.0.1) gitlab-gollum-lib (~> 4.2) diff --git a/PROCESS.md b/PROCESS.md index a46fd8c25b4..1cc5b44aa67 100644 --- a/PROCESS.md +++ b/PROCESS.md @@ -197,24 +197,7 @@ to. For example: If you think a merge request should go into an RC or patch even though it does not meet these requirements, you can ask for an exception to be made. -Go to [Release tasks issue tracker](https://gitlab.com/gitlab-org/release/tasks/issues/new) and create an issue -using the `Exception-request` issue template. - -**Do not** set the relevant `Pick into X.Y` label (see above) before request an -exception; this should be done after the exception is approved. - -You can find who is who on the [team page](https://about.gitlab.com/team/). - -Whether an exception is made is determined by weighing the benefit and urgency of the change -(how important it is to the company that this is released _right now_ instead of in a month) -against the potential negative impact -(things breaking without enough time to comfortably find and fix them before the release on the 22nd). -When in doubt, we err on the side of _not_ cherry-picking. - -For example, it is likely that an exception will be made for a trivial 1-5 line performance improvement -(e.g. adding a database index or adding `includes` to a query), but not for a new feature, no matter how relatively small or thoroughly tested. - -All MRs which have had exceptions granted must be merged by the 15th. +Check [this guide](https://gitlab.com/gitlab-org/release/docs/blob/master/general/exception-request/process.md) about how to open an exception request before opening one. ### Regressions diff --git a/app/assets/javascripts/boards/components/board_card.vue b/app/assets/javascripts/boards/components/board_card.vue index b7d3574bc80..0398102ad02 100644 --- a/app/assets/javascripts/boards/components/board_card.vue +++ b/app/assets/javascripts/boards/components/board_card.vue @@ -1,78 +1,78 @@ diff --git a/app/assets/javascripts/boards/components/issue_card_inner.js b/app/assets/javascripts/boards/components/issue_card_inner.js deleted file mode 100644 index f7d7b910e2f..00000000000 --- a/app/assets/javascripts/boards/components/issue_card_inner.js +++ /dev/null @@ -1,196 +0,0 @@ -import $ from 'jquery'; -import Vue from 'vue'; -import UserAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue'; -import eventHub from '../eventhub'; - -const Store = gl.issueBoards.BoardsStore; - -window.gl = window.gl || {}; -window.gl.issueBoards = window.gl.issueBoards || {}; - -gl.issueBoards.IssueCardInner = Vue.extend({ - components: { - UserAvatarLink, - }, - props: { - issue: { - type: Object, - required: true, - }, - issueLinkBase: { - type: String, - required: true, - }, - list: { - type: Object, - required: false, - default: () => ({}), - }, - rootPath: { - type: String, - required: true, - }, - updateFilters: { - type: Boolean, - required: false, - default: false, - }, - groupId: { - type: Number, - required: false, - default: null, - }, - }, - data() { - return { - limitBeforeCounter: 3, - maxRender: 4, - maxCounter: 99, - }; - }, - computed: { - numberOverLimit() { - return this.issue.assignees.length - this.limitBeforeCounter; - }, - assigneeCounterTooltip() { - return `${this.assigneeCounterLabel} more`; - }, - assigneeCounterLabel() { - if (this.numberOverLimit > this.maxCounter) { - return `${this.maxCounter}+`; - } - - return `+${this.numberOverLimit}`; - }, - shouldRenderCounter() { - if (this.issue.assignees.length <= this.maxRender) { - return false; - } - - return this.issue.assignees.length > this.numberOverLimit; - }, - issueId() { - if (this.issue.iid) { - return `#${this.issue.iid}`; - } - return false; - }, - showLabelFooter() { - return this.issue.labels.find(l => this.showLabel(l)) !== undefined; - }, - }, - methods: { - isIndexLessThanlimit(index) { - return index < this.limitBeforeCounter; - }, - shouldRenderAssignee(index) { - // Eg. maxRender is 4, - // Render up to all 4 assignees if there are only 4 assigness - // Otherwise render up to the limitBeforeCounter - if (this.issue.assignees.length <= this.maxRender) { - return index < this.maxRender; - } - - return index < this.limitBeforeCounter; - }, - assigneeUrl(assignee) { - return `${this.rootPath}${assignee.username}`; - }, - assigneeUrlTitle(assignee) { - return `Assigned to ${assignee.name}`; - }, - avatarUrlTitle(assignee) { - return `Avatar for ${assignee.name}`; - }, - showLabel(label) { - if (!label.id) return false; - return true; - }, - filterByLabel(label, e) { - if (!this.updateFilters) return; - - const filterPath = gl.issueBoards.BoardsStore.filter.path.split('&'); - const labelTitle = encodeURIComponent(label.title); - const param = `label_name[]=${labelTitle}`; - const labelIndex = filterPath.indexOf(param); - $(e.currentTarget).tooltip('hide'); - - if (labelIndex === -1) { - filterPath.push(param); - } else { - filterPath.splice(labelIndex, 1); - } - - gl.issueBoards.BoardsStore.filter.path = filterPath.join('&'); - - Store.updateFiltersUrl(); - - eventHub.$emit('updateTokens'); - }, - labelStyle(label) { - return { - backgroundColor: label.color, - color: label.textColor, - }; - }, - }, - template: ` - - - - - {{ issue.title }} - - {{ issue.referencePath }} - - - - - - {{ assigneeCounterLabel }} - - - - - - `, -}); diff --git a/app/assets/javascripts/boards/components/issue_card_inner.vue b/app/assets/javascripts/boards/components/issue_card_inner.vue new file mode 100644 index 00000000000..a0b7fe81a4a --- /dev/null +++ b/app/assets/javascripts/boards/components/issue_card_inner.vue @@ -0,0 +1,196 @@ + + + + + + + {{ issue.title }} + + {{ issue.referencePath }} + + + + + + {{ assigneeCounterLabel }} + + + + + + diff --git a/app/assets/javascripts/boards/components/modal/header.js b/app/assets/javascripts/boards/components/modal/header.js deleted file mode 100644 index cc9848058ca..00000000000 --- a/app/assets/javascripts/boards/components/modal/header.js +++ /dev/null @@ -1,79 +0,0 @@ -import Vue from 'vue'; -import modalFilters from './filters'; -import modalTabs from './tabs.vue'; -import ModalStore from '../../stores/modal_store'; -import modalMixin from '../../mixins/modal_mixins'; - -gl.issueBoards.ModalHeader = Vue.extend({ - components: { - modalTabs, - modalFilters, - }, - mixins: [modalMixin], - props: { - projectId: { - type: Number, - required: true, - }, - milestonePath: { - type: String, - required: true, - }, - labelPath: { - type: String, - required: true, - }, - }, - data() { - return ModalStore.store; - }, - computed: { - selectAllText() { - if (ModalStore.selectedCount() !== this.issues.length || this.issues.length === 0) { - return 'Select all'; - } - - return 'Deselect all'; - }, - showSearch() { - return this.activeTab === 'all' && !this.loading && this.issuesCount > 0; - }, - }, - methods: { - toggleAll() { - this.$refs.selectAllBtn.blur(); - - ModalStore.toggleAll(); - }, - }, - template: ` - - - - Add issues - - × - - - - - - - - {{ selectAllText }} - - - - `, -}); diff --git a/app/assets/javascripts/boards/components/modal/header.vue b/app/assets/javascripts/boards/components/modal/header.vue new file mode 100644 index 00000000000..979fb4d7199 --- /dev/null +++ b/app/assets/javascripts/boards/components/modal/header.vue @@ -0,0 +1,82 @@ + + + + + + Add issues + + × + + + + + + + + {{ selectAllText }} + + + + diff --git a/app/assets/javascripts/boards/components/modal/index.js b/app/assets/javascripts/boards/components/modal/index.js deleted file mode 100644 index 983061f52ae..00000000000 --- a/app/assets/javascripts/boards/components/modal/index.js +++ /dev/null @@ -1,171 +0,0 @@ -/* global ListIssue */ - -import Vue from 'vue'; -import queryData from '~/boards/utils/query_data'; -import loadingIcon from '~/vue_shared/components/loading_icon.vue'; -import './header'; -import './list'; -import ModalFooter from './footer.vue'; -import EmptyState from './empty_state.vue'; -import ModalStore from '../../stores/modal_store'; - -gl.issueBoards.IssuesModal = Vue.extend({ - components: { - EmptyState, - 'modal-header': gl.issueBoards.ModalHeader, - 'modal-list': gl.issueBoards.ModalList, - ModalFooter, - loadingIcon, - }, - props: { - newIssuePath: { - type: String, - required: true, - }, - emptyStateSvg: { - type: String, - required: true, - }, - issueLinkBase: { - type: String, - required: true, - }, - rootPath: { - type: String, - required: true, - }, - projectId: { - type: Number, - required: true, - }, - milestonePath: { - type: String, - required: true, - }, - labelPath: { - type: String, - required: true, - }, - }, - data() { - return ModalStore.store; - }, - computed: { - showList() { - if (this.activeTab === 'selected') { - return this.selectedIssues.length > 0; - } - - return this.issuesCount > 0; - }, - showEmptyState() { - if (!this.loading && this.issuesCount === 0) { - return true; - } - - return this.activeTab === 'selected' && this.selectedIssues.length === 0; - }, - }, - watch: { - page() { - this.loadIssues(); - }, - showAddIssuesModal() { - if (this.showAddIssuesModal && !this.issues.length) { - this.loading = true; - const loadingDone = () => { - this.loading = false; - }; - - this.loadIssues() - .then(loadingDone) - .catch(loadingDone); - } else if (!this.showAddIssuesModal) { - this.issues = []; - this.selectedIssues = []; - this.issuesCount = false; - } - }, - filter: { - handler() { - if (this.$el.tagName) { - this.page = 1; - this.filterLoading = true; - const loadingDone = () => { - this.filterLoading = false; - }; - - this.loadIssues(true) - .then(loadingDone) - .catch(loadingDone); - } - }, - deep: true, - }, - }, - created() { - this.page = 1; - }, - methods: { - loadIssues(clearIssues = false) { - if (!this.showAddIssuesModal) return false; - - return gl.boardService.getBacklog(queryData(this.filter.path, { - page: this.page, - per: this.perPage, - })) - .then(res => res.data) - .then((data) => { - if (clearIssues) { - this.issues = []; - } - - data.issues.forEach((issueObj) => { - const issue = new ListIssue(issueObj); - const foundSelectedIssue = ModalStore.findSelectedIssue(issue); - issue.selected = !!foundSelectedIssue; - - this.issues.push(issue); - }); - - this.loadingNewPage = false; - - if (!this.issuesCount) { - this.issuesCount = data.size; - } - }).catch(() => { - // TODO: handle request error - }); - }, - }, - template: ` - - - - - - - - - - - - - - - `, -}); diff --git a/app/assets/javascripts/boards/components/modal/index.vue b/app/assets/javascripts/boards/components/modal/index.vue new file mode 100644 index 00000000000..33e72a6782e --- /dev/null +++ b/app/assets/javascripts/boards/components/modal/index.vue @@ -0,0 +1,178 @@ + + + + + + + + + + + + + + + + diff --git a/app/assets/javascripts/boards/components/modal/list.js b/app/assets/javascripts/boards/components/modal/list.js deleted file mode 100644 index 11061c72a7b..00000000000 --- a/app/assets/javascripts/boards/components/modal/list.js +++ /dev/null @@ -1,159 +0,0 @@ -import Vue from 'vue'; -import bp from '../../../breakpoints'; -import ModalStore from '../../stores/modal_store'; - -gl.issueBoards.ModalList = Vue.extend({ - components: { - 'issue-card-inner': gl.issueBoards.IssueCardInner, - }, - props: { - issueLinkBase: { - type: String, - required: true, - }, - rootPath: { - type: String, - required: true, - }, - emptyStateSvg: { - type: String, - required: true, - }, - }, - data() { - return ModalStore.store; - }, - computed: { - loopIssues() { - if (this.activeTab === 'all') { - return this.issues; - } - - return this.selectedIssues; - }, - groupedIssues() { - const groups = []; - this.loopIssues.forEach((issue, i) => { - const index = i % this.columns; - - if (!groups[index]) { - groups.push([]); - } - - groups[index].push(issue); - }); - - return groups; - }, - }, - watch: { - activeTab() { - if (this.activeTab === 'all') { - ModalStore.purgeUnselectedIssues(); - } - }, - }, - mounted() { - this.scrollHandlerWrapper = this.scrollHandler.bind(this); - this.setColumnCountWrapper = this.setColumnCount.bind(this); - this.setColumnCount(); - - this.$refs.list.addEventListener('scroll', this.scrollHandlerWrapper); - window.addEventListener('resize', this.setColumnCountWrapper); - }, - beforeDestroy() { - this.$refs.list.removeEventListener('scroll', this.scrollHandlerWrapper); - window.removeEventListener('resize', this.setColumnCountWrapper); - }, - methods: { - scrollHandler() { - const currentPage = Math.floor(this.issues.length / this.perPage); - - if ( - this.scrollTop() > this.scrollHeight() - 100 && - !this.loadingNewPage && - currentPage === this.page - ) { - this.loadingNewPage = true; - this.page += 1; - } - }, - toggleIssue(e, issue) { - if (e.target.tagName !== 'A') { - ModalStore.toggleIssue(issue); - } - }, - listHeight() { - return this.$refs.list.getBoundingClientRect().height; - }, - scrollHeight() { - return this.$refs.list.scrollHeight; - }, - scrollTop() { - return this.$refs.list.scrollTop + this.listHeight(); - }, - showIssue(issue) { - if (this.activeTab === 'all') return true; - - const index = ModalStore.selectedIssueIndex(issue); - - return index !== -1; - }, - setColumnCount() { - const breakpoint = bp.getBreakpointSize(); - - if (breakpoint === 'lg' || breakpoint === 'md') { - this.columns = 3; - } else if (breakpoint === 'sm') { - this.columns = 2; - } else { - this.columns = 1; - } - }, - }, - template: ` - - - - - - - - There are no issues to show. - - - - - - - - - - - - - - - - `, -}); diff --git a/app/assets/javascripts/boards/components/modal/list.vue b/app/assets/javascripts/boards/components/modal/list.vue new file mode 100644 index 00000000000..02ac36d7367 --- /dev/null +++ b/app/assets/javascripts/boards/components/modal/list.vue @@ -0,0 +1,162 @@ + + + + + + + + + + There are no issues to show. + + + + + + + + + + + + + + + diff --git a/app/assets/javascripts/boards/index.js b/app/assets/javascripts/boards/index.js index 751a66f89c6..200d1923635 100644 --- a/app/assets/javascripts/boards/index.js +++ b/app/assets/javascripts/boards/index.js @@ -25,7 +25,7 @@ import './filters/due_date_filters'; import './components/board'; import './components/board_sidebar'; import './components/new_list_dropdown'; -import './components/modal/index'; +import BoardAddIssuesModal from './components/modal/index.vue'; import '~/vue_shared/vue_resource_interceptor'; // eslint-disable-line import/first export default () => { @@ -49,7 +49,7 @@ export default () => { components: { 'board': gl.issueBoards.Board, 'board-sidebar': gl.issueBoards.BoardSidebar, - 'board-add-issues-modal': gl.issueBoards.IssuesModal, + BoardAddIssuesModal, }, data: { state: Store.state, diff --git a/app/assets/javascripts/lib/utils/common_utils.js b/app/assets/javascripts/lib/utils/common_utils.js index 5c249f3068e..6b7550efff8 100644 --- a/app/assets/javascripts/lib/utils/common_utils.js +++ b/app/assets/javascripts/lib/utils/common_utils.js @@ -189,12 +189,25 @@ export const getParameterByName = (name, urlToParse) => { return decodeURIComponent(results[2].replace(/\+/g, ' ')); }; +const handleSelectedRange = (range) => { + const container = range.commonAncestorContainer; + // add context to fragment if needed + if (container.tagName === 'OL') { + const parentContainer = document.createElement(container.tagName); + parentContainer.appendChild(range.cloneContents()); + return parentContainer; + } + return range.cloneContents(); +}; + export const getSelectedFragment = () => { const selection = window.getSelection(); if (selection.rangeCount === 0) return null; const documentFragment = document.createDocumentFragment(); + for (let i = 0; i < selection.rangeCount; i += 1) { - documentFragment.appendChild(selection.getRangeAt(i).cloneContents()); + const range = selection.getRangeAt(i); + documentFragment.appendChild(handleSelectedRange(range)); } if (documentFragment.textContent.length === 0) return null; diff --git a/app/assets/javascripts/protected_branches/protected_branch_create.js b/app/assets/javascripts/protected_branches/protected_branch_create.js index 7c61c070a35..b601b19e7be 100644 --- a/app/assets/javascripts/protected_branches/protected_branch_create.js +++ b/app/assets/javascripts/protected_branches/protected_branch_create.js @@ -1,11 +1,8 @@ import $ from 'jquery'; -import _ from 'underscore'; import ProtectedBranchAccessDropdown from './protected_branch_access_dropdown'; import CreateItemDropdown from '../create_item_dropdown'; import AccessorUtilities from '../lib/utils/accessor'; -const PB_LOCAL_STORAGE_KEY = 'protected-branches-defaults'; - export default class ProtectedBranchCreate { constructor() { this.$form = $('.js-new-protected-branch'); @@ -43,8 +40,6 @@ export default class ProtectedBranchCreate { onSelect: this.onSelectCallback, getData: ProtectedBranchCreate.getProtectedBranches, }); - - this.loadPreviousSelection($allowedToMergeDropdown.data('glDropdown'), $allowedToPushDropdown.data('glDropdown')); } // This will run after clicked callback @@ -59,39 +54,10 @@ export default class ProtectedBranchCreate { $allowedToPushInput.length ); - this.savePreviousSelection($allowedToMergeInput.val(), $allowedToPushInput.val()); this.$form.find('input[type="submit"]').prop('disabled', completedForm); } static getProtectedBranches(term, callback) { callback(gon.open_branches); } - - loadPreviousSelection(mergeDropdown, pushDropdown) { - let mergeIndex = 0; - let pushIndex = 0; - if (this.isLocalStorageAvailable) { - const savedDefaults = JSON.parse(window.localStorage.getItem(PB_LOCAL_STORAGE_KEY)); - if (savedDefaults != null) { - mergeIndex = _.findLastIndex(mergeDropdown.fullData.roles, { - id: parseInt(savedDefaults.mergeSelection, 0), - }); - pushIndex = _.findLastIndex(pushDropdown.fullData.roles, { - id: parseInt(savedDefaults.pushSelection, 0), - }); - } - } - mergeDropdown.selectRowAtIndex(mergeIndex); - pushDropdown.selectRowAtIndex(pushIndex); - } - - savePreviousSelection(mergeSelection, pushSelection) { - if (this.isLocalStorageAvailable) { - const branchDefaults = { - mergeSelection, - pushSelection, - }; - window.localStorage.setItem(PB_LOCAL_STORAGE_KEY, JSON.stringify(branchDefaults)); - } - } } diff --git a/app/assets/javascripts/search_autocomplete.js b/app/assets/javascripts/search_autocomplete.js index 2f4e4881f24..5b2e0468784 100644 --- a/app/assets/javascripts/search_autocomplete.js +++ b/app/assets/javascripts/search_autocomplete.js @@ -289,7 +289,7 @@ export default class SearchAutocomplete { } // If the dropdown is closed, we'll open it - if (!this.dropdown.hasClass('open')) { + if (!this.dropdown.hasClass('show')) { this.loadingSuggestions = false; this.dropdownToggle.dropdown('toggle'); return this.searchInput.removeClass('disabled'); @@ -424,9 +424,9 @@ export default class SearchAutocomplete { } disableAutocomplete() { - if (!this.searchInput.hasClass('disabled') && this.dropdown.hasClass('open')) { + if (!this.searchInput.hasClass('disabled') && this.dropdown.hasClass('show')) { this.searchInput.addClass('disabled'); - this.dropdown.removeClass('open').trigger('hidden.bs.dropdown'); + this.dropdown.removeClass('show').trigger('hidden.bs.dropdown'); this.restoreMenu(); } } diff --git a/app/controllers/health_controller.rb b/app/controllers/health_controller.rb index e54f372344d..3fedd5bfb29 100644 --- a/app/controllers/health_controller.rb +++ b/app/controllers/health_controller.rb @@ -8,7 +8,6 @@ class HealthController < ActionController::Base Gitlab::HealthChecks::Redis::CacheCheck, Gitlab::HealthChecks::Redis::QueuesCheck, Gitlab::HealthChecks::Redis::SharedStateCheck, - Gitlab::HealthChecks::FsShardsCheck, Gitlab::HealthChecks::GitalyCheck ].freeze diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index f5d94ad96a1..0190aa90763 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -270,7 +270,7 @@ module ApplicationHelper { members: members_project_autocomplete_sources_path(object, type: noteable_type, type_id: params[:id]), issues: issues_project_autocomplete_sources_path(object), - merge_requests: merge_requests_project_autocomplete_sources_path(object), + mergeRequests: merge_requests_project_autocomplete_sources_path(object), labels: labels_project_autocomplete_sources_path(object, type: noteable_type, type_id: params[:id]), milestones: milestones_project_autocomplete_sources_path(object), commands: commands_project_autocomplete_sources_path(object, type: noteable_type, type_id: params[:id]) diff --git a/app/services/metrics_service.rb b/app/services/metrics_service.rb index 236e9fe8c44..51ff9eff5e4 100644 --- a/app/services/metrics_service.rb +++ b/app/services/metrics_service.rb @@ -6,7 +6,8 @@ class MetricsService Gitlab::HealthChecks::Redis::RedisCheck, Gitlab::HealthChecks::Redis::CacheCheck, Gitlab::HealthChecks::Redis::QueuesCheck, - Gitlab::HealthChecks::Redis::SharedStateCheck + Gitlab::HealthChecks::Redis::SharedStateCheck, + Gitlab::HealthChecks::GitalyCheck ].freeze def prometheus_metrics_text diff --git a/app/workers/admin_email_worker.rb b/app/workers/admin_email_worker.rb index 044e470141e..06324575ffc 100644 --- a/app/workers/admin_email_worker.rb +++ b/app/workers/admin_email_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AdminEmailWorker include ApplicationWorker include CronjobQueue diff --git a/app/workers/archive_trace_worker.rb b/app/workers/archive_trace_worker.rb index dea7425ad88..9169f21af2a 100644 --- a/app/workers/archive_trace_worker.rb +++ b/app/workers/archive_trace_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ArchiveTraceWorker include ApplicationWorker include PipelineBackgroundQueue diff --git a/app/workers/authorized_projects_worker.rb b/app/workers/authorized_projects_worker.rb index 8fe3619f6ee..dd62bb0f33d 100644 --- a/app/workers/authorized_projects_worker.rb +++ b/app/workers/authorized_projects_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AuthorizedProjectsWorker include ApplicationWorker prepend WaitableWorker diff --git a/app/workers/background_migration_worker.rb b/app/workers/background_migration_worker.rb index 376703f6319..eaec7d48f35 100644 --- a/app/workers/background_migration_worker.rb +++ b/app/workers/background_migration_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class BackgroundMigrationWorker include ApplicationWorker diff --git a/app/workers/build_coverage_worker.rb b/app/workers/build_coverage_worker.rb index 62b212c79be..53d77dc4524 100644 --- a/app/workers/build_coverage_worker.rb +++ b/app/workers/build_coverage_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class BuildCoverageWorker include ApplicationWorker include PipelineQueue diff --git a/app/workers/build_finished_worker.rb b/app/workers/build_finished_worker.rb index 46f1ac09915..9dc2c7f3601 100644 --- a/app/workers/build_finished_worker.rb +++ b/app/workers/build_finished_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class BuildFinishedWorker include ApplicationWorker include PipelineQueue diff --git a/app/workers/build_hooks_worker.rb b/app/workers/build_hooks_worker.rb index cbfca8c342c..f1f71dc589c 100644 --- a/app/workers/build_hooks_worker.rb +++ b/app/workers/build_hooks_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class BuildHooksWorker include ApplicationWorker include PipelineQueue diff --git a/app/workers/build_queue_worker.rb b/app/workers/build_queue_worker.rb index e4f4e6c1d9e..1b3f1fd3c2a 100644 --- a/app/workers/build_queue_worker.rb +++ b/app/workers/build_queue_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class BuildQueueWorker include ApplicationWorker include PipelineQueue diff --git a/app/workers/build_success_worker.rb b/app/workers/build_success_worker.rb index 4b9097bc5e4..e1c1cc24a94 100644 --- a/app/workers/build_success_worker.rb +++ b/app/workers/build_success_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class BuildSuccessWorker include ApplicationWorker include PipelineQueue diff --git a/app/workers/build_trace_sections_worker.rb b/app/workers/build_trace_sections_worker.rb index c0f5c144e10..f4114b3353c 100644 --- a/app/workers/build_trace_sections_worker.rb +++ b/app/workers/build_trace_sections_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class BuildTraceSectionsWorker include ApplicationWorker include PipelineQueue diff --git a/app/workers/ci/archive_traces_cron_worker.rb b/app/workers/ci/archive_traces_cron_worker.rb index 2ac65f41f4e..7016edde698 100644 --- a/app/workers/ci/archive_traces_cron_worker.rb +++ b/app/workers/ci/archive_traces_cron_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Ci class ArchiveTracesCronWorker include ApplicationWorker diff --git a/app/workers/ci/build_trace_chunk_flush_worker.rb b/app/workers/ci/build_trace_chunk_flush_worker.rb index 218d6688bd9..6376c6d32cf 100644 --- a/app/workers/ci/build_trace_chunk_flush_worker.rb +++ b/app/workers/ci/build_trace_chunk_flush_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Ci class BuildTraceChunkFlushWorker include ApplicationWorker diff --git a/app/workers/cluster_install_app_worker.rb b/app/workers/cluster_install_app_worker.rb index f771cb4939f..32e2ea7996c 100644 --- a/app/workers/cluster_install_app_worker.rb +++ b/app/workers/cluster_install_app_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ClusterInstallAppWorker include ApplicationWorker include ClusterQueue diff --git a/app/workers/cluster_provision_worker.rb b/app/workers/cluster_provision_worker.rb index 1ab4de3b647..59de7903c1c 100644 --- a/app/workers/cluster_provision_worker.rb +++ b/app/workers/cluster_provision_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ClusterProvisionWorker include ApplicationWorker include ClusterQueue diff --git a/app/workers/cluster_wait_for_app_installation_worker.rb b/app/workers/cluster_wait_for_app_installation_worker.rb index d564d5e48bf..e8d7e52f70f 100644 --- a/app/workers/cluster_wait_for_app_installation_worker.rb +++ b/app/workers/cluster_wait_for_app_installation_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ClusterWaitForAppInstallationWorker include ApplicationWorker include ClusterQueue diff --git a/app/workers/cluster_wait_for_ingress_ip_address_worker.rb b/app/workers/cluster_wait_for_ingress_ip_address_worker.rb index 8ba5951750c..6865384df44 100644 --- a/app/workers/cluster_wait_for_ingress_ip_address_worker.rb +++ b/app/workers/cluster_wait_for_ingress_ip_address_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ClusterWaitForIngressIpAddressWorker include ApplicationWorker include ClusterQueue diff --git a/app/workers/concerns/application_worker.rb b/app/workers/concerns/application_worker.rb index 37586e161c9..bb06e31641d 100644 --- a/app/workers/concerns/application_worker.rb +++ b/app/workers/concerns/application_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + Sidekiq::Worker.extend ActiveSupport::Concern module ApplicationWorker diff --git a/app/workers/concerns/cluster_applications.rb b/app/workers/concerns/cluster_applications.rb index 24ecaa0b52f..9758a1ceb0e 100644 --- a/app/workers/concerns/cluster_applications.rb +++ b/app/workers/concerns/cluster_applications.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ClusterApplications extend ActiveSupport::Concern diff --git a/app/workers/concerns/cluster_queue.rb b/app/workers/concerns/cluster_queue.rb index 24b9f145220..e44b40c36c9 100644 --- a/app/workers/concerns/cluster_queue.rb +++ b/app/workers/concerns/cluster_queue.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + ## # Concern for setting Sidekiq settings for the various Gcp clusters workers. # diff --git a/app/workers/concerns/cronjob_queue.rb b/app/workers/concerns/cronjob_queue.rb index b6581779f6a..0683b229381 100644 --- a/app/workers/concerns/cronjob_queue.rb +++ b/app/workers/concerns/cronjob_queue.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Concern that sets various Sidekiq settings for workers executed using a # cronjob. module CronjobQueue diff --git a/app/workers/concerns/exception_backtrace.rb b/app/workers/concerns/exception_backtrace.rb index ea0f1f8d19b..37c9eaba0d7 100644 --- a/app/workers/concerns/exception_backtrace.rb +++ b/app/workers/concerns/exception_backtrace.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Concern for enabling a few lines of exception backtraces in Sidekiq module ExceptionBacktrace extend ActiveSupport::Concern diff --git a/app/workers/concerns/gitlab/github_import/queue.rb b/app/workers/concerns/gitlab/github_import/queue.rb index 22c2ce458e8..59b621f16ab 100644 --- a/app/workers/concerns/gitlab/github_import/queue.rb +++ b/app/workers/concerns/gitlab/github_import/queue.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Gitlab module GithubImport module Queue diff --git a/app/workers/concerns/mail_scheduler_queue.rb b/app/workers/concerns/mail_scheduler_queue.rb index f3e9680d756..c051151e973 100644 --- a/app/workers/concerns/mail_scheduler_queue.rb +++ b/app/workers/concerns/mail_scheduler_queue.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module MailSchedulerQueue extend ActiveSupport::Concern diff --git a/app/workers/concerns/new_issuable.rb b/app/workers/concerns/new_issuable.rb index 526ed0bad07..7735dec5e6b 100644 --- a/app/workers/concerns/new_issuable.rb +++ b/app/workers/concerns/new_issuable.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module NewIssuable attr_reader :issuable, :user diff --git a/app/workers/concerns/object_storage_queue.rb b/app/workers/concerns/object_storage_queue.rb index a80f473a6d4..8650eed213a 100644 --- a/app/workers/concerns/object_storage_queue.rb +++ b/app/workers/concerns/object_storage_queue.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Concern for setting Sidekiq settings for the various GitLab ObjectStorage workers. module ObjectStorageQueue extend ActiveSupport::Concern diff --git a/app/workers/concerns/pipeline_background_queue.rb b/app/workers/concerns/pipeline_background_queue.rb index 8bf43de6b26..bbb8ad0c982 100644 --- a/app/workers/concerns/pipeline_background_queue.rb +++ b/app/workers/concerns/pipeline_background_queue.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + ## # Concern for setting Sidekiq settings for the low priority CI pipeline workers. # diff --git a/app/workers/concerns/pipeline_queue.rb b/app/workers/concerns/pipeline_queue.rb index e77093a6902..3aaed4669e5 100644 --- a/app/workers/concerns/pipeline_queue.rb +++ b/app/workers/concerns/pipeline_queue.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + ## # Concern for setting Sidekiq settings for the various CI pipeline workers. # diff --git a/app/workers/concerns/project_import_options.rb b/app/workers/concerns/project_import_options.rb index ef23990ad97..22bdf441d6b 100644 --- a/app/workers/concerns/project_import_options.rb +++ b/app/workers/concerns/project_import_options.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ProjectImportOptions extend ActiveSupport::Concern diff --git a/app/workers/concerns/project_start_import.rb b/app/workers/concerns/project_start_import.rb index 4e55a1ee3d6..46a133db2a1 100644 --- a/app/workers/concerns/project_start_import.rb +++ b/app/workers/concerns/project_start_import.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Used in EE by mirroring module ProjectStartImport def start(project) diff --git a/app/workers/concerns/repository_check_queue.rb b/app/workers/concerns/repository_check_queue.rb index 43fb66c31b0..216d67e5dbc 100644 --- a/app/workers/concerns/repository_check_queue.rb +++ b/app/workers/concerns/repository_check_queue.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Concern for setting Sidekiq settings for the various repository check workers. module RepositoryCheckQueue extend ActiveSupport::Concern diff --git a/app/workers/concerns/waitable_worker.rb b/app/workers/concerns/waitable_worker.rb index 48ebe862248..d85bc7d1660 100644 --- a/app/workers/concerns/waitable_worker.rb +++ b/app/workers/concerns/waitable_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module WaitableWorker extend ActiveSupport::Concern diff --git a/app/workers/create_gpg_signature_worker.rb b/app/workers/create_gpg_signature_worker.rb index f371731f68c..a2da1bda11f 100644 --- a/app/workers/create_gpg_signature_worker.rb +++ b/app/workers/create_gpg_signature_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CreateGpgSignatureWorker include ApplicationWorker diff --git a/app/workers/create_note_diff_file_worker.rb b/app/workers/create_note_diff_file_worker.rb index 624b638a24e..0850250f7e3 100644 --- a/app/workers/create_note_diff_file_worker.rb +++ b/app/workers/create_note_diff_file_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CreateNoteDiffFileWorker include ApplicationWorker diff --git a/app/workers/create_pipeline_worker.rb b/app/workers/create_pipeline_worker.rb index c3ac35e54f5..037b4a57d4b 100644 --- a/app/workers/create_pipeline_worker.rb +++ b/app/workers/create_pipeline_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CreatePipelineWorker include ApplicationWorker include PipelineQueue diff --git a/app/workers/delete_merged_branches_worker.rb b/app/workers/delete_merged_branches_worker.rb index 07cd1f02fb5..017d7fd1cb0 100644 --- a/app/workers/delete_merged_branches_worker.rb +++ b/app/workers/delete_merged_branches_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class DeleteMergedBranchesWorker include ApplicationWorker diff --git a/app/workers/delete_user_worker.rb b/app/workers/delete_user_worker.rb index 6c431b02979..4d0295f8d2e 100644 --- a/app/workers/delete_user_worker.rb +++ b/app/workers/delete_user_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class DeleteUserWorker include ApplicationWorker diff --git a/app/workers/email_receiver_worker.rb b/app/workers/email_receiver_worker.rb index dd8a6cbbef1..f9f0efb302a 100644 --- a/app/workers/email_receiver_worker.rb +++ b/app/workers/email_receiver_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class EmailReceiverWorker include ApplicationWorker diff --git a/app/workers/emails_on_push_worker.rb b/app/workers/emails_on_push_worker.rb index 2a4d65b5cb3..8d0cfc73ccd 100644 --- a/app/workers/emails_on_push_worker.rb +++ b/app/workers/emails_on_push_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class EmailsOnPushWorker include ApplicationWorker diff --git a/app/workers/expire_build_artifacts_worker.rb b/app/workers/expire_build_artifacts_worker.rb index 87e5dca01fd..5d3a9a39b93 100644 --- a/app/workers/expire_build_artifacts_worker.rb +++ b/app/workers/expire_build_artifacts_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ExpireBuildArtifactsWorker include ApplicationWorker include CronjobQueue diff --git a/app/workers/expire_build_instance_artifacts_worker.rb b/app/workers/expire_build_instance_artifacts_worker.rb index 234b4357cf7..3b57ecb36e3 100644 --- a/app/workers/expire_build_instance_artifacts_worker.rb +++ b/app/workers/expire_build_instance_artifacts_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ExpireBuildInstanceArtifactsWorker include ApplicationWorker diff --git a/app/workers/expire_job_cache_worker.rb b/app/workers/expire_job_cache_worker.rb index 7217364a9f2..14a57b90114 100644 --- a/app/workers/expire_job_cache_worker.rb +++ b/app/workers/expire_job_cache_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ExpireJobCacheWorker include ApplicationWorker include PipelineQueue diff --git a/app/workers/expire_pipeline_cache_worker.rb b/app/workers/expire_pipeline_cache_worker.rb index db73d37868a..992fc63c451 100644 --- a/app/workers/expire_pipeline_cache_worker.rb +++ b/app/workers/expire_pipeline_cache_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ExpirePipelineCacheWorker include ApplicationWorker include PipelineQueue diff --git a/app/workers/git_garbage_collect_worker.rb b/app/workers/git_garbage_collect_worker.rb index ae5c5fac834..fd49bc18161 100644 --- a/app/workers/git_garbage_collect_worker.rb +++ b/app/workers/git_garbage_collect_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class GitGarbageCollectWorker include ApplicationWorker diff --git a/app/workers/gitlab_shell_worker.rb b/app/workers/gitlab_shell_worker.rb index a0028e41332..0e4d40acc5c 100644 --- a/app/workers/gitlab_shell_worker.rb +++ b/app/workers/gitlab_shell_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class GitlabShellWorker include ApplicationWorker include Gitlab::ShellAdapter diff --git a/app/workers/gitlab_usage_ping_worker.rb b/app/workers/gitlab_usage_ping_worker.rb index 6dd281b1147..b75e724ca98 100644 --- a/app/workers/gitlab_usage_ping_worker.rb +++ b/app/workers/gitlab_usage_ping_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class GitlabUsagePingWorker LEASE_TIMEOUT = 86400 diff --git a/app/workers/group_destroy_worker.rb b/app/workers/group_destroy_worker.rb index 509bd09dc2e..b4a3ddcae51 100644 --- a/app/workers/group_destroy_worker.rb +++ b/app/workers/group_destroy_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class GroupDestroyWorker include ApplicationWorker include ExceptionBacktrace diff --git a/app/workers/import_export_project_cleanup_worker.rb b/app/workers/import_export_project_cleanup_worker.rb index 9788c8df3a3..da3debdeede 100644 --- a/app/workers/import_export_project_cleanup_worker.rb +++ b/app/workers/import_export_project_cleanup_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ImportExportProjectCleanupWorker include ApplicationWorker include CronjobQueue diff --git a/app/workers/invalid_gpg_signature_update_worker.rb b/app/workers/invalid_gpg_signature_update_worker.rb index 6774ab307c6..4724ab7ad98 100644 --- a/app/workers/invalid_gpg_signature_update_worker.rb +++ b/app/workers/invalid_gpg_signature_update_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class InvalidGpgSignatureUpdateWorker include ApplicationWorker diff --git a/app/workers/irker_worker.rb b/app/workers/irker_worker.rb index 9ae5456be4c..29631c6b7ac 100644 --- a/app/workers/irker_worker.rb +++ b/app/workers/irker_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'json' require 'socket' @@ -69,8 +71,8 @@ class IrkerWorker newbranch = "#{Gitlab.config.gitlab.url}/#{repo_path}/branches" newbranch = "\x0302\x1f#{newbranch}\x0f" if @colors - privmsg = "[#{repo_name}] #{committer} has created a new branch " - privmsg += "#{branch}: #{newbranch}" + privmsg = "[#{repo_name}] #{committer} has created a new branch " \ + "#{branch}: #{newbranch}" sendtoirker privmsg end @@ -112,9 +114,7 @@ class IrkerWorker url = compare_url data, project.full_path commits = colorize_commits data['total_commits_count'] - new_commits = 'new commit' - new_commits += 's' if data['total_commits_count'] > 1 - + new_commits = 'new commit'.pluralize(data['total_commits_count']) sendtoirker "[#{repo}] #{committer} pushed #{commits} #{new_commits} " \ "to #{branch}: #{url}" end @@ -122,8 +122,8 @@ class IrkerWorker def compare_url(data, repo_path) sha1 = Commit.truncate_sha(data['before']) sha2 = Commit.truncate_sha(data['after']) - compare_url = "#{Gitlab.config.gitlab.url}/#{repo_path}/compare" - compare_url += "/#{sha1}...#{sha2}" + compare_url = "#{Gitlab.config.gitlab.url}/#{repo_path}/compare" \ + "/#{sha1}...#{sha2}" colorize_url compare_url end @@ -144,8 +144,7 @@ class IrkerWorker def files_count(commit) diff_size = commit.raw_deltas.size - files = "#{diff_size} file" - files += 's' if diff_size > 1 + files = "#{diff_size} file".pluralize(diff_size) files end diff --git a/app/workers/issue_due_scheduler_worker.rb b/app/workers/issue_due_scheduler_worker.rb index 16ab5d069e0..c04a2d75e0b 100644 --- a/app/workers/issue_due_scheduler_worker.rb +++ b/app/workers/issue_due_scheduler_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class IssueDueSchedulerWorker include ApplicationWorker include CronjobQueue diff --git a/app/workers/mail_scheduler/issue_due_worker.rb b/app/workers/mail_scheduler/issue_due_worker.rb index 54285884a52..8794ad7a82c 100644 --- a/app/workers/mail_scheduler/issue_due_worker.rb +++ b/app/workers/mail_scheduler/issue_due_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module MailScheduler class IssueDueWorker include ApplicationWorker diff --git a/app/workers/mail_scheduler/notification_service_worker.rb b/app/workers/mail_scheduler/notification_service_worker.rb index 7cfe0aa0df1..4726e416182 100644 --- a/app/workers/mail_scheduler/notification_service_worker.rb +++ b/app/workers/mail_scheduler/notification_service_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'active_job/arguments' module MailScheduler diff --git a/app/workers/merge_worker.rb b/app/workers/merge_worker.rb index ba832fe30c6..ee864b733cd 100644 --- a/app/workers/merge_worker.rb +++ b/app/workers/merge_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class MergeWorker include ApplicationWorker diff --git a/app/workers/namespaceless_project_destroy_worker.rb b/app/workers/namespaceless_project_destroy_worker.rb index adb25c2a170..d9df42c9e17 100644 --- a/app/workers/namespaceless_project_destroy_worker.rb +++ b/app/workers/namespaceless_project_destroy_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Worker to destroy projects that do not have a namespace # # It destroys everything it can without having the info about the namespace it diff --git a/app/workers/new_issue_worker.rb b/app/workers/new_issue_worker.rb index 3bc030f9c62..85b53973f56 100644 --- a/app/workers/new_issue_worker.rb +++ b/app/workers/new_issue_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class NewIssueWorker include ApplicationWorker include NewIssuable diff --git a/app/workers/new_merge_request_worker.rb b/app/workers/new_merge_request_worker.rb index bda2a0ab59d..5d8b8904502 100644 --- a/app/workers/new_merge_request_worker.rb +++ b/app/workers/new_merge_request_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class NewMergeRequestWorker include ApplicationWorker include NewIssuable diff --git a/app/workers/new_note_worker.rb b/app/workers/new_note_worker.rb index 67c54fbf10e..74f34dcf9aa 100644 --- a/app/workers/new_note_worker.rb +++ b/app/workers/new_note_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class NewNoteWorker include ApplicationWorker diff --git a/app/workers/object_storage/background_move_worker.rb b/app/workers/object_storage/background_move_worker.rb index 9c4d72e0ecf..8dff65e46e3 100644 --- a/app/workers/object_storage/background_move_worker.rb +++ b/app/workers/object_storage/background_move_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ObjectStorage class BackgroundMoveWorker include ApplicationWorker diff --git a/app/workers/object_storage_upload_worker.rb b/app/workers/object_storage_upload_worker.rb index 5c80f34069c..f17980a83d8 100644 --- a/app/workers/object_storage_upload_worker.rb +++ b/app/workers/object_storage_upload_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # @Deprecated - remove once the `object_storage_upload` queue is empty # The queue has been renamed `object_storage:object_storage_background_upload` # diff --git a/app/workers/pages_domain_verification_cron_worker.rb b/app/workers/pages_domain_verification_cron_worker.rb index a3ff4bd2101..92d62a15aee 100644 --- a/app/workers/pages_domain_verification_cron_worker.rb +++ b/app/workers/pages_domain_verification_cron_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class PagesDomainVerificationCronWorker include ApplicationWorker include CronjobQueue diff --git a/app/workers/pages_domain_verification_worker.rb b/app/workers/pages_domain_verification_worker.rb index 2e93489113c..4610b688189 100644 --- a/app/workers/pages_domain_verification_worker.rb +++ b/app/workers/pages_domain_verification_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class PagesDomainVerificationWorker include ApplicationWorker diff --git a/app/workers/pages_worker.rb b/app/workers/pages_worker.rb index 66a0ff83bef..13a6576a301 100644 --- a/app/workers/pages_worker.rb +++ b/app/workers/pages_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class PagesWorker include ApplicationWorker diff --git a/app/workers/pipeline_hooks_worker.rb b/app/workers/pipeline_hooks_worker.rb index c94918ff4ee..58023e0af1b 100644 --- a/app/workers/pipeline_hooks_worker.rb +++ b/app/workers/pipeline_hooks_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class PipelineHooksWorker include ApplicationWorker include PipelineQueue diff --git a/app/workers/pipeline_metrics_worker.rb b/app/workers/pipeline_metrics_worker.rb index d46d1f122fc..a97019b100a 100644 --- a/app/workers/pipeline_metrics_worker.rb +++ b/app/workers/pipeline_metrics_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class PipelineMetricsWorker include ApplicationWorker include PipelineQueue diff --git a/app/workers/pipeline_notification_worker.rb b/app/workers/pipeline_notification_worker.rb index a9a1168a6e3..3a8846b3747 100644 --- a/app/workers/pipeline_notification_worker.rb +++ b/app/workers/pipeline_notification_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class PipelineNotificationWorker include ApplicationWorker include PipelineQueue diff --git a/app/workers/pipeline_process_worker.rb b/app/workers/pipeline_process_worker.rb index 24424b3f472..83744c5338a 100644 --- a/app/workers/pipeline_process_worker.rb +++ b/app/workers/pipeline_process_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class PipelineProcessWorker include ApplicationWorker include PipelineQueue diff --git a/app/workers/pipeline_schedule_worker.rb b/app/workers/pipeline_schedule_worker.rb index c49758878a4..a1815757735 100644 --- a/app/workers/pipeline_schedule_worker.rb +++ b/app/workers/pipeline_schedule_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class PipelineScheduleWorker include ApplicationWorker include CronjobQueue diff --git a/app/workers/pipeline_success_worker.rb b/app/workers/pipeline_success_worker.rb index 2ab0739a17f..68e9af6a619 100644 --- a/app/workers/pipeline_success_worker.rb +++ b/app/workers/pipeline_success_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class PipelineSuccessWorker include ApplicationWorker include PipelineQueue diff --git a/app/workers/pipeline_update_worker.rb b/app/workers/pipeline_update_worker.rb index fc9da2d45b1..c33468c1f14 100644 --- a/app/workers/pipeline_update_worker.rb +++ b/app/workers/pipeline_update_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class PipelineUpdateWorker include ApplicationWorker include PipelineQueue diff --git a/app/workers/plugin_worker.rb b/app/workers/plugin_worker.rb index bfcc683d99a..c293e28be4a 100644 --- a/app/workers/plugin_worker.rb +++ b/app/workers/plugin_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class PluginWorker include ApplicationWorker diff --git a/app/workers/post_receive.rb b/app/workers/post_receive.rb index f88b3fdbfb1..09a594cdb4e 100644 --- a/app/workers/post_receive.rb +++ b/app/workers/post_receive.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class PostReceive include ApplicationWorker diff --git a/app/workers/process_commit_worker.rb b/app/workers/process_commit_worker.rb index 201e7f332b4..ed39b4a1ea8 100644 --- a/app/workers/process_commit_worker.rb +++ b/app/workers/process_commit_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Worker for processing individiual commit messages pushed to a repository. # # Jobs for this worker are scheduled for every commit that is being pushed. As a diff --git a/app/workers/project_cache_worker.rb b/app/workers/project_cache_worker.rb index a993b4b2680..b0e1d8837d9 100644 --- a/app/workers/project_cache_worker.rb +++ b/app/workers/project_cache_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Worker for updating any project specific caches. class ProjectCacheWorker include ApplicationWorker diff --git a/app/workers/project_destroy_worker.rb b/app/workers/project_destroy_worker.rb index 1ba854ca4cb..4447e867240 100644 --- a/app/workers/project_destroy_worker.rb +++ b/app/workers/project_destroy_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ProjectDestroyWorker include ApplicationWorker include ExceptionBacktrace diff --git a/app/workers/project_export_worker.rb b/app/workers/project_export_worker.rb index c3d84bb0b93..ed9da39c7c3 100644 --- a/app/workers/project_export_worker.rb +++ b/app/workers/project_export_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ProjectExportWorker include ApplicationWorker include ExceptionBacktrace diff --git a/app/workers/project_migrate_hashed_storage_worker.rb b/app/workers/project_migrate_hashed_storage_worker.rb index d01eb744e5d..9e4d66250a4 100644 --- a/app/workers/project_migrate_hashed_storage_worker.rb +++ b/app/workers/project_migrate_hashed_storage_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ProjectMigrateHashedStorageWorker include ApplicationWorker diff --git a/app/workers/project_service_worker.rb b/app/workers/project_service_worker.rb index 75c4b8b3663..a0bc9288cf0 100644 --- a/app/workers/project_service_worker.rb +++ b/app/workers/project_service_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ProjectServiceWorker include ApplicationWorker diff --git a/app/workers/propagate_service_template_worker.rb b/app/workers/propagate_service_template_worker.rb index 635a97c99af..c9da1cae255 100644 --- a/app/workers/propagate_service_template_worker.rb +++ b/app/workers/propagate_service_template_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Worker for updating any project specific caches. class PropagateServiceTemplateWorker include ApplicationWorker diff --git a/app/workers/prune_old_events_worker.rb b/app/workers/prune_old_events_worker.rb index 5ff62ab1369..c1d05ebbcfd 100644 --- a/app/workers/prune_old_events_worker.rb +++ b/app/workers/prune_old_events_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class PruneOldEventsWorker include ApplicationWorker include CronjobQueue diff --git a/app/workers/reactive_caching_worker.rb b/app/workers/reactive_caching_worker.rb index ef3ddb9024b..9b331f15dc5 100644 --- a/app/workers/reactive_caching_worker.rb +++ b/app/workers/reactive_caching_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ReactiveCachingWorker include ApplicationWorker diff --git a/app/workers/rebase_worker.rb b/app/workers/rebase_worker.rb index 090987778a2..a6baebc1443 100644 --- a/app/workers/rebase_worker.rb +++ b/app/workers/rebase_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class RebaseWorker include ApplicationWorker diff --git a/app/workers/remove_expired_group_links_worker.rb b/app/workers/remove_expired_group_links_worker.rb index 7e64c3070a8..6b8b972a440 100644 --- a/app/workers/remove_expired_group_links_worker.rb +++ b/app/workers/remove_expired_group_links_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class RemoveExpiredGroupLinksWorker include ApplicationWorker include CronjobQueue diff --git a/app/workers/remove_expired_members_worker.rb b/app/workers/remove_expired_members_worker.rb index 68960f72bf6..41913900571 100644 --- a/app/workers/remove_expired_members_worker.rb +++ b/app/workers/remove_expired_members_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class RemoveExpiredMembersWorker include ApplicationWorker include CronjobQueue diff --git a/app/workers/remove_old_web_hook_logs_worker.rb b/app/workers/remove_old_web_hook_logs_worker.rb index 87fed42d7ce..17140ac4450 100644 --- a/app/workers/remove_old_web_hook_logs_worker.rb +++ b/app/workers/remove_old_web_hook_logs_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class RemoveOldWebHookLogsWorker include ApplicationWorker include CronjobQueue diff --git a/app/workers/remove_unreferenced_lfs_objects_worker.rb b/app/workers/remove_unreferenced_lfs_objects_worker.rb index 8daf079fc31..95e7a9f537f 100644 --- a/app/workers/remove_unreferenced_lfs_objects_worker.rb +++ b/app/workers/remove_unreferenced_lfs_objects_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class RemoveUnreferencedLfsObjectsWorker include ApplicationWorker include CronjobQueue diff --git a/app/workers/repository_archive_cache_worker.rb b/app/workers/repository_archive_cache_worker.rb index 86a258cf94f..c1dff8ced90 100644 --- a/app/workers/repository_archive_cache_worker.rb +++ b/app/workers/repository_archive_cache_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class RepositoryArchiveCacheWorker include ApplicationWorker include CronjobQueue diff --git a/app/workers/repository_check/batch_worker.rb b/app/workers/repository_check/batch_worker.rb index 72f0a9b0619..898bca976ec 100644 --- a/app/workers/repository_check/batch_worker.rb +++ b/app/workers/repository_check/batch_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module RepositoryCheck class BatchWorker include ApplicationWorker diff --git a/app/workers/repository_check/clear_worker.rb b/app/workers/repository_check/clear_worker.rb index 97b89dc3db5..81e1a4b63bb 100644 --- a/app/workers/repository_check/clear_worker.rb +++ b/app/workers/repository_check/clear_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module RepositoryCheck class ClearWorker include ApplicationWorker diff --git a/app/workers/repository_check/single_repository_worker.rb b/app/workers/repository_check/single_repository_worker.rb index 3cffb8b14e4..f44e5693b25 100644 --- a/app/workers/repository_check/single_repository_worker.rb +++ b/app/workers/repository_check/single_repository_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module RepositoryCheck class SingleRepositoryWorker include ApplicationWorker diff --git a/app/workers/repository_fork_worker.rb b/app/workers/repository_fork_worker.rb index dbb215f1964..5ef9b744db3 100644 --- a/app/workers/repository_fork_worker.rb +++ b/app/workers/repository_fork_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class RepositoryForkWorker include ApplicationWorker include Gitlab::ShellAdapter diff --git a/app/workers/repository_import_worker.rb b/app/workers/repository_import_worker.rb index d79b5ee5346..25fec542ac7 100644 --- a/app/workers/repository_import_worker.rb +++ b/app/workers/repository_import_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class RepositoryImportWorker include ApplicationWorker include ExceptionBacktrace diff --git a/app/workers/repository_remove_remote_worker.rb b/app/workers/repository_remove_remote_worker.rb index 1c19b604b77..a85e9fa9394 100644 --- a/app/workers/repository_remove_remote_worker.rb +++ b/app/workers/repository_remove_remote_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class RepositoryRemoveRemoteWorker include ApplicationWorker include ExclusiveLeaseGuard diff --git a/app/workers/repository_update_remote_mirror_worker.rb b/app/workers/repository_update_remote_mirror_worker.rb index bb963979e88..9d4e67deb9c 100644 --- a/app/workers/repository_update_remote_mirror_worker.rb +++ b/app/workers/repository_update_remote_mirror_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class RepositoryUpdateRemoteMirrorWorker UpdateAlreadyInProgressError = Class.new(StandardError) UpdateError = Class.new(StandardError) diff --git a/app/workers/requests_profiles_worker.rb b/app/workers/requests_profiles_worker.rb index 55c236e9e9d..ae022d43e29 100644 --- a/app/workers/requests_profiles_worker.rb +++ b/app/workers/requests_profiles_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class RequestsProfilesWorker include ApplicationWorker include CronjobQueue diff --git a/app/workers/run_pipeline_schedule_worker.rb b/app/workers/run_pipeline_schedule_worker.rb index 8f5138fc873..1f6cb18c812 100644 --- a/app/workers/run_pipeline_schedule_worker.rb +++ b/app/workers/run_pipeline_schedule_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class RunPipelineScheduleWorker include ApplicationWorker include PipelineQueue diff --git a/app/workers/schedule_update_user_activity_worker.rb b/app/workers/schedule_update_user_activity_worker.rb index d9376577597..ff42fb8f0e5 100644 --- a/app/workers/schedule_update_user_activity_worker.rb +++ b/app/workers/schedule_update_user_activity_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ScheduleUpdateUserActivityWorker include ApplicationWorker include CronjobQueue diff --git a/app/workers/stage_update_worker.rb b/app/workers/stage_update_worker.rb index e4b683fca33..ec8c8e3689f 100644 --- a/app/workers/stage_update_worker.rb +++ b/app/workers/stage_update_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class StageUpdateWorker include ApplicationWorker include PipelineQueue diff --git a/app/workers/storage_migrator_worker.rb b/app/workers/storage_migrator_worker.rb index 0aff0c4c7c6..fa76fbac55c 100644 --- a/app/workers/storage_migrator_worker.rb +++ b/app/workers/storage_migrator_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class StorageMigratorWorker include ApplicationWorker diff --git a/app/workers/stuck_ci_jobs_worker.rb b/app/workers/stuck_ci_jobs_worker.rb index 7ebf69bdc39..c78b7fac589 100644 --- a/app/workers/stuck_ci_jobs_worker.rb +++ b/app/workers/stuck_ci_jobs_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class StuckCiJobsWorker include ApplicationWorker include CronjobQueue diff --git a/app/workers/stuck_import_jobs_worker.rb b/app/workers/stuck_import_jobs_worker.rb index 6fdd7592e74..79ce06dd66e 100644 --- a/app/workers/stuck_import_jobs_worker.rb +++ b/app/workers/stuck_import_jobs_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class StuckImportJobsWorker include ApplicationWorker include CronjobQueue diff --git a/app/workers/stuck_merge_jobs_worker.rb b/app/workers/stuck_merge_jobs_worker.rb index 16394293c79..b0a62f76e94 100644 --- a/app/workers/stuck_merge_jobs_worker.rb +++ b/app/workers/stuck_merge_jobs_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class StuckMergeJobsWorker include ApplicationWorker include CronjobQueue diff --git a/app/workers/system_hook_push_worker.rb b/app/workers/system_hook_push_worker.rb index ceeaaf8d189..15e369ebcfb 100644 --- a/app/workers/system_hook_push_worker.rb +++ b/app/workers/system_hook_push_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class SystemHookPushWorker include ApplicationWorker diff --git a/app/workers/trending_projects_worker.rb b/app/workers/trending_projects_worker.rb index 7eb65452a7d..3297a1fe3d0 100644 --- a/app/workers/trending_projects_worker.rb +++ b/app/workers/trending_projects_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class TrendingProjectsWorker include ApplicationWorker include CronjobQueue diff --git a/app/workers/update_head_pipeline_for_merge_request_worker.rb b/app/workers/update_head_pipeline_for_merge_request_worker.rb index 76f84ff920f..0487a393566 100644 --- a/app/workers/update_head_pipeline_for_merge_request_worker.rb +++ b/app/workers/update_head_pipeline_for_merge_request_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class UpdateHeadPipelineForMergeRequestWorker include ApplicationWorker include PipelineQueue diff --git a/app/workers/update_merge_requests_worker.rb b/app/workers/update_merge_requests_worker.rb index 74bb9993275..742841219b3 100644 --- a/app/workers/update_merge_requests_worker.rb +++ b/app/workers/update_merge_requests_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class UpdateMergeRequestsWorker include ApplicationWorker diff --git a/app/workers/update_user_activity_worker.rb b/app/workers/update_user_activity_worker.rb index 27ec5cd33fb..15f01a70337 100644 --- a/app/workers/update_user_activity_worker.rb +++ b/app/workers/update_user_activity_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class UpdateUserActivityWorker include ApplicationWorker diff --git a/app/workers/upload_checksum_worker.rb b/app/workers/upload_checksum_worker.rb index 65d40336f18..2a0536106d7 100644 --- a/app/workers/upload_checksum_worker.rb +++ b/app/workers/upload_checksum_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class UploadChecksumWorker include ApplicationWorker diff --git a/app/workers/wait_for_cluster_creation_worker.rb b/app/workers/wait_for_cluster_creation_worker.rb index 19cdb279aaa..8aa1d9290fd 100644 --- a/app/workers/wait_for_cluster_creation_worker.rb +++ b/app/workers/wait_for_cluster_creation_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class WaitForClusterCreationWorker include ApplicationWorker include ClusterQueue diff --git a/app/workers/web_hook_worker.rb b/app/workers/web_hook_worker.rb index dfc3f33ad9d..09219a24a16 100644 --- a/app/workers/web_hook_worker.rb +++ b/app/workers/web_hook_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class WebHookWorker include ApplicationWorker diff --git a/changelogs/unreleased/40484-ordered-lists-copy-gfm.yml b/changelogs/unreleased/40484-ordered-lists-copy-gfm.yml new file mode 100644 index 00000000000..f4b34909ae9 --- /dev/null +++ b/changelogs/unreleased/40484-ordered-lists-copy-gfm.yml @@ -0,0 +1,5 @@ +--- +title: Keep lists ordered when copying only list items +merge_request: 18522 +author: Jan Beckmann +type: fixed diff --git a/changelogs/unreleased/46546-do-not-pre-select-previous-user-s-when-creating-protected-branches.yml b/changelogs/unreleased/46546-do-not-pre-select-previous-user-s-when-creating-protected-branches.yml new file mode 100644 index 00000000000..7d42d971022 --- /dev/null +++ b/changelogs/unreleased/46546-do-not-pre-select-previous-user-s-when-creating-protected-branches.yml @@ -0,0 +1,5 @@ +--- +title: CE port gitlab-ee!6112 +merge_request: 19714 +author: +type: other diff --git a/changelogs/unreleased/48461-search-dropdown-hides-shows-when-typing.yml b/changelogs/unreleased/48461-search-dropdown-hides-shows-when-typing.yml new file mode 100644 index 00000000000..2ebc22dbf8f --- /dev/null +++ b/changelogs/unreleased/48461-search-dropdown-hides-shows-when-typing.yml @@ -0,0 +1,5 @@ +--- +title: Fix loading screen for search autocomplete dropdown +merge_request: +author: +type: fixed diff --git a/changelogs/unreleased/48528-fix-mr-autocompletion.yml b/changelogs/unreleased/48528-fix-mr-autocompletion.yml new file mode 100644 index 00000000000..ac44f878d1d --- /dev/null +++ b/changelogs/unreleased/48528-fix-mr-autocompletion.yml @@ -0,0 +1,5 @@ +--- +title: Fix broken '!' support to autocomplete MRs in GFM fields +merge_request: 20204 +author: +type: fixed diff --git a/changelogs/unreleased/frozen-string-app-workers.yml b/changelogs/unreleased/frozen-string-app-workers.yml new file mode 100644 index 00000000000..48b50cc6ca4 --- /dev/null +++ b/changelogs/unreleased/frozen-string-app-workers.yml @@ -0,0 +1,5 @@ +--- +title: Enable frozen string in app/workers/*.rb +merge_request: 19944 +author: gfyoung +type: other diff --git a/changelogs/unreleased/frozen-string-enable-app-workers-2.yml b/changelogs/unreleased/frozen-string-enable-app-workers-2.yml new file mode 100644 index 00000000000..81de6899d76 --- /dev/null +++ b/changelogs/unreleased/frozen-string-enable-app-workers-2.yml @@ -0,0 +1,5 @@ +--- +title: Finish enabling frozen string for app/workers/*.rb +merge_request: 20197 +author: gfyoung +type: other diff --git a/changelogs/unreleased/zj-gitaly-read-write-check.yml b/changelogs/unreleased/zj-gitaly-read-write-check.yml new file mode 100644 index 00000000000..43951d20e8f --- /dev/null +++ b/changelogs/unreleased/zj-gitaly-read-write-check.yml @@ -0,0 +1,5 @@ +--- +title: Gitaly metrics check for read/writeability +merge_request: 20022 +author: +type: other diff --git a/doc/administration/repository_storage_types.md b/doc/administration/repository_storage_types.md index 39bd19ac851..087fe729b28 100644 --- a/doc/administration/repository_storage_types.md +++ b/doc/administration/repository_storage_types.md @@ -82,6 +82,46 @@ To migrate your existing projects to the new storage type, check the specific [rake tasks]: raketasks/storage.md#migrate-existing-projects-to-hashed-storage [storage-paths]: repository_storage_types.md +#### Rollback + +There is no automated rollback implemented. Below are the steps required to rollback +from each storage migration. + +The rollback has to be performed in the reverse order. To get into "Legacy" state, +you need to rollback Attachments first, then Project. + +Also note that if Geo is enabled, after the migration was triggered, an event is generated +to replicate the operation on any Secondary node. That means the on disk changes will also +need to be performed on these nodes as well. Database changes will propagate without issues. + +You must make sure the migration event was already processed or otherwise it may migrate +the files back to Hashed state again. + +##### Attachments + +To rollback single Attachment migration, rename `aa/bb/abcdef1234567890...` folder back to `namespace/project`. + +Both folder names can be generated by the `FileUploader.absolute_base_dir(project)`, you +just need to switch the version from the `project` back to the previous one. + +```ruby +project.storage_version +# => 2 + +FileUploader.absolute_base_dir(project) +# => "/opt/gitlab/embedded/service/gitlab-rails/public/uploads/@hashed/d4/73/d4735e3a265e16eee03f59718b9b5d03019c07d8b6c51f90da3a666eec13ab35" + +project.storage_version = 1 + +FileUploader.absolute_base_dir(project) +# => "/opt/gitlab/embedded/service/gitlab-rails/public/uploads/gitlab/gitlab-shell-renamed" +``` + +##### Project + +To rollback single Project migration, move `@hashed/aa/bb/aabbcdef1234567890abcdef.git` and `@hashed/aa/bb/aabbcdef1234567890abcdef.wiki.git` +back to `namespace/project.git` and `namespace/project.wiki.git` respectively and switch the version from the `project` back to `null`. + ### Hashed Storage coverage We are incrementally moving every storable object in GitLab to the Hashed @@ -100,6 +140,30 @@ which is true for CI Cache and LFS Objects. | Pages | Yes | No | - | - | | Docker Registry | Yes | No | - | - | | CI Build Logs | No | No | - | - | -| CI Artifacts | No | No | Yes (Premium) | - | +| CI Artifacts | No | No | Yes | 9.4 / 10.6 | | CI Cache | No | No | Yes | - | -| LFS Objects | Yes | No | Yes (Premium) | - | +| LFS Objects | Yes | Similar | Yes | 10.0 / 10.7 | + +#### Implementation Details + +##### Avatars + +Each file is stored in a folder with its `id` from the database. The filename is always `avatar.png` for user avatars. +When avatar is replaced, `Upload` model is destroyed and a new one takes place with different `id`. + +##### CI Artifacts + +CI Artifacts are S3 compatible since **9.4** (GitLab Premium), and available in GitLab Core since **10.6**. + +##### LFS Objects + +LFS Objects implements a similar storage pattern using 2 chars, 2 level folders, following git own implementation: + +```ruby +"shared/lfs-objects/#{oid[0..1}/#{oid[2..3]}/#{oid[4..-1]}" + +# Based on object `oid`: `8909029eb962194cfb326259411b22ae3f4a814b5be4f80651735aeef9f3229c`, path will be: +"shared/lfs-objects/89/09/029eb962194cfb326259411b22ae3f4a814b5be4f80651735aeef9f3229c" +``` + +They are also S3 compatible since **10.0** (GitLab Premium), and available in GitLab Core since **10.7**. diff --git a/lib/gitaly/server.rb b/lib/gitaly/server.rb index 605e93022e7..2760211fee8 100644 --- a/lib/gitaly/server.rb +++ b/lib/gitaly/server.rb @@ -22,6 +22,18 @@ module Gitaly server_version == Gitlab::GitalyClient.expected_server_version end + def read_writeable? + readable? && writeable? + end + + def readable? + storage_status&.readable + end + + def writeable? + storage_status&.writeable + end + def address Gitlab::GitalyClient.address(@storage) rescue RuntimeError => e @@ -30,13 +42,17 @@ module Gitaly private + def storage_status + @storage_status ||= info.storage_statuses.find { |s| s.storage_name == storage } + end + def info @info ||= begin Gitlab::GitalyClient::ServerService.new(@storage).info rescue GRPC::Unavailable, GRPC::GRPC::DeadlineExceeded # This will show the server as being out of date - Gitaly::ServerInfoResponse.new(git_version: '', server_version: '') + Gitaly::ServerInfoResponse.new(git_version: '', server_version: '', storage_statuses: []) end end end diff --git a/lib/gitlab/git/commit.rb b/lib/gitlab/git/commit.rb index 341768752dc..74240cedc9d 100644 --- a/lib/gitlab/git/commit.rb +++ b/lib/gitlab/git/commit.rb @@ -493,13 +493,18 @@ module Gitlab def tree_entry(path) return unless path.present? - @repository.gitaly_migrate(:commit_tree_entry) do |is_migrated| - if is_migrated - gitaly_tree_entry(path) - else - rugged_tree_entry(path) - end - end + # We're only interested in metadata, so limit actual data to 1 byte + # since Gitaly doesn't support "send no data" option. + entry = @repository.gitaly_commit_client.tree_entry(id, path, 1) + return unless entry + + # To be compatible with the rugged format + entry = entry.to_h + entry.delete(:data) + entry[:name] = File.basename(path) + entry[:type] = entry[:type].downcase + + entry end def to_gitaly_commit @@ -562,28 +567,6 @@ module Gitlab SERIALIZE_KEYS end - def gitaly_tree_entry(path) - # We're only interested in metadata, so limit actual data to 1 byte - # since Gitaly doesn't support "send no data" option. - entry = @repository.gitaly_commit_client.tree_entry(id, path, 1) - return unless entry - - # To be compatible with the rugged format - entry = entry.to_h - entry.delete(:data) - entry[:name] = File.basename(path) - entry[:type] = entry[:type].downcase - - entry - end - - # Is this the same as Blob.find_entry_by_path ? - def rugged_tree_entry(path) - rugged_commit.tree.path(path) - rescue Rugged::TreeError - nil - end - def gitaly_commit_author_from_rugged(author_or_committer) Gitaly::CommitAuthor.new( name: author_or_committer[:name].b, diff --git a/lib/gitlab/gitaly_client/commit_service.rb b/lib/gitlab/gitaly_client/commit_service.rb index 7f2e6441f16..077297b9d6d 100644 --- a/lib/gitlab/gitaly_client/commit_service.rb +++ b/lib/gitlab/gitaly_client/commit_service.rb @@ -76,6 +76,13 @@ module Gitlab end def tree_entry(ref, path, limit = nil) + if Pathname.new(path).cleanpath.to_s.start_with?('../') + # The TreeEntry RPC should return an empty reponse in this case but in + # Gitaly 0.107.0 and earlier we get an exception instead. This early return + # saves us a Gitaly roundtrip while also avoiding the exception. + return + end + request = Gitaly::TreeEntryRequest.new( repository: @gitaly_repo, revision: encode_binary(ref), diff --git a/lib/gitlab/health_checks/fs_shards_check.rb b/lib/gitlab/health_checks/fs_shards_check.rb deleted file mode 100644 index 050fe7a5173..00000000000 --- a/lib/gitlab/health_checks/fs_shards_check.rb +++ /dev/null @@ -1,169 +0,0 @@ -module Gitlab - module HealthChecks - # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/1218 - class FsShardsCheck - extend BaseAbstractCheck - RANDOM_STRING = SecureRandom.hex(1000).freeze - COMMAND_TIMEOUT = '1'.freeze - TIMEOUT_EXECUTABLE = 'timeout'.freeze - - class << self - def readiness - repository_storages.map do |storage_name| - begin - if !storage_circuitbreaker_test(storage_name) - HealthChecks::Result.new(false, 'circuitbreaker tripped', shard: storage_name) - elsif !storage_stat_test(storage_name) - HealthChecks::Result.new(false, 'cannot stat storage', shard: storage_name) - else - with_temp_file(storage_name) do |tmp_file_path| - if !storage_write_test(tmp_file_path) - HealthChecks::Result.new(false, 'cannot write to storage', shard: storage_name) - elsif !storage_read_test(tmp_file_path) - HealthChecks::Result.new(false, 'cannot read from storage', shard: storage_name) - else - HealthChecks::Result.new(true, nil, shard: storage_name) - end - end - end - rescue RuntimeError => ex - message = "unexpected error #{ex} when checking storage #{storage_name}" - Rails.logger.error(message) - HealthChecks::Result.new(false, message, shard: storage_name) - end - end - end - - def metrics - repository_storages.flat_map do |storage_name| - [ - storage_stat_metrics(storage_name), - storage_write_metrics(storage_name), - storage_read_metrics(storage_name), - storage_circuitbreaker_metrics(storage_name) - ].flatten - end - end - - private - - def operation_metrics(ok_metric, latency_metric, **labels) - result, elapsed = yield - [ - metric(latency_metric, elapsed, **labels), - metric(ok_metric, result ? 1 : 0, **labels) - ] - rescue RuntimeError => ex - Rails.logger.error("unexpected error #{ex} when checking #{ok_metric}") - [metric(ok_metric, 0, **labels)] - end - - def repository_storages - storages_paths.keys - end - - def storages_paths - Gitlab.config.repositories.storages - end - - def exec_with_timeout(cmd_args, *args, &block) - Gitlab::Popen.popen([TIMEOUT_EXECUTABLE, COMMAND_TIMEOUT].concat(cmd_args), *args, &block) - end - - def with_temp_file(storage_name) - temp_file_path = Dir::Tmpname.create(%w(fs_shards_check +deleted), storage_path(storage_name)) { |path| path } - yield temp_file_path - ensure - delete_test_file(temp_file_path) - end - - def storage_path(storage_name) - Gitlab::GitalyClient::StorageSettings.allow_disk_access do - storages_paths[storage_name]&.legacy_disk_path - end - end - - # All below test methods use shell commands to perform actions on storage volumes. - # In case a storage volume have connectivity problems causing pure Ruby IO operation to wait indefinitely, - # we can rely on shell commands to be terminated once `timeout` kills them. - # - # However we also fallback to pure Ruby file operations in case a specific shell command is missing - # so we are still able to perform healthchecks and gather metrics from such system. - - def delete_test_file(tmp_path) - _, status = exec_with_timeout(%W{ rm -f #{tmp_path} }) - status.zero? - rescue Errno::ENOENT - File.delete(tmp_path) rescue Errno::ENOENT - end - - def storage_stat_test(storage_name) - stat_path = File.join(storage_path(storage_name), '.') - begin - _, status = exec_with_timeout(%W{ stat #{stat_path} }) - status.zero? - rescue Errno::ENOENT - File.exist?(stat_path) && File::Stat.new(stat_path).readable? - end - end - - def storage_write_test(tmp_path) - _, status = exec_with_timeout(%W{ tee #{tmp_path} }) do |stdin| - stdin.write(RANDOM_STRING) - end - status.zero? - rescue Errno::ENOENT - written_bytes = File.write(tmp_path, RANDOM_STRING) rescue Errno::ENOENT - written_bytes == RANDOM_STRING.length - end - - def storage_read_test(tmp_path) - _, status = exec_with_timeout(%W{ diff #{tmp_path} - }) do |stdin| - stdin.write(RANDOM_STRING) - end - status.zero? - rescue Errno::ENOENT - file_contents = File.read(tmp_path) rescue Errno::ENOENT - file_contents == RANDOM_STRING - end - - def storage_circuitbreaker_test(storage_name) - Gitlab::Git::Storage::CircuitBreaker.build(storage_name).perform { "OK" } - rescue Gitlab::Git::Storage::Inaccessible - nil - end - - def storage_stat_metrics(storage_name) - operation_metrics(:filesystem_accessible, :filesystem_access_latency_seconds, shard: storage_name) do - with_timing { storage_stat_test(storage_name) } - end - end - - def storage_write_metrics(storage_name) - operation_metrics(:filesystem_writable, :filesystem_write_latency_seconds, shard: storage_name) do - with_temp_file(storage_name) do |tmp_file_path| - with_timing { storage_write_test(tmp_file_path) } - end - end - end - - def storage_read_metrics(storage_name) - operation_metrics(:filesystem_readable, :filesystem_read_latency_seconds, shard: storage_name) do - with_temp_file(storage_name) do |tmp_file_path| - storage_write_test(tmp_file_path) # writes data used by read test - with_timing { storage_read_test(tmp_file_path) } - end - end - end - - def storage_circuitbreaker_metrics(storage_name) - operation_metrics(:filesystem_circuitbreaker, - :filesystem_circuitbreaker_latency_seconds, - shard: storage_name) do - with_timing { storage_circuitbreaker_test(storage_name) } - end - end - end - end - end -end diff --git a/lib/gitlab/health_checks/gitaly_check.rb b/lib/gitlab/health_checks/gitaly_check.rb index 11416c002e3..1f623e0b6ec 100644 --- a/lib/gitlab/health_checks/gitaly_check.rb +++ b/lib/gitlab/health_checks/gitaly_check.rb @@ -13,14 +13,14 @@ module Gitlab end def metrics - repository_storages.flat_map do |storage_name| - result, elapsed = with_timing { check(storage_name) } - labels = { shard: storage_name } + Gitaly::Server.all.flat_map do |server| + result, elapsed = with_timing { server.read_writeable? } + labels = { shard: server.storage } [ - metric("#{metric_prefix}_success", successful?(result) ? 1 : 0, **labels), + metric("#{metric_prefix}_success", result ? 1 : 0, **labels), metric("#{metric_prefix}_latency_seconds", elapsed, **labels) - ].flatten + ] end end @@ -36,10 +36,6 @@ module Gitlab METRIC_PREFIX end - def successful?(result) - result[:success] - end - def repository_storages storages.keys end diff --git a/spec/controllers/health_controller_spec.rb b/spec/controllers/health_controller_spec.rb index 542eddc2d16..d800ad7c187 100644 --- a/spec/controllers/health_controller_spec.rb +++ b/spec/controllers/health_controller_spec.rb @@ -69,8 +69,7 @@ describe HealthController do expect(json_response['cache_check']['status']).to eq('ok') expect(json_response['queues_check']['status']).to eq('ok') expect(json_response['shared_state_check']['status']).to eq('ok') - expect(json_response['fs_shards_check']['status']).to eq('ok') - expect(json_response['fs_shards_check']['labels']['shard']).to eq('default') + expect(json_response['gitaly_check']['status']).to eq('ok') end end @@ -122,7 +121,6 @@ describe HealthController do expect(json_response['cache_check']['status']).to eq('ok') expect(json_response['queues_check']['status']).to eq('ok') expect(json_response['shared_state_check']['status']).to eq('ok') - expect(json_response['fs_shards_check']['status']).to eq('ok') end end diff --git a/spec/controllers/metrics_controller_spec.rb b/spec/controllers/metrics_controller_spec.rb index 9e8a37171ec..7376841fac8 100644 --- a/spec/controllers/metrics_controller_spec.rb +++ b/spec/controllers/metrics_controller_spec.rb @@ -59,6 +59,13 @@ describe MetricsController do expect(response.body).to match(/^redis_shared_state_ping_latency_seconds [0-9\.]+$/) end + it 'returns Gitaly metrics' do + get :index + + expect(response.body).to match(/^gitaly_health_check_success{shard="default"} 1$/) + expect(response.body).to match(/^gitaly_health_check_latency_seconds{shard="default"} [0-9\.]+$/) + end + context 'prometheus metrics are disabled' do before do allow(Gitlab::Metrics).to receive(:prometheus_metrics_enabled?).and_return(false) diff --git a/spec/features/protected_branches_spec.rb b/spec/features/protected_branches_spec.rb index 4c0f9971425..39bd4af6cd0 100644 --- a/spec/features/protected_branches_spec.rb +++ b/spec/features/protected_branches_spec.rb @@ -60,33 +60,6 @@ feature 'Protected Branches', :js do expect(page).to have_content('No branches to show') end end - - describe "Saved defaults" do - it "keeps the allowed to merge and push dropdowns defaults based on the previous selection" do - visit project_protected_branches_path(project) - form = '.js-new-protected-branch' - - within form do - find(".js-allowed-to-merge").click - wait_for_requests - click_link 'No one' - find(".js-allowed-to-push").click - wait_for_requests - click_link 'Developers + Maintainers' - end - - visit project_protected_branches_path(project) - - within form do - page.within(".js-allowed-to-merge") do - expect(page.find(".dropdown-toggle-text")).to have_content("No one") - end - page.within(".js-allowed-to-push") do - expect(page.find(".dropdown-toggle-text")).to have_content("Developers + Maintainers") - end - end - end - end end context 'logged in as admin' do @@ -97,6 +70,7 @@ feature 'Protected Branches', :js do describe "explicit protected branches" do it "allows creating explicit protected branches" do visit project_protected_branches_path(project) + set_defaults set_protected_branch_name('some-branch') click_on "Protect" @@ -110,6 +84,7 @@ feature 'Protected Branches', :js do project.repository.add_branch(admin, 'some-branch', commit.id) visit project_protected_branches_path(project) + set_defaults set_protected_branch_name('some-branch') click_on "Protect" @@ -118,6 +93,7 @@ feature 'Protected Branches', :js do it "displays an error message if the named branch does not exist" do visit project_protected_branches_path(project) + set_defaults set_protected_branch_name('some-branch') click_on "Protect" @@ -128,6 +104,7 @@ feature 'Protected Branches', :js do describe "wildcard protected branches" do it "allows creating protected branches with a wildcard" do visit project_protected_branches_path(project) + set_defaults set_protected_branch_name('*-stable') click_on "Protect" @@ -141,6 +118,7 @@ feature 'Protected Branches', :js do project.repository.add_branch(admin, 'staging-stable', 'master') visit project_protected_branches_path(project) + set_defaults set_protected_branch_name('*-stable') click_on "Protect" @@ -157,6 +135,7 @@ feature 'Protected Branches', :js do visit project_protected_branches_path(project) set_protected_branch_name('*-stable') + set_defaults click_on "Protect" visit project_protected_branches_path(project) @@ -180,4 +159,18 @@ feature 'Protected Branches', :js do find(".dropdown-input-field").set(branch_name) click_on("Create wildcard #{branch_name}") end + + def set_defaults + find(".js-allowed-to-merge").click + within('.qa-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 + expect(first("li")).to have_content("Roles") + find(:link, 'No one').click + end + end end diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb index 593b2ca1825..14297a1a544 100644 --- a/spec/helpers/application_helper_spec.rb +++ b/spec/helpers/application_helper_spec.rb @@ -157,7 +157,7 @@ describe ApplicationHelper do let(:noteable_type) { Issue } it 'returns paths for autocomplete_sources_controller' do sources = helper.autocomplete_data_sources(project, noteable_type) - expect(sources.keys).to match_array([:members, :issues, :merge_requests, :labels, :milestones, :commands]) + expect(sources.keys).to match_array([:members, :issues, :mergeRequests, :labels, :milestones, :commands]) sources.keys.each do |key| expect(sources[key]).not_to be_nil end diff --git a/spec/javascripts/behaviors/copy_as_gfm_spec.js b/spec/javascripts/behaviors/copy_as_gfm_spec.js index efbe09a10a2..c2db81c6ce4 100644 --- a/spec/javascripts/behaviors/copy_as_gfm_spec.js +++ b/spec/javascripts/behaviors/copy_as_gfm_spec.js @@ -44,4 +44,59 @@ describe('CopyAsGFM', () => { callPasteGFM(); }); }); + + describe('CopyAsGFM.copyGFM', () => { + // Stub getSelection to return a purpose-built object. + const stubSelection = (html, parentNode) => ({ + getRangeAt: () => ({ + commonAncestorContainer: { tagName: parentNode }, + cloneContents: () => { + const fragment = document.createDocumentFragment(); + const node = document.createElement('div'); + node.innerHTML = html; + Array.from(node.childNodes).forEach((item) => fragment.appendChild(item)); + return fragment; + }, + }), + rangeCount: 1, + }); + + const clipboardData = { + setData() {}, + }; + + const simulateCopy = () => { + const e = { + originalEvent: { + clipboardData, + }, + preventDefault() {}, + stopPropagation() {}, + }; + CopyAsGFM.copyAsGFM(e, CopyAsGFM.transformGFMSelection); + return clipboardData; + }; + + beforeEach(() => spyOn(clipboardData, 'setData')); + + describe('list handling', () => { + it('uses correct gfm for unordered lists', () => { + const selection = stubSelection('List Item1List Item2\n', 'UL'); + spyOn(window, 'getSelection').and.returnValue(selection); + simulateCopy(); + + const expectedGFM = '- List Item1\n- List Item2'; + expect(clipboardData.setData).toHaveBeenCalledWith('text/x-gfm', expectedGFM); + }); + + it('uses correct gfm for ordered lists', () => { + const selection = stubSelection('List Item1List Item2\n', 'OL'); + spyOn(window, 'getSelection').and.returnValue(selection); + simulateCopy(); + + const expectedGFM = '1. List Item1\n1. List Item2'; + expect(clipboardData.setData).toHaveBeenCalledWith('text/x-gfm', expectedGFM); + }); + }); + }); }); diff --git a/spec/javascripts/boards/issue_card_spec.js b/spec/javascripts/boards/issue_card_spec.js index 05acf903933..72e961c8a10 100644 --- a/spec/javascripts/boards/issue_card_spec.js +++ b/spec/javascripts/boards/issue_card_spec.js @@ -9,7 +9,7 @@ import '~/vue_shared/models/assignee'; import '~/boards/models/issue'; import '~/boards/models/list'; import '~/boards/stores/boards_store'; -import '~/boards/components/issue_card_inner'; +import IssueCardInner from '~/boards/components/issue_card_inner.vue'; import { listObj } from './mock_data'; describe('Issue card component', () => { @@ -48,7 +48,7 @@ describe('Issue card component', () => { component = new Vue({ el: document.querySelector('.test-container'), components: { - 'issue-card': gl.issueBoards.IssueCardInner, + 'issue-card': IssueCardInner, }, data() { return { diff --git a/spec/lib/gitaly/server_spec.rb b/spec/lib/gitaly/server_spec.rb index ed5d56e91d4..09bf21b5946 100644 --- a/spec/lib/gitaly/server_spec.rb +++ b/spec/lib/gitaly/server_spec.rb @@ -1,6 +1,8 @@ require 'spec_helper' describe Gitaly::Server do + let(:server) { described_class.new('default') } + describe '.all' do let(:storages) { Gitlab.config.repositories.storages } @@ -17,6 +19,38 @@ describe Gitaly::Server do it { is_expected.to respond_to(:up_to_date?) } it { is_expected.to respond_to(:address) } + describe 'readable?' do + context 'when the storage is readable' do + it 'returns true' do + expect(server).to be_readable + end + end + + context 'when the storage is not readable' do + let(:server) { described_class.new('broken') } + + it 'returns false' do + expect(server).not_to be_readable + end + end + end + + describe 'writeable?' do + context 'when the storage is writeable' do + it 'returns true' do + expect(server).to be_writeable + end + end + + context 'when the storage is not writeable' do + let(:server) { described_class.new('broken') } + + it 'returns false' do + expect(server).not_to be_writeable + end + end + end + describe 'request memoization' do context 'when requesting multiple properties', :request_store do it 'uses memoization for the info request' do diff --git a/spec/lib/gitlab/health_checks/fs_shards_check_spec.rb b/spec/lib/gitlab/health_checks/fs_shards_check_spec.rb deleted file mode 100644 index 9dcf272d25e..00000000000 --- a/spec/lib/gitlab/health_checks/fs_shards_check_spec.rb +++ /dev/null @@ -1,200 +0,0 @@ -require 'spec_helper' - -describe Gitlab::HealthChecks::FsShardsCheck do - def command_exists?(command) - _, status = Gitlab::Popen.popen(%W{ #{command} 1 echo }) - status.zero? - rescue Errno::ENOENT - false - end - - def timeout_command - @timeout_command ||= - if command_exists?('timeout') - 'timeout' - elsif command_exists?('gtimeout') - 'gtimeout' - else - '' - end - end - - let(:metric_class) { Gitlab::HealthChecks::Metric } - let(:result_class) { Gitlab::HealthChecks::Result } - let(:repository_storages) { ['default'] } - let(:tmp_dir) { Dir.mktmpdir } - - let(:storages_paths) do - { - default: Gitlab::GitalyClient::StorageSettings.new('path' => tmp_dir) - }.with_indifferent_access - end - - before do - allow(described_class).to receive(:repository_storages) { repository_storages } - allow(described_class).to receive(:storages_paths) { storages_paths } - stub_const('Gitlab::HealthChecks::FsShardsCheck::TIMEOUT_EXECUTABLE', timeout_command) - end - - after do - FileUtils.remove_entry_secure(tmp_dir) if Dir.exist?(tmp_dir) - end - - shared_examples 'filesystem checks' do - describe '#readiness' do - subject { described_class.readiness } - - context 'storage has a tripped circuitbreaker', :broken_storage do - let(:repository_storages) { ['broken'] } - let(:storages_paths) do - Gitlab.config.repositories.storages - end - - it { is_expected.to include(result_class.new(false, 'circuitbreaker tripped', shard: 'broken')) } - end - - context 'storage points to not existing folder' do - let(:storages_paths) do - { - default: Gitlab::GitalyClient::StorageSettings.new('path' => 'tmp/this/path/doesnt/exist') - }.with_indifferent_access - end - - before do - allow(described_class).to receive(:storage_circuitbreaker_test) { true } - end - - it { is_expected.to include(result_class.new(false, 'cannot stat storage', shard: 'default')) } - end - - context 'storage points to directory that has both read and write rights' do - before do - FileUtils.chmod_R(0755, tmp_dir) - end - - it { is_expected.to include(result_class.new(true, nil, shard: 'default')) } - - it 'cleans up files used for testing' do - expect(described_class).to receive(:storage_write_test).with(any_args).and_call_original - - expect { subject }.not_to change(Dir.entries(tmp_dir), :count) - end - - context 'read test fails' do - before do - allow(described_class).to receive(:storage_read_test).with(any_args).and_return(false) - end - - it { is_expected.to include(result_class.new(false, 'cannot read from storage', shard: 'default')) } - end - - context 'write test fails' do - before do - allow(described_class).to receive(:storage_write_test).with(any_args).and_return(false) - end - - it { is_expected.to include(result_class.new(false, 'cannot write to storage', shard: 'default')) } - end - end - end - - describe '#metrics' do - context 'storage points to not existing folder' do - let(:storages_paths) do - { - default: Gitlab::GitalyClient::StorageSettings.new('path' => 'tmp/this/path/doesnt/exist') - }.with_indifferent_access - end - - it 'provides metrics' do - metrics = described_class.metrics - - expect(metrics).to all(have_attributes(labels: { shard: 'default' })) - expect(metrics).to include(an_object_having_attributes(name: :filesystem_accessible, value: 0)) - expect(metrics).to include(an_object_having_attributes(name: :filesystem_readable, value: 0)) - expect(metrics).to include(an_object_having_attributes(name: :filesystem_writable, value: 0)) - expect(metrics).to include(an_object_having_attributes(name: :filesystem_access_latency_seconds, value: be >= 0)) - expect(metrics).to include(an_object_having_attributes(name: :filesystem_read_latency_seconds, value: be >= 0)) - expect(metrics).to include(an_object_having_attributes(name: :filesystem_write_latency_seconds, value: be >= 0)) - expect(metrics).to include(an_object_having_attributes(name: :filesystem_circuitbreaker_latency_seconds, value: be >= 0)) - end - end - - context 'storage points to directory that has both read and write rights' do - before do - FileUtils.chmod_R(0755, tmp_dir) - end - - it 'provides metrics' do - metrics = described_class.metrics - - expect(metrics).to all(have_attributes(labels: { shard: 'default' })) - expect(metrics).to include(an_object_having_attributes(name: :filesystem_accessible, value: 1)) - expect(metrics).to include(an_object_having_attributes(name: :filesystem_readable, value: 1)) - expect(metrics).to include(an_object_having_attributes(name: :filesystem_writable, value: 1)) - expect(metrics).to include(an_object_having_attributes(name: :filesystem_access_latency_seconds, value: be >= 0)) - expect(metrics).to include(an_object_having_attributes(name: :filesystem_read_latency_seconds, value: be >= 0)) - expect(metrics).to include(an_object_having_attributes(name: :filesystem_write_latency_seconds, value: be >= 0)) - expect(metrics).to include(an_object_having_attributes(name: :filesystem_circuitbreaker_latency_seconds, value: be >= 0)) - end - - it 'cleans up files used for metrics' do - expect { described_class.metrics }.not_to change(Dir.entries(tmp_dir), :count) - end - end - end - end - - context 'when timeout kills fs checks' do - before do - stub_const('Gitlab::HealthChecks::FsShardsCheck::COMMAND_TIMEOUT', '1') - - allow(described_class).to receive(:exec_with_timeout).and_wrap_original { |m| m.call(%w(sleep 60)) } - FileUtils.chmod_R(0755, tmp_dir) - end - - describe '#readiness' do - subject { described_class.readiness } - - it { is_expected.to include(result_class.new(false, 'cannot stat storage', shard: 'default')) } - end - - describe '#metrics' do - it 'provides metrics' do - metrics = described_class.metrics - - expect(metrics).to all(have_attributes(labels: { shard: 'default' })) - expect(metrics).to include(an_object_having_attributes(name: :filesystem_accessible, value: 0)) - expect(metrics).to include(an_object_having_attributes(name: :filesystem_readable, value: 0)) - expect(metrics).to include(an_object_having_attributes(name: :filesystem_writable, value: 0)) - expect(metrics).to include(an_object_having_attributes(name: :filesystem_access_latency_seconds, value: be >= 0)) - expect(metrics).to include(an_object_having_attributes(name: :filesystem_read_latency_seconds, value: be >= 0)) - expect(metrics).to include(an_object_having_attributes(name: :filesystem_write_latency_seconds, value: be >= 0)) - end - end - end - - context 'when popen always finds required binaries' do - before do - allow(described_class).to receive(:exec_with_timeout).and_wrap_original do |method, *args, &block| - begin - method.call(*args, &block) - rescue RuntimeError, Errno::ENOENT - raise 'expected not to happen' - end - end - - stub_const('Gitlab::HealthChecks::FsShardsCheck::COMMAND_TIMEOUT', '10') - end - - it_behaves_like 'filesystem checks' - end - - context 'when popen never finds required binaries' do - before do - allow(Gitlab::Popen).to receive(:popen).and_raise(Errno::ENOENT) - end - - it_behaves_like 'filesystem checks' - end -end diff --git a/spec/lib/gitlab/health_checks/gitaly_check_spec.rb b/spec/lib/gitlab/health_checks/gitaly_check_spec.rb index 724beefff69..4912cd48761 100644 --- a/spec/lib/gitlab/health_checks/gitaly_check_spec.rb +++ b/spec/lib/gitlab/health_checks/gitaly_check_spec.rb @@ -30,13 +30,14 @@ describe Gitlab::HealthChecks::GitalyCheck do describe '#metrics' do subject { described_class.metrics } + let(:server) { double(storage: 'default', read_writeable?: up) } before do - expect(Gitlab::GitalyClient::HealthCheckService).to receive(:new).and_return(gitaly_check) + allow(Gitaly::Server).to receive(:new).and_return(server) end context 'Gitaly server is up' do - let(:gitaly_check) { double(check: { success: true }) } + let(:up) { true } it 'provides metrics' do expect(subject).to all(have_attributes(labels: { shard: 'default' })) @@ -46,7 +47,7 @@ describe Gitlab::HealthChecks::GitalyCheck do end context 'Gitaly server is down' do - let(:gitaly_check) { double(check: { success: false, message: 'Connection refused' }) } + let(:up) { false } it 'provides metrics' do expect(subject).to include(an_object_having_attributes(name: 'gitaly_health_check_success', value: 0)) diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb index 090f91168ad..5157d8fc645 100644 --- a/spec/models/commit_spec.rb +++ b/spec/models/commit_spec.rb @@ -514,30 +514,21 @@ eos end describe '#uri_type' do - shared_examples 'URI type' do - it 'returns the URI type at the given path' do - expect(commit.uri_type('files/html')).to be(:tree) - expect(commit.uri_type('files/images/logo-black.png')).to be(:raw) - expect(project.commit('video').uri_type('files/videos/intro.mp4')).to be(:raw) - expect(commit.uri_type('files/js/application.js')).to be(:blob) - end - - it "returns nil if the path doesn't exists" do - expect(commit.uri_type('this/path/doesnt/exist')).to be_nil - end - - it 'is nil if the path is nil or empty' do - expect(commit.uri_type(nil)).to be_nil - expect(commit.uri_type("")).to be_nil - end + it 'returns the URI type at the given path' do + expect(commit.uri_type('files/html')).to be(:tree) + expect(commit.uri_type('files/images/logo-black.png')).to be(:raw) + expect(project.commit('video').uri_type('files/videos/intro.mp4')).to be(:raw) + expect(commit.uri_type('files/js/application.js')).to be(:blob) end - context 'when Gitaly commit_tree_entry feature is enabled' do - it_behaves_like 'URI type' + it "returns nil if the path doesn't exists" do + expect(commit.uri_type('this/path/doesnt/exist')).to be_nil + expect(commit.uri_type('../path/doesnt/exist')).to be_nil end - context 'when Gitaly commit_tree_entry feature is disabled', :disable_gitaly do - it_behaves_like 'URI type' + it 'is nil if the path is nil or empty' do + expect(commit.uri_type(nil)).to be_nil + expect(commit.uri_type("")).to be_nil end end diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index d817a8376f4..c7e751130d8 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -46,7 +46,7 @@ describe Repository do it { is_expected.not_to include('feature') } it { is_expected.not_to include('fix') } - describe 'when storage is broken', :broken_storage do + describe 'when storage is broken', :broken_storage do it 'should raise a storage error' do expect_to_raise_storage_error do broken_repository.branch_names_contains(sample_commit.id) @@ -192,7 +192,7 @@ describe Repository do it { is_expected.to eq('c1acaa58bbcbc3eafe538cb8274ba387047b69f8') } - describe 'when storage is broken', :broken_storage do + describe 'when storage is broken', :broken_storage do it 'should raise a storage error' do expect_to_raise_storage_error do broken_repository.last_commit_id_for_path(sample_commit.id, '.gitignore') @@ -226,7 +226,7 @@ describe Repository do is_expected.to eq('c1acaa5') end - describe 'when storage is broken', :broken_storage do + describe 'when storage is broken', :broken_storage do it 'should raise a storage error' do expect_to_raise_storage_error do broken_repository.last_commit_for_path(sample_commit.id, '.gitignore').id @@ -391,7 +391,7 @@ describe Repository do it_behaves_like 'finding commits by message' end - describe 'when storage is broken', :broken_storage do + describe 'when storage is broken', :broken_storage do it 'should raise a storage error' do expect_to_raise_storage_error { broken_repository.find_commits_by_message('s') } end @@ -695,7 +695,7 @@ describe Repository do expect(results).to match_array([]) end - describe 'when storage is broken', :broken_storage do + describe 'when storage is broken', :broken_storage do it 'should raise a storage error' do expect_to_raise_storage_error do broken_repository.search_files_by_content('feature', 'master') @@ -744,7 +744,7 @@ describe Repository do expect(results).to match_array([]) end - describe 'when storage is broken', :broken_storage do + describe 'when storage is broken', :broken_storage do it 'should raise a storage error' do expect_to_raise_storage_error { broken_repository.search_files_by_name('files', 'master') } end @@ -796,7 +796,7 @@ describe Repository do describe '#fetch_ref' do let(:broken_repository) { create(:project, :broken_storage).repository } - describe 'when storage is broken', :broken_storage do + describe 'when storage is broken', :broken_storage do it 'should raise a storage error' do expect_to_raise_storage_error do broken_repository.fetch_ref(broken_repository, source_ref: '1', target_ref: '2') @@ -2294,6 +2294,28 @@ describe Repository do end end + describe '#local_branches' do + it 'returns the local branches' do + masterrev = repository.find_branch('master').dereferenced_target + create_remote_branch('joe', 'remote_branch', masterrev) + repository.add_branch(user, 'local_branch', masterrev.id) + + expect(repository.local_branches.any? { |branch| branch.name == 'remote_branch' }).to eq(false) + expect(repository.local_branches.any? { |branch| branch.name == 'local_branch' }).to eq(true) + end + end + + describe '#remote_branches' do + it 'returns the remote branches' do + masterrev = repository.find_branch('master').dereferenced_target + create_remote_branch('joe', 'remote_branch', masterrev) + repository.add_branch(user, 'local_branch', masterrev.id) + + expect(repository.remote_branches('joe').any? { |branch| branch.name == 'local_branch' }).to eq(false) + expect(repository.remote_branches('joe').any? { |branch| branch.name == 'remote_branch' }).to eq(true) + end + end + describe '#commit_count' do context 'with a non-existing repository' do it 'returns 0' do 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 5241c0fa6f1..a8f2c2e7a5a 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 @@ -5,6 +5,12 @@ 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 + expect(first("li")).to have_content("Roles") + find(:link, 'No one').click + end + within('.js-new-protected-branch') do allowed_to_push_button = find(".js-allowed-to-push") @@ -25,6 +31,18 @@ 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 + 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 + expect(first("li")).to have_content("Roles") + find(:link, 'No one').click + end + click_on "Protect" expect(ProtectedBranch.count).to eq(1) @@ -59,6 +77,12 @@ shared_examples "protected branches > access control > CE" do end end + find(".js-allowed-to-push").click + within('.qa-allowed-to-push-dropdown') do + expect(first("li")).to have_content("Roles") + find(:link, 'No one').click + end + click_on "Protect" expect(ProtectedBranch.count).to eq(1) @@ -70,6 +94,18 @@ 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 + 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 + expect(first("li")).to have_content("Roles") + find(:link, 'No one').click + end + click_on "Protect" expect(ProtectedBranch.count).to eq(1)