diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-04-13 15:11:32 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-04-13 15:11:32 +0300 |
commit | 7ad147d6b88837b12b02d1b1711061dcdcd6c0e3 (patch) | |
tree | 75fccfb5f4f66d2a20d53be6e9c2e60964fad04e | |
parent | 37974ac0b196b06ffcc6cbea44385eaac1cc57bd (diff) |
Add latest changes from gitlab-org/gitlab@master
69 files changed, 580 insertions, 507 deletions
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION index a9d42925fc7..07684334b57 100644 --- a/GITALY_SERVER_VERSION +++ b/GITALY_SERVER_VERSION @@ -1 +1 @@ -4ea88e921af65ba0577c40f8b54830c97adaa56c +996add2f4e011cec8e9317912978cf1fa59e66c1 diff --git a/app/assets/javascripts/content_editor/extensions/code_block_highlight.js b/app/assets/javascripts/content_editor/extensions/code_block_highlight.js new file mode 100644 index 00000000000..1d050ed208b --- /dev/null +++ b/app/assets/javascripts/content_editor/extensions/code_block_highlight.js @@ -0,0 +1,38 @@ +import { CodeBlockHighlight as BaseCodeBlockHighlight } from 'tiptap-extensions'; + +export default class GlCodeBlockHighlight extends BaseCodeBlockHighlight { + get schema() { + const baseSchema = super.schema; + + return { + ...baseSchema, + attrs: { + params: { + default: null, + }, + }, + parseDOM: [ + { + tag: 'pre', + preserveWhitespace: 'full', + getAttrs: (node) => { + const code = node.querySelector('code'); + + if (!code) { + return null; + } + + return { + /* `params` is the name of the attribute that + prosemirror-markdown uses to extract the language + of a codeblock. + https://github.com/ProseMirror/prosemirror-markdown/blob/master/src/to_markdown.js#L62 + */ + params: code.getAttribute('lang'), + }; + }, + }, + ], + }; + } +} diff --git a/app/assets/javascripts/content_editor/services/create_editor.js b/app/assets/javascripts/content_editor/services/create_editor.js index 5ff80350f5d..128d332b0a2 100644 --- a/app/assets/javascripts/content_editor/services/create_editor.js +++ b/app/assets/javascripts/content_editor/services/create_editor.js @@ -1,7 +1,20 @@ import { isFunction, isString } from 'lodash'; import { Editor } from 'tiptap'; -import { Bold, Code } from 'tiptap-extensions'; +import { + Bold, + Italic, + Code, + Link, + Image, + Heading, + Blockquote, + HorizontalRule, + BulletList, + OrderedList, + ListItem, +} from 'tiptap-extensions'; import { PROVIDE_SERIALIZER_OR_RENDERER_ERROR } from '../constants'; +import CodeBlockHighlight from '../extensions/code_block_highlight'; import createMarkdownSerializer from './markdown_serializer'; const createEditor = async ({ content, renderMarkdown, serializer: customSerializer } = {}) => { @@ -10,7 +23,20 @@ const createEditor = async ({ content, renderMarkdown, serializer: customSeriali } const editor = new Editor({ - extensions: [new Bold(), new Code()], + extensions: [ + new Bold(), + new Italic(), + new Code(), + new Link(), + new Image(), + new Heading({ levels: [1, 2, 3, 4, 5, 6] }), + new Blockquote(), + new HorizontalRule(), + new BulletList(), + new ListItem(), + new OrderedList(), + new CodeBlockHighlight(), + ], }); const serializer = customSerializer || createMarkdownSerializer({ render: renderMarkdown }); diff --git a/app/assets/javascripts/content_editor/services/markdown_serializer.js b/app/assets/javascripts/content_editor/services/markdown_serializer.js index 632d4f92218..e3b5775e320 100644 --- a/app/assets/javascripts/content_editor/services/markdown_serializer.js +++ b/app/assets/javascripts/content_editor/services/markdown_serializer.js @@ -60,9 +60,12 @@ const create = ({ render = () => null }) => { // creates a bold alias for the strong mark converter ...defaultMarkdownSerializer.marks.strong, }, + italic: { open: '_', close: '_', mixable: true, expelEnclosingWhitespace: true }, }); - return serializer.serialize(document); + return serializer.serialize(document, { + tightLists: true, + }); }, }; }; diff --git a/app/assets/javascripts/diffs/components/app.vue b/app/assets/javascripts/diffs/components/app.vue index 02fb5df07e8..8f41b848b0b 100644 --- a/app/assets/javascripts/diffs/components/app.vue +++ b/app/assets/javascripts/diffs/components/app.vue @@ -184,12 +184,7 @@ export default { 'viewDiffsFileByFile', 'mrReviews', ]), - ...mapGetters('diffs', [ - 'whichCollapsedTypes', - 'isParallelView', - 'currentDiffIndex', - 'fileCodequalityDiff', - ]), + ...mapGetters('diffs', ['whichCollapsedTypes', 'isParallelView', 'currentDiffIndex']), ...mapGetters(['isNotesFetched', 'getNoteableData']), diffs() { if (!this.viewDiffsFileByFile) { @@ -287,7 +282,6 @@ export default { endpointMetadata: this.endpointMetadata, endpointBatch: this.endpointBatch, endpointCoverage: this.endpointCoverage, - endpointCodequality: this.endpointCodequality, endpointUpdateUser: this.endpointUpdateUser, projectPath: this.projectPath, dismissEndpoint: this.dismissEndpoint, @@ -297,6 +291,10 @@ export default { mrReviews: this.rehydratedMrReviews, }); + if (this.endpointCodequality) { + this.setCodequalityEndpoint(this.endpointCodequality); + } + if (this.shouldShow) { this.fetchData(); } @@ -341,6 +339,7 @@ export default { ...mapActions('diffs', [ 'moveToNeighboringCommit', 'setBaseConfig', + 'setCodequalityEndpoint', 'fetchDiffFilesMeta', 'fetchDiffFilesBatch', 'fetchCoverageFiles', @@ -532,7 +531,6 @@ export default { :help-page-path="helpPagePath" :can-current-user-fork="canCurrentUserFork" :view-diffs-file-by-file="viewDiffsFileByFile" - :codequality-diff="fileCodequalityDiff(file.file_path)" /> <div v-if="showFileByFileNavigation" diff --git a/app/assets/javascripts/diffs/components/diff_file.vue b/app/assets/javascripts/diffs/components/diff_file.vue index 93855db52b6..bdbc13a38c4 100644 --- a/app/assets/javascripts/diffs/components/diff_file.vue +++ b/app/assets/javascripts/diffs/components/diff_file.vue @@ -67,11 +67,6 @@ export default { type: Boolean, required: true, }, - codequalityDiff: { - type: Array, - required: false, - default: () => [], - }, }, data() { return { @@ -85,7 +80,7 @@ export default { genericError: GENERIC_ERROR, }, computed: { - ...mapState('diffs', ['currentDiffFileId']), + ...mapState('diffs', ['currentDiffFileId', 'codequalityDiff']), ...mapGetters(['isNotesFetched']), ...mapGetters('diffs', ['getDiffFileDiscussions']), viewBlobHref() { @@ -154,7 +149,9 @@ export default { return loggedIn && featureOn; }, hasCodequalityChanges() { - return this.codequalityDiff.length > 0; + return ( + this.codequalityDiff?.files && this.codequalityDiff?.files[this.file.file_path]?.length > 0 + ); }, }, watch: { diff --git a/app/assets/javascripts/diffs/store/actions.js b/app/assets/javascripts/diffs/store/actions.js index 81416984dbf..1c66ad1a18c 100644 --- a/app/assets/javascripts/diffs/store/actions.js +++ b/app/assets/javascripts/diffs/store/actions.js @@ -1,5 +1,4 @@ import Cookies from 'js-cookie'; -import Visibility from 'visibilityjs'; import Vue from 'vue'; import { deprecatedCreateFlash as createFlash } from '~/flash'; import { diffViewerModes } from '~/ide/constants'; @@ -53,15 +52,12 @@ import { prepareLineForRenamedFile, } from './utils'; -let eTagPoll; - export const setBaseConfig = ({ commit }, options) => { const { endpoint, endpointMetadata, endpointBatch, endpointCoverage, - endpointCodequality, endpointUpdateUser, projectPath, dismissEndpoint, @@ -75,7 +71,6 @@ export const setBaseConfig = ({ commit }, options) => { endpointMetadata, endpointBatch, endpointCoverage, - endpointCodequality, endpointUpdateUser, projectPath, dismissEndpoint, @@ -238,48 +233,6 @@ export const fetchCoverageFiles = ({ commit, state }) => { coveragePoll.makeRequest(); }; -export const clearEtagPoll = () => { - eTagPoll = null; -}; - -export const stopCodequalityPolling = () => { - if (eTagPoll) eTagPoll.stop(); -}; - -export const restartCodequalityPolling = () => { - if (eTagPoll) eTagPoll.restart(); -}; - -export const fetchCodequality = ({ commit, state, dispatch }) => { - eTagPoll = new Poll({ - resource: { - getCodequalityDiffReports: (endpoint) => axios.get(endpoint), - }, - data: state.endpointCodequality, - method: 'getCodequalityDiffReports', - successCallback: ({ status, data }) => { - if (status === httpStatusCodes.OK) { - commit(types.SET_CODEQUALITY_DATA, data); - - eTagPoll.stop(); - } - }, - errorCallback: () => createFlash(__('Something went wrong on our end. Please try again!')), - }); - - if (!Visibility.hidden()) { - eTagPoll.makeRequest(); - } - - Visibility.change(() => { - if (!Visibility.hidden()) { - dispatch('restartCodequalityPolling'); - } else { - dispatch('stopCodequalityPolling'); - } - }); -}; - export const setHighlightedRow = ({ commit }, lineCode) => { const fileHash = lineCode.split('_')[0]; commit(types.SET_HIGHLIGHTED_ROW, lineCode); diff --git a/app/assets/javascripts/diffs/store/getters.js b/app/assets/javascripts/diffs/store/getters.js index b06faa2284b..dec3f87b03e 100644 --- a/app/assets/javascripts/diffs/store/getters.js +++ b/app/assets/javascripts/diffs/store/getters.js @@ -136,16 +136,6 @@ export const fileLineCoverage = (state) => (file, line) => { }; /** - * Returns the codequality diff data for a given file - * @param {string} filePath - * @returns {Array} - */ -export const fileCodequalityDiff = (state) => (filePath) => { - if (!state.codequalityDiff.files || !state.codequalityDiff.files[filePath]) return []; - return state.codequalityDiff.files[filePath]; -}; - -/** * Returns index of a currently selected diff in diffFiles * @returns {number} */ diff --git a/app/assets/javascripts/diffs/store/modules/diff_state.js b/app/assets/javascripts/diffs/store/modules/diff_state.js index e5bbc9ed8f8..38366663cfd 100644 --- a/app/assets/javascripts/diffs/store/modules/diff_state.js +++ b/app/assets/javascripts/diffs/store/modules/diff_state.js @@ -29,7 +29,6 @@ export default () => ({ startVersion: null, // Null unless a target diff is selected for comparison that is not the "base" diff diffFiles: [], coverageFiles: {}, - codequalityDiff: {}, mergeRequestDiffs: [], mergeRequestDiff: null, diffViewType: viewTypeFromQueryString || viewTypeFromCookie || defaultViewType, diff --git a/app/assets/javascripts/diffs/store/modules/index.js b/app/assets/javascripts/diffs/store/modules/index.js index 6860e24db6b..03d11e60745 100644 --- a/app/assets/javascripts/diffs/store/modules/index.js +++ b/app/assets/javascripts/diffs/store/modules/index.js @@ -1,7 +1,7 @@ -import * as actions from '../actions'; +import * as actions from 'ee_else_ce/diffs/store/actions'; +import createState from 'ee_else_ce/diffs/store/modules/diff_state'; +import mutations from 'ee_else_ce/diffs/store/mutations'; import * as getters from '../getters'; -import mutations from '../mutations'; -import createState from './diff_state'; export default () => ({ namespaced: true, diff --git a/app/assets/javascripts/diffs/store/mutation_types.js b/app/assets/javascripts/diffs/store/mutation_types.js index b0f396f905a..4641731c4b6 100644 --- a/app/assets/javascripts/diffs/store/mutation_types.js +++ b/app/assets/javascripts/diffs/store/mutation_types.js @@ -11,7 +11,6 @@ export const SET_MR_FILE_REVIEWS = 'SET_MR_FILE_REVIEWS'; export const SET_DIFF_VIEW_TYPE = 'SET_DIFF_VIEW_TYPE'; export const SET_COVERAGE_DATA = 'SET_COVERAGE_DATA'; -export const SET_CODEQUALITY_DATA = 'SET_CODEQUALITY_DATA'; export const SET_MERGE_REQUEST_DIFFS = 'SET_MERGE_REQUEST_DIFFS'; export const TOGGLE_LINE_HAS_FORM = 'TOGGLE_LINE_HAS_FORM'; export const ADD_CONTEXT_LINES = 'ADD_CONTEXT_LINES'; diff --git a/app/assets/javascripts/diffs/store/mutations.js b/app/assets/javascripts/diffs/store/mutations.js index eacf76234fc..9ff9a02d444 100644 --- a/app/assets/javascripts/diffs/store/mutations.js +++ b/app/assets/javascripts/diffs/store/mutations.js @@ -33,7 +33,6 @@ export default { endpointMetadata, endpointBatch, endpointCoverage, - endpointCodequality, endpointUpdateUser, projectPath, dismissEndpoint, @@ -47,7 +46,6 @@ export default { endpointMetadata, endpointBatch, endpointCoverage, - endpointCodequality, endpointUpdateUser, projectPath, dismissEndpoint, @@ -91,10 +89,6 @@ export default { Object.assign(state, { coverageFiles }); }, - [types.SET_CODEQUALITY_DATA](state, codequalityDiffData) { - Object.assign(state, { codequalityDiff: codequalityDiffData }); - }, - [types.RENDER_FILE](state, file) { renderFile(file); }, diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_ci_templates.vue b/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_ci_templates.vue index 4d4420436a5..c2ec8c57fd7 100644 --- a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_ci_templates.vue +++ b/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_ci_templates.vue @@ -1,5 +1,6 @@ <script> import { GlButton, GlCard, GlSprintf } from '@gitlab/ui'; +import ExperimentTracking from '~/experimentation/experiment_tracking'; import { mergeUrlParams } from '~/lib/utils/url_utility'; import { s__, sprintf } from '~/locale'; import { HELLO_WORLD_TEMPLATE_KEY } from '../../constants'; @@ -10,6 +11,7 @@ export default { GlCard, GlSprintf, }, + HELLO_WORLD_TEMPLATE_KEY, i18n: { cta: s__('Pipelines|Use template'), testTemplates: { @@ -51,6 +53,14 @@ export default { ), }; }, + methods: { + trackEvent(template) { + const tracking = new ExperimentTracking('pipeline_empty_state_templates', { + label: template, + }); + tracking.event('template_clicked'); + }, + }, }; </script> <template> @@ -82,6 +92,7 @@ export default { variant="confirm" :href="helloWorldTemplateUrl" data-testid="test-template-link" + @click="trackEvent($options.HELLO_WORLD_TEMPLATE_KEY)" > {{ $options.i18n.cta }} </gl-button> @@ -121,6 +132,7 @@ export default { variant="confirm" :href="template.link" data-testid="template-link" + @click="trackEvent(template.name)" > {{ $options.i18n.cta }} </gl-button> diff --git a/app/services/merge_requests/resolve_todos_service.rb b/app/services/merge_requests/resolve_todos_service.rb new file mode 100644 index 00000000000..0010b596eee --- /dev/null +++ b/app/services/merge_requests/resolve_todos_service.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +module MergeRequests + class ResolveTodosService + include BaseServiceUtility + + def initialize(merge_request, user) + @merge_request = merge_request + @user = user + end + + def async_execute + if Feature.enabled?(:resolve_merge_request_todos_async, merge_request.target_project, default_enabled: :yaml) + MergeRequests::ResolveTodosWorker.perform_async(merge_request.id, user.id) + else + execute + end + end + + def execute + todo_service.resolve_todos_for_target(merge_request, user) + end + + private + + attr_reader :merge_request, :user + end +end diff --git a/app/services/merge_requests/update_service.rb b/app/services/merge_requests/update_service.rb index 15fe92e0edd..89202edd0d4 100644 --- a/app/services/merge_requests/update_service.rb +++ b/app/services/merge_requests/update_service.rb @@ -147,7 +147,11 @@ module MergeRequests def resolve_todos(merge_request, old_labels, old_assignees, old_reviewers) return unless has_changes?(merge_request, old_labels: old_labels, old_assignees: old_assignees, old_reviewers: old_reviewers) - todo_service.resolve_todos_for_target(merge_request, current_user) + service_user = current_user + + merge_request.run_after_commit_or_now do + ::MergeRequests::ResolveTodosService.new(merge_request, service_user).async_execute + end end def handle_target_branch_change(merge_request) diff --git a/app/views/admin/users/_head.html.haml b/app/views/admin/users/_head.html.haml index db146f437b6..ade3581e5b9 100644 --- a/app/views/admin/users/_head.html.haml +++ b/app/views/admin/users/_head.html.haml @@ -20,20 +20,20 @@ .float-right - if impersonation_enabled? && @user != current_user && @user.can?(:log_in) - = link_to 'Impersonate', impersonate_admin_user_path(@user), method: :post, class: "btn btn-info gl-button btn-grouped", data: { qa_selector: 'impersonate_user_link' } + = link_to _('Impersonate'), impersonate_admin_user_path(@user), method: :post, class: "btn btn-info gl-button btn-grouped", data: { qa_selector: 'impersonate_user_link' } = link_to edit_admin_user_path(@user), class: "btn btn-default gl-button btn-grouped" do = sprite_icon('pencil-square', css_class: 'gl-icon gl-button-icon') = _('Edit') %hr %ul.nav-links.nav.nav-tabs = nav_link(path: 'users#show') do - = link_to "Account", admin_user_path(@user) + = link_to _("Account"), admin_user_path(@user) = nav_link(path: 'users#projects') do - = link_to "Groups and projects", projects_admin_user_path(@user) + = link_to _("Groups and projects"), projects_admin_user_path(@user) = nav_link(path: 'users#keys') do - = link_to "SSH keys", keys_admin_user_path(@user) + = link_to _("SSH keys"), keys_admin_user_path(@user) = nav_link(controller: :identities) do - = link_to "Identities", admin_user_identities_path(@user) + = link_to _("Identities"), admin_user_identities_path(@user) = nav_link(controller: :impersonation_tokens) do - = link_to "Impersonation Tokens", admin_user_impersonation_tokens_path(@user) + = link_to _("Impersonation Tokens"), admin_user_impersonation_tokens_path(@user) .gl-mb-3 diff --git a/app/views/groups/runners/_runner.html.haml b/app/views/groups/runners/_runner.html.haml index 01c921d0c0d..c687167e519 100644 --- a/app/views/groups/runners/_runner.html.haml +++ b/app/views/groups/runners/_runner.html.haml @@ -3,16 +3,16 @@ .table-mobile-header{ role: 'rowheader' }= _('Type') .table-mobile-content - if runner.group_type? - %span.badge.badge-success + %span.badge.badge-pill.gl-badge.sm.badge-success = _('group') - else - %span.badge.badge-info + %span.badge.badge-pill.gl-badge.sm.badge-info = _('specific') - if runner.locked? - %span.badge.badge-warning + %span.badge.badge-pill.gl-badge.sm.badge-warning = _('locked') - unless runner.active? - %span.badge.badge-danger + %span.badge.badge-pill.gl-badge.sm.badge-danger = _('paused') .table-section.section-10 diff --git a/app/views/profiles/gpg_keys/_key.html.haml b/app/views/profiles/gpg_keys/_key.html.haml index 4b3f6f8cfc7..ec48a611377 100644 --- a/app/views/profiles/gpg_keys/_key.html.haml +++ b/app/views/profiles/gpg_keys/_key.html.haml @@ -19,7 +19,7 @@ .float-right %span.key-created-at = s_('Profiles|Created %{time_ago}'.html_safe) % { time_ago: time_ago_with_tooltip(key.created_at) } - = link_to profile_gpg_key_path(key), data: { confirm: _('Are you sure? Removing this GPG key does not affect already signed commits.') }, method: :delete, class: "gl-button btn btn-danger gl-ml-3" do + = link_to profile_gpg_key_path(key), data: { confirm: _('Are you sure? Removing this GPG key does not affect already signed commits.') }, method: :delete, class: "gl-button btn btn-icon btn-danger gl-ml-3" do %span.sr-only= _('Remove') = sprite_icon('remove') = link_to revoke_profile_gpg_key_path(key), data: { confirm: _('Are you sure? All commits that were signed with this GPG key will be unverified.') }, method: :put, class: "gl-button btn btn-danger gl-ml-3" do diff --git a/app/workers/all_queues.yml b/app/workers/all_queues.yml index ff3d3740ed6..2f2fd19a3aa 100644 --- a/app/workers/all_queues.yml +++ b/app/workers/all_queues.yml @@ -1908,6 +1908,14 @@ :weight: 1 :idempotent: true :tags: [] +- :name: merge_requests_resolve_todos + :feature_category: :code_review + :has_external_dependencies: + :urgency: :high + :resource_boundary: :unknown + :weight: 1 + :idempotent: true + :tags: [] - :name: metrics_dashboard_prune_old_annotations :feature_category: :metrics :has_external_dependencies: diff --git a/app/workers/merge_requests/resolve_todos_worker.rb b/app/workers/merge_requests/resolve_todos_worker.rb new file mode 100644 index 00000000000..2a5f742f809 --- /dev/null +++ b/app/workers/merge_requests/resolve_todos_worker.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +class MergeRequests::ResolveTodosWorker + include ApplicationWorker + + feature_category :code_review + urgency :high + deduplicate :until_executed + idempotent! + + def perform(merge_request_id, user_id) + merge_request = MergeRequest.find(merge_request_id) + user = User.find(user_id) + + MergeRequests::ResolveTodosService.new(merge_request, user).execute + rescue ActiveRecord::RecordNotFound + end +end diff --git a/changelogs/unreleased/20827-async-todo-creation-resolution.yml b/changelogs/unreleased/20827-async-todo-creation-resolution.yml new file mode 100644 index 00000000000..9ffd28aa4ea --- /dev/null +++ b/changelogs/unreleased/20827-async-todo-creation-resolution.yml @@ -0,0 +1,5 @@ +--- +title: Resolve merge request todos asynchronously on update +merge_request: 58647 +author: +type: performance diff --git a/changelogs/unreleased/Externalize-strings-in-users-_head-html-haml.yml b/changelogs/unreleased/Externalize-strings-in-users-_head-html-haml.yml new file mode 100644 index 00000000000..9fd8b743d94 --- /dev/null +++ b/changelogs/unreleased/Externalize-strings-in-users-_head-html-haml.yml @@ -0,0 +1,5 @@ +--- +title: Externalise strings in admin/users/_head.html.haml +merge_request: 58101 +author: nuwe1 +type: other diff --git a/changelogs/unreleased/ab-spam-logs-index.yml b/changelogs/unreleased/ab-spam-logs-index.yml new file mode 100644 index 00000000000..8711f5cb4f6 --- /dev/null +++ b/changelogs/unreleased/ab-spam-logs-index.yml @@ -0,0 +1,5 @@ +--- +title: Add user index on spam logs +merge_request: 59151 +author: +type: performance diff --git a/changelogs/unreleased/btn-icon-gpg-delete.yml b/changelogs/unreleased/btn-icon-gpg-delete.yml new file mode 100644 index 00000000000..c4b21e3899e --- /dev/null +++ b/changelogs/unreleased/btn-icon-gpg-delete.yml @@ -0,0 +1,5 @@ +--- +title: Add btn-icon class for GPG key delete button +merge_request: 57974 +author: Yogi (@yo) +type: changed diff --git a/changelogs/unreleased/eb-update-usage-ping-metrics-definition.yml b/changelogs/unreleased/eb-update-usage-ping-metrics-definition.yml new file mode 100644 index 00000000000..09f0b70735e --- /dev/null +++ b/changelogs/unreleased/eb-update-usage-ping-metrics-definition.yml @@ -0,0 +1,5 @@ +--- +title: Update metric definition under verify testing group +merge_request: 59028 +author: +type: other diff --git a/config/feature_flags/development/resolve_merge_request_todos_async.yml b/config/feature_flags/development/resolve_merge_request_todos_async.yml new file mode 100644 index 00000000000..db19e439994 --- /dev/null +++ b/config/feature_flags/development/resolve_merge_request_todos_async.yml @@ -0,0 +1,8 @@ +--- +name: resolve_merge_request_todos_async +introduced_by_url: +rollout_issue_url: +milestone: '13.11' +type: development +group: group::code review +default_enabled: false diff --git a/config/metrics/counts_28d/20210216182136_i_testing_test_case_parsed_monthly.yml b/config/metrics/counts_28d/20210216182136_i_testing_test_case_parsed_monthly.yml index 15369757cb8..fa4b6b14946 100644 --- a/config/metrics/counts_28d/20210216182136_i_testing_test_case_parsed_monthly.yml +++ b/config/metrics/counts_28d/20210216182136_i_testing_test_case_parsed_monthly.yml @@ -17,4 +17,3 @@ tier: - free - premium - ultimate -skip_validation: true diff --git a/config/metrics/counts_28d/20210216182200_i_testing_metrics_report_artifact_uploaders_monthly.yml b/config/metrics/counts_28d/20210216182200_i_testing_metrics_report_artifact_uploaders_monthly.yml deleted file mode 100644 index 1a475b19f01..00000000000 --- a/config/metrics/counts_28d/20210216182200_i_testing_metrics_report_artifact_uploaders_monthly.yml +++ /dev/null @@ -1,20 +0,0 @@ ---- -key_path: redis_hll_counters.testing.i_testing_metrics_report_artifact_uploaders_monthly -description: Internal Tracking to count number of unit tests parsed for planning of - future code testing features. Data available [here](https://app.periscopedata.com/app/gitlab/788674/Verify:Testing-Group-Metrics?widget=10454394&udv=0) -product_section: ops -product_stage: verify -product_group: group::testing -product_category: code_testing -value_type: number -status: data_available -time_frame: 28d -data_source: redis_hll -distribution: -- ce -- ee -tier: -- free -- premium -- ultimate -skip_validation: true diff --git a/config/metrics/counts_28d/20210216183209_i_testing_paid_monthly_active_user_total.yml b/config/metrics/counts_28d/20210216183209_i_testing_paid_monthly_active_user_total.yml deleted file mode 100644 index 367cfb77c09..00000000000 --- a/config/metrics/counts_28d/20210216183209_i_testing_paid_monthly_active_user_total.yml +++ /dev/null @@ -1,16 +0,0 @@ ---- -key_path: counts_monthly.aggregated_metrics.i_testing_paid_monthly_active_user_total -description: '' -product_section: '' -product_stage: '' -product_group: '' -product_category: '' -value_type: number -status: data_available -time_frame: 28d -data_source: database -distribution: -- ce -tier: -- free -skip_validation: true diff --git a/config/metrics/counts_28d/20210216184140_testing_total_unique_counts_monthly.yml b/config/metrics/counts_28d/20210216184140_testing_total_unique_counts_monthly.yml index 12d51d8d560..381f691fe27 100644 --- a/config/metrics/counts_28d/20210216184140_testing_total_unique_counts_monthly.yml +++ b/config/metrics/counts_28d/20210216184140_testing_total_unique_counts_monthly.yml @@ -6,11 +6,10 @@ product_stage: '' product_group: '' product_category: '' value_type: number -status: data_available +status: removed time_frame: 28d data_source: redis_hll distribution: - ce tier: - free -skip_validation: true diff --git a/config/metrics/counts_7d/20210216182134_i_testing_test_case_parsed_weekly.yml b/config/metrics/counts_7d/20210216182134_i_testing_test_case_parsed_weekly.yml index f6f2bb9ab74..cc125283f2c 100644 --- a/config/metrics/counts_7d/20210216182134_i_testing_test_case_parsed_weekly.yml +++ b/config/metrics/counts_7d/20210216182134_i_testing_test_case_parsed_weekly.yml @@ -17,4 +17,3 @@ tier: - free - premium - ultimate -skip_validation: true diff --git a/config/metrics/counts_7d/20210216182158_i_testing_metrics_report_artifact_uploaders_weekly.yml b/config/metrics/counts_7d/20210216182158_i_testing_metrics_report_artifact_uploaders_weekly.yml deleted file mode 100644 index f88b6539ceb..00000000000 --- a/config/metrics/counts_7d/20210216182158_i_testing_metrics_report_artifact_uploaders_weekly.yml +++ /dev/null @@ -1,20 +0,0 @@ ---- -key_path: redis_hll_counters.testing.i_testing_metrics_report_artifact_uploaders_weekly -description: Internal Tracking to count number of unit tests parsed for planning of - future code testing features. Data available [here](https://app.periscopedata.com/app/gitlab/788674/Verify:Testing-Group-Metrics?widget=10454394&udv=0) -product_section: ops -product_stage: verify -product_group: group::testing -product_category: code_testing -value_type: number -status: data_available -time_frame: 7d -data_source: redis_hll -distribution: -- ee -- ce -tier: -- free -- premium -- ultimate -skip_validation: true diff --git a/config/sidekiq_queues.yml b/config/sidekiq_queues.yml index 99cada568c0..7febb3770d1 100644 --- a/config/sidekiq_queues.yml +++ b/config/sidekiq_queues.yml @@ -218,6 +218,8 @@ - 1 - - merge_requests_handle_assignees_change - 1 +- - merge_requests_resolve_todos + - 1 - - metrics_dashboard_prune_old_annotations - 1 - - metrics_dashboard_sync_dashboards diff --git a/db/migrate/20210412142223_add_user_index_on_spam_logs.rb b/db/migrate/20210412142223_add_user_index_on_spam_logs.rb new file mode 100644 index 00000000000..0a12f0f1a87 --- /dev/null +++ b/db/migrate/20210412142223_add_user_index_on_spam_logs.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class AddUserIndexOnSpamLogs < ActiveRecord::Migration[6.0] + include Gitlab::Database::MigrationHelpers + + disable_ddl_transaction! + + INDEX_NAME = 'index_spam_logs_on_user_id' + + def up + add_concurrent_index :spam_logs, :user_id, name: INDEX_NAME + end + + def down + remove_concurrent_index_by_name :spam_logs, INDEX_NAME + end +end diff --git a/db/post_migrate/20210311120155_backfill_events_id_for_bigint_conversion.rb b/db/post_migrate/20210311120155_backfill_events_id_for_bigint_conversion.rb index 812f0a3a84e..01e81c65eee 100644 --- a/db/post_migrate/20210311120155_backfill_events_id_for_bigint_conversion.rb +++ b/db/post_migrate/20210311120155_backfill_events_id_for_bigint_conversion.rb @@ -6,13 +6,13 @@ class BackfillEventsIdForBigintConversion < ActiveRecord::Migration[6.0] DOWNTIME = false def up - return unless Gitlab.dev_env_or_com? + return unless should_run? backfill_conversion_of_integer_to_bigint :events, :id, batch_size: 15000, sub_batch_size: 100 end def down - return unless Gitlab.dev_env_or_com? + return unless should_run? Gitlab::Database::BackgroundMigration::BatchedMigration .where(job_class_name: 'CopyColumnUsingBackgroundMigrationJob') @@ -20,4 +20,10 @@ class BackfillEventsIdForBigintConversion < ActiveRecord::Migration[6.0] .where('job_arguments = ?', %w[id id_convert_to_bigint].to_json) .delete_all end + + private + + def should_run? + Gitlab.dev_or_test_env? || Gitlab.com? + end end diff --git a/db/post_migrate/20210311120156_backfill_push_event_payload_event_id_for_bigint_conversion.rb b/db/post_migrate/20210311120156_backfill_push_event_payload_event_id_for_bigint_conversion.rb index 7c1aba254f0..6b8595b3ad3 100644 --- a/db/post_migrate/20210311120156_backfill_push_event_payload_event_id_for_bigint_conversion.rb +++ b/db/post_migrate/20210311120156_backfill_push_event_payload_event_id_for_bigint_conversion.rb @@ -6,14 +6,14 @@ class BackfillPushEventPayloadEventIdForBigintConversion < ActiveRecord::Migrati DOWNTIME = false def up - return unless Gitlab.dev_env_or_com? + return unless should_run? backfill_conversion_of_integer_to_bigint :push_event_payloads, :event_id, primary_key: :event_id, batch_size: 15000, sub_batch_size: 100 end def down - return unless Gitlab.dev_env_or_com? + return unless should_run? Gitlab::Database::BackgroundMigration::BatchedMigration .where(job_class_name: 'CopyColumnUsingBackgroundMigrationJob') @@ -21,4 +21,10 @@ class BackfillPushEventPayloadEventIdForBigintConversion < ActiveRecord::Migrati .where('job_arguments = ?', %w[event_id event_id_convert_to_bigint].to_json) .delete_all end + + private + + def should_run? + Gitlab.dev_or_test_env? || Gitlab.com? + end end diff --git a/db/schema_migrations/20210412142223 b/db/schema_migrations/20210412142223 new file mode 100644 index 00000000000..9ddb9b7f1e4 --- /dev/null +++ b/db/schema_migrations/20210412142223 @@ -0,0 +1 @@ +4a1435a56b8e5cddd83b844f84374bca91810bbfc5f44faf2a53fd41f93be69c
\ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 15f14bc5208..5d0ca31e91f 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -23942,6 +23942,8 @@ CREATE UNIQUE INDEX index_sop_configs_on_project_id ON security_orchestration_po CREATE INDEX index_sop_configurations_project_id_policy_project_id ON security_orchestration_policy_configurations USING btree (security_policy_management_project_id, project_id); +CREATE INDEX index_spam_logs_on_user_id ON spam_logs USING btree (user_id); + CREATE INDEX index_sprints_iterations_cadence_id ON sprints USING btree (iterations_cadence_id); CREATE INDEX index_sprints_on_description_trigram ON sprints USING gin (description gin_trgm_ops); diff --git a/doc/administration/geo/index.md b/doc/administration/geo/index.md index d14ab70c138..f1884f297e8 100644 --- a/doc/administration/geo/index.md +++ b/doc/administration/geo/index.md @@ -281,7 +281,6 @@ WARNING: This list of limitations only reflects the latest version of GitLab. If you are using an older version, extra limitations may be in place. - Pushing directly to a **secondary** node redirects (for HTTP) or proxies (for SSH) the request to the **primary** node instead of [handling it directly](https://gitlab.com/gitlab-org/gitlab/-/issues/1381), except when using Git over HTTP with credentials embedded within the URI. For example, `https://user:password@secondary.tld`. -- Cloning, pulling, or pushing repositories that exist on the **primary** node but not on the **secondary** nodes where [selective synchronization](replication/configuration.md#selective-synchronization) does not include the project is not supported over SSH [but support is planned](https://gitlab.com/groups/gitlab-org/-/epics/2562). HTTP(S) is supported. - The **primary** node has to be online for OAuth login to happen. Existing sessions and Git are not affected. Support for the **secondary** node to use an OAuth provider independent from the primary is [being planned](https://gitlab.com/gitlab-org/gitlab/-/issues/208465). - The installation takes multiple manual steps that together can take about an hour depending on circumstances. We are working on improving this experience. See [Omnibus GitLab issue #2978](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/2978) for details. - Real-time updates of issues/merge requests (for example, via long polling) doesn't work on the **secondary** node. @@ -289,6 +288,7 @@ This list of limitations only reflects the latest version of GitLab. If you are - Object pools for forked project deduplication work only on the **primary** node, and are duplicated on the **secondary** node. - GitLab Runners cannot register with a **secondary** node. Support for this is [planned for the future](https://gitlab.com/gitlab-org/gitlab/-/issues/3294). - Geo **secondary** nodes can not be configured to [use high-availability configurations of PostgreSQL](https://gitlab.com/groups/gitlab-org/-/epics/2536). +- [Selective synchronization](replication/configuration.md#selective-synchronization) only limits what repositories are replicated. The entire PostgreSQL data is still replicated. Selective synchronization is not built to accomodate compliance / export control use cases. ### Limitations on replication/verification diff --git a/doc/development/testing_guide/end_to_end/beginners_guide.md b/doc/development/testing_guide/end_to_end/beginners_guide.md index d60b780eeea..29f6c93d65a 100644 --- a/doc/development/testing_guide/end_to_end/beginners_guide.md +++ b/doc/development/testing_guide/end_to_end/beginners_guide.md @@ -332,12 +332,13 @@ can see it. ## Run the spec -Before running the spec, confirm: +Before running the spec, make sure that: -- The GDK is installed. -- The GDK is running on port 3000 locally. +- GDK is installed. +- GDK is running locally on port 3000. - No additional [RSpec metadata tags](rspec_metadata_tests.md) have been applied. - Your working directory is `qa/` within your GDK GitLab installation. +- Your GitLab instance-level settings are default. If you changed the default settings, some tests might have unexpected results. To run the spec, run the following command: diff --git a/doc/development/usage_ping/dictionary.md b/doc/development/usage_ping/dictionary.md index 278c379fa48..2e5183e4a60 100644 --- a/doc/development/usage_ping/dictionary.md +++ b/doc/development/usage_ping/dictionary.md @@ -6106,15 +6106,15 @@ Tiers: `free` ### `counts_monthly.aggregated_metrics.i_testing_paid_monthly_active_user_total` -Missing description +Aggregated count of users who have engaged with a Premium or Ultimate tier testing feature per month. -[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/counts_28d/20210216183209_i_testing_paid_monthly_active_user_total.yml) +[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_28d/20210216183209_i_testing_paid_monthly_active_user_total.yml) -Group: `` +Group: `group::testing` Status: `data_available` -Tiers: `free` +Tiers: `premium`, `ultimate` ### `counts_monthly.aggregated_metrics.incident_management_alerts_total_unique_counts` @@ -6274,15 +6274,15 @@ Tiers: ### `counts_weekly.aggregated_metrics.i_testing_paid_monthly_active_user_total` -Missing description +Aggregated count of users who have engaged with a Premium or Ultimate tier testing feature per week. [YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_7d/20210216183219_i_testing_paid_monthly_active_user_total.yml) -Group: `` +Group: `group::testing` Status: `data_available` -Tiers: +Tiers: `premium`, `ultimate` ### `counts_weekly.aggregated_metrics.incident_management_alerts_total_unique_counts` @@ -13654,7 +13654,7 @@ Tiers: `premium`, `ultimate` ### `redis_hll_counters.testing.i_testing_full_code_quality_report_total_weekly` -Count of unique users per week|month who visit the full code quality report +Count of unique users per week who visit the full code quality report [YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_7d/20210216182145_i_testing_full_code_quality_report_total_weekly.yml) @@ -13666,7 +13666,7 @@ Tiers: `premium`, `ultimate` ### `redis_hll_counters.testing.i_testing_group_code_coverage_project_click_total_monthly` -Count of unique users per week|month who click on a project link in the group code coverage table +Aggregated count of unique users who have clicked from group code coverage page to an individual project page each month. [YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_28d/20210216182153_i_testing_group_code_coverage_project_click_total_monthly.yml) @@ -13678,19 +13678,19 @@ Tiers: `premium`, `ultimate` ### `redis_hll_counters.testing.i_testing_group_code_coverage_project_click_total_weekly` -Missing description +Aggregated count of unique users who have clicked from group code coverage page to an individual project page each week. [YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_7d/20210216184132_i_testing_group_code_coverage_project_click_total_weekly.yml) -Group: `` +Group: `group::testing` Status: `data_available` -Tiers: +Tiers: `premium`, `ultimate` ### `redis_hll_counters.testing.i_testing_group_code_coverage_visit_total_monthly` -Count of unique users per week|month who visited the group code coverage page +Count of unique users per month who visited the group code coverage page [YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_28d/20210216182143_i_testing_group_code_coverage_visit_total_monthly.yml) @@ -13702,7 +13702,7 @@ Tiers: `premium`, `ultimate` ### `redis_hll_counters.testing.i_testing_group_code_coverage_visit_total_weekly` -Count of unique users per week|month who visited the group code coverage page +Count of unique users per week who visited the group code coverage page [YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_7d/20210216182141_i_testing_group_code_coverage_visit_total_weekly.yml) @@ -13714,7 +13714,7 @@ Tiers: `premium`, `ultimate` ### `redis_hll_counters.testing.i_testing_load_performance_widget_total_monthly` -Count of unique users per week|month who expanded the load performance report MR widget +Count of unique users per month who expanded the load performance report MR widget [YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_28d/20210216182156_i_testing_load_performance_widget_total_monthly.yml) @@ -13726,7 +13726,7 @@ Tiers: `premium`, `ultimate` ### `redis_hll_counters.testing.i_testing_load_performance_widget_total_weekly` -Count of unique users per week|month who expanded the load performance report MR widget +Count of unique users per week who expanded the load performance report MR widget [YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_7d/20210216182154_i_testing_load_performance_widget_total_weekly.yml) @@ -13738,31 +13738,31 @@ Tiers: `premium`, `ultimate` ### `redis_hll_counters.testing.i_testing_metrics_report_artifact_uploaders_monthly` -Internal Tracking to count number of unit tests parsed for planning of future code testing features. Data available [here](https://app.periscopedata.com/app/gitlab/788674/Verify:Testing-Group-Metrics?widget=10454394&udv=0) +Tracks number of metrics reports uploaded monthly. -[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/counts_28d/20210216182200_i_testing_metrics_report_artifact_uploaders_monthly.yml) +[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_28d/20210216182200_i_testing_metrics_report_artifact_uploaders_monthly.yml) Group: `group::testing` Status: `data_available` -Tiers: `free`, `premium`, `ultimate` +Tiers: `premium`, `ultimate` ### `redis_hll_counters.testing.i_testing_metrics_report_artifact_uploaders_weekly` -Internal Tracking to count number of unit tests parsed for planning of future code testing features. Data available [here](https://app.periscopedata.com/app/gitlab/788674/Verify:Testing-Group-Metrics?widget=10454394&udv=0) +Count of unique users per week who trigger a pipeline that uploads a metrics report. -[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/counts_7d/20210216182158_i_testing_metrics_report_artifact_uploaders_weekly.yml) +[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_7d/20210216182158_i_testing_metrics_report_artifact_uploaders_weekly.yml) Group: `group::testing` Status: `data_available` -Tiers: `free`, `premium`, `ultimate` +Tiers: `premium`, `ultimate` ### `redis_hll_counters.testing.i_testing_metrics_report_widget_total_monthly` -Count of unique users per week|month who expanded the metrics report MR widget +Count of unique users per month who expanded the metrics report MR widget [YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_28d/20210216182139_i_testing_metrics_report_widget_total_monthly.yml) @@ -13774,7 +13774,7 @@ Tiers: `premium`, `ultimate` ### `redis_hll_counters.testing.i_testing_metrics_report_widget_total_weekly` -Count of unique users per week|month who expanded the metrics report MR widget +Count of unique users per week who expanded the metrics report MR widget [YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_7d/20210216182138_i_testing_metrics_report_widget_total_weekly.yml) @@ -13810,7 +13810,7 @@ Tiers: `free`, `premium`, `ultimate` ### `redis_hll_counters.testing.i_testing_web_performance_widget_total_monthly` -Count of unique users per week|month who expanded the browser performance report MR widget +Count of unique users per month who expanded the browser performance report MR widget [YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_28d/20210216182151_i_testing_web_performance_widget_total_monthly.yml) @@ -13822,7 +13822,7 @@ Tiers: `premium`, `ultimate` ### `redis_hll_counters.testing.i_testing_web_performance_widget_total_weekly` -Count of unique users per week|month who expanded the browser performance report MR widget +Count of unique users per week who expanded the browser performance report MR widget [YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_7d/20210216182149_i_testing_web_performance_widget_total_weekly.yml) @@ -13840,7 +13840,7 @@ Missing description Group: `` -Status: `data_available` +Status: `removed` Tiers: `free` @@ -13852,9 +13852,9 @@ Missing description Group: `` -Status: `data_available` +Status: `removed` -Tiers: +Tiers: `premium`, `ultimate` ### `redis_hll_counters.user_packages.i_package_composer_user_monthly` diff --git a/doc/policy/maintenance.md b/doc/policy/maintenance.md index 0df0ef06d19..95bc176e70a 100644 --- a/doc/policy/maintenance.md +++ b/doc/policy/maintenance.md @@ -36,7 +36,7 @@ The following table describes the version types and their release cadence: | Version type | Description | Cadence | |:-------------|:------------|:--------| -| Major | For significant changes, or when any backward-incompatible changes are introduced to the public API. | Yearly. The next major release is GitLab 14.0 on May 22, 2021. Subsequent major releases will be scheduled for May 22 each year, by default. | +| Major | For significant changes, or when any backward-incompatible changes are introduced to the public API. | Yearly. The next major release is GitLab 14.0 on June 22, 2021 (one month later than typical, details in [this issue](https://gitlab.com/gitlab-com/Product/-/issues/2337)). Subsequent major releases will be scheduled for May 22 each year, by default. | | Minor | For when new backward-compatible functionality is introduced to the public API, a minor feature is introduced, or when a set of smaller features is rolled out. | Monthly on the 22nd. | | Patch | For backward-compatible bug fixes that fix incorrect behavior. See [Patch releases](#patch-releases). | As needed. | diff --git a/doc/user/project/issues/managing_issues.md b/doc/user/project/issues/managing_issues.md index 35298d72769..dafc0e6ba02 100644 --- a/doc/user/project/issues/managing_issues.md +++ b/doc/user/project/issues/managing_issues.md @@ -323,14 +323,6 @@ in a comment or description field. Assignees in the sidebar are updated in real time. This feature is **disabled by default**. To enable it, you need to enable [ActionCable in-app mode](https://docs.gitlab.com/omnibus/settings/actioncable.html). -## Cached issue count **(FREE SELF)** - -> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/243753) in GitLab 13.9. -> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/323493) in GitLab 13.11. - -In a group, the sidebar displays the total count of open issues and this value is cached if higher -than 1000. The cached value is rounded to thousands (or millions) and updated every 24 hours. - ## Similar issues > [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/22866) in GitLab 11.6. diff --git a/doc/user/project/pages/getting_started/pages_new_project_template.md b/doc/user/project/pages/getting_started/pages_new_project_template.md index eec8349abe6..36371573fd9 100644 --- a/doc/user/project/pages/getting_started/pages_new_project_template.md +++ b/doc/user/project/pages/getting_started/pages_new_project_template.md @@ -5,7 +5,7 @@ group: Release info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- -# Create a Pages website from a new project template +# Create a Pages website from a template > [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/47857) in GitLab 11.8. diff --git a/doc/user/project/pages/index.md b/doc/user/project/pages/index.md index 162fcff12a4..2ff91292b1b 100644 --- a/doc/user/project/pages/index.md +++ b/doc/user/project/pages/index.md @@ -49,7 +49,7 @@ To create a GitLab Pages website: | [Create a `gitlab-ci.yml` file from scratch](getting_started/pages_from_scratch.md) | Add a Pages site to an existing project. Learn how to create and configure your own CI file. | | [Use a `.gitlab-ci.yml` template](getting_started/pages_ci_cd_template.md) | Add a Pages site to an existing project. Use a pre-populated CI template file. | | [Fork a sample project](getting_started/pages_forked_sample_project.md) | Create a new project with Pages already configured by forking a sample project. | -| [Use a new project template](getting_started/pages_new_project_template.md) | Create a new project with Pages already configured by using a new project template. | +| [Use a project template](getting_started/pages_new_project_template.md) | Create a new project with Pages already configured by using a template. | To update a GitLab Pages website: diff --git a/lib/gitlab/ci/config/entry/processable.rb b/lib/gitlab/ci/config/entry/processable.rb index 1cdf84ef4d3..947b6787aa0 100644 --- a/lib/gitlab/ci/config/entry/processable.rb +++ b/lib/gitlab/ci/config/entry/processable.rb @@ -142,14 +142,10 @@ module Gitlab end def job_variables - return unless ::Feature.enabled?(:ci_workflow_rules_variables, default_enabled: :yaml) - variables_value.to_h end def root_variables_inheritance - return unless ::Feature.enabled?(:ci_workflow_rules_variables, default_enabled: :yaml) - inherit_entry&.variables_entry&.value end diff --git a/lib/gitlab/ci/config/normalizer/matrix_strategy.rb b/lib/gitlab/ci/config/normalizer/matrix_strategy.rb index 48b6fca598a..5cabbc86d3e 100644 --- a/lib/gitlab/ci/config/normalizer/matrix_strategy.rb +++ b/lib/gitlab/ci/config/normalizer/matrix_strategy.rb @@ -44,7 +44,7 @@ module Gitlab name: name, instance: instance, variables: variables, # https://gitlab.com/gitlab-org/gitlab/-/issues/300581 - job_variables: job_variables, + job_variables: variables, parallel: { total: total } }.compact end @@ -61,12 +61,6 @@ module Gitlab private attr_reader :job_name, :instance, :variables, :total - - def job_variables - return unless ::Feature.enabled?(:ci_workflow_rules_variables, default_enabled: :yaml) - - variables - end end end end diff --git a/lib/gitlab/ci/pipeline/chain/seed.rb b/lib/gitlab/ci/pipeline/chain/seed.rb index 560e62ce850..66fc6741252 100644 --- a/lib/gitlab/ci/pipeline/chain/seed.rb +++ b/lib/gitlab/ci/pipeline/chain/seed.rb @@ -11,7 +11,7 @@ module Gitlab def perform! raise ArgumentError, 'missing YAML processor result' unless @command.yaml_processor_result - if ::Feature.enabled?(:ci_workflow_rules_variables, default_enabled: :yaml) + if ::Feature.enabled?(:ci_workflow_rules_variables, pipeline.project, default_enabled: :yaml) raise ArgumentError, 'missing workflow rules result' unless @command.workflow_rules_result end @@ -51,7 +51,7 @@ module Gitlab end def root_variables - if ::Feature.enabled?(:ci_workflow_rules_variables, default_enabled: :yaml) + if ::Feature.enabled?(:ci_workflow_rules_variables, pipeline.project, default_enabled: :yaml) ::Gitlab::Ci::Variables::Helpers.merge_variables( @command.yaml_processor_result.root_variables, @command.workflow_rules_result.variables ) diff --git a/lib/gitlab/ci/pipeline/seed/build.rb b/lib/gitlab/ci/pipeline/seed/build.rb index 722ef1d658e..39dee7750d6 100644 --- a/lib/gitlab/ci/pipeline/seed/build.rb +++ b/lib/gitlab/ci/pipeline/seed/build.rb @@ -213,7 +213,7 @@ module Gitlab end def recalculate_yaml_variables! - return unless ::Feature.enabled?(:ci_workflow_rules_variables, default_enabled: :yaml) + return unless ::Feature.enabled?(:ci_workflow_rules_variables, @pipeline.project, default_enabled: :yaml) @seed_attributes[:yaml_variables] = Gitlab::Ci::Variables::Helpers.inherit_yaml_variables( from: @context.root_variables, to: @job_variables, inheritance: @root_variables_inheritance diff --git a/lib/gitlab/database/migrations/background_migration_helpers.rb b/lib/gitlab/database/migrations/background_migration_helpers.rb index 320ff907c68..8d5ea652bfc 100644 --- a/lib/gitlab/database/migrations/background_migration_helpers.rb +++ b/lib/gitlab/database/migrations/background_migration_helpers.rb @@ -190,11 +190,7 @@ module Gitlab migration_status = batch_max_value.nil? ? :finished : :active batch_max_value ||= batch_min_value - # We keep track of the estimated number of tuples to reason later - # about the overall progress of a migration. - total_tuple_count = Gitlab::Database::PgClass.for_table(batch_table_name)&.cardinality_estimate - - Gitlab::Database::BackgroundMigration::BatchedMigration.create!( + migration = Gitlab::Database::BackgroundMigration::BatchedMigration.create!( job_class_name: job_class_name, table_name: batch_table_name, column_name: batch_column_name, @@ -205,8 +201,18 @@ module Gitlab batch_size: batch_size, sub_batch_size: sub_batch_size, job_arguments: job_arguments, - status: migration_status, - total_tuple_count: total_tuple_count) + status: migration_status) + + # This guard is necessary since #total_tuple_count was only introduced schema-wise, + # after this migration helper had been used for the first time. + return migration unless migration.respond_to?(:total_tuple_count) + + # We keep track of the estimated number of tuples to reason later + # about the overall progress of a migration. + migration.total_tuple_count = Gitlab::Database::PgClass.for_table(batch_table_name)&.cardinality_estimate + migration.save! + + migration end def perform_background_migration_inline? diff --git a/lib/gitlab/web_ide/config/entry/terminal.rb b/lib/gitlab/web_ide/config/entry/terminal.rb index 514fca1435c..ec07023461f 100644 --- a/lib/gitlab/web_ide/config/entry/terminal.rb +++ b/lib/gitlab/web_ide/config/entry/terminal.rb @@ -55,7 +55,7 @@ module Gitlab { tag_list: tags || [], yaml_variables: yaml_variables, # https://gitlab.com/gitlab-org/gitlab/-/issues/300581 - job_variables: job_variables, + job_variables: yaml_variables, options: { image: image_value, services: services_value, @@ -74,12 +74,6 @@ module Gitlab end end end - - def job_variables - return unless ::Feature.enabled?(:ci_workflow_rules_variables, default_enabled: :yaml) - - yaml_variables - end end end end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 90f564fdd42..c7df470f207 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -16044,6 +16044,9 @@ msgstr "" msgid "ImageViewerDimensions|W" msgstr "" +msgid "Impersonate" +msgstr "" + msgid "Impersonation Tokens" msgstr "" @@ -27173,6 +27176,9 @@ msgstr "" msgid "SSH key" msgstr "" +msgid "SSH keys" +msgstr "" + msgid "SSH keys allow you to establish a secure connection between your computer and GitLab." msgstr "" @@ -27669,7 +27675,7 @@ msgstr "" msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}." msgstr "" -msgid "SecurityOrchestration|A security policy project can be used enforce policies for a given project, group, or instance. It allows you to speficy security policies that are important to you and enforce them with every commit." +msgid "SecurityOrchestration|A security policy project can be used enforce policies for a given project, group, or instance. It allows you to specify security policies that are important to you and enforce them with every commit." msgstr "" msgid "SecurityOrchestration|Create a policy" @@ -29017,6 +29023,9 @@ msgstr "" msgid "Something went wrong on our end" msgstr "" +msgid "Something went wrong on our end while loading the code quality diff." +msgstr "" + msgid "Something went wrong on our end." msgstr "" @@ -30988,7 +30997,7 @@ msgstr "" msgid "The merge request can now be merged." msgstr "" -msgid "The merge request has been updated, and the number of code quality violations in this file has changed." +msgid "The merge request has made changes to this file that affect the number of code quality violations in it." msgstr "" msgid "The metric must be one of %{metrics}." diff --git a/package.json b/package.json index 868ac33d8e3..c5b6d7da605 100644 --- a/package.json +++ b/package.json @@ -176,11 +176,11 @@ "commander": "^2.18.0", "custom-jquery-matchers": "^2.1.0", "docdash": "^1.0.2", - "eslint": "7.21.0", + "eslint": "7.24.0", "eslint-import-resolver-jest": "3.0.0", "eslint-import-resolver-webpack": "0.13.0", "eslint-plugin-jasmine": "4.1.2", - "eslint-plugin-no-jquery": "2.5.0", + "eslint-plugin-no-jquery": "2.6.0", "gettext-extractor": "^3.5.3", "gettext-extractor-vue": "^5.0.0", "glob": "^7.1.6", diff --git a/qa/qa/service/praefect_manager.rb b/qa/qa/service/praefect_manager.rb index 59effc4c184..5adc52680f0 100644 --- a/qa/qa/service/praefect_manager.rb +++ b/qa/qa/service/praefect_manager.rb @@ -225,6 +225,10 @@ module QA ) end + def health_check_failure_message?(msg) + ['error when pinging healthcheck', 'failed checking node health'].include?(msg) + end + def wait_for_no_praefect_storage_error # If a healthcheck error was the last message to be logged, we'll keep seeing that message even if it's no longer a problem # That is, there's no message shown in the Praefect logs when the healthcheck succeeds @@ -241,7 +245,7 @@ module QA QA::Runtime::Logger.debug(line.chomp) log = JSON.parse(line) - break true if log['msg'] != 'error when pinging healthcheck' + break true unless health_check_failure_message?(log['msg']) rescue JSON::ParserError # Ignore lines that can't be parsed as JSON end @@ -302,7 +306,7 @@ module QA QA::Runtime::Logger.debug(line.chomp) log = JSON.parse(line) - log['msg'] == 'error when pinging healthcheck' && log['storage'] == node + health_check_failure_message?(log['msg']) && log['storage'] == node rescue JSON::ParserError # Ignore lines that can't be parsed as JSON end diff --git a/qa/qa/specs/features/api/3_create/gitaly/gitaly_mtls_spec.rb b/qa/qa/specs/features/api/3_create/gitaly/gitaly_mtls_spec.rb index 2b331e1a2f4..8c3b8d88a29 100644 --- a/qa/qa/specs/features/api/3_create/gitaly/gitaly_mtls_spec.rb +++ b/qa/qa/specs/features/api/3_create/gitaly/gitaly_mtls_spec.rb @@ -2,7 +2,7 @@ module QA RSpec.describe 'Create' do - context 'Gitaly', :orchestrated, :mtls, quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/324622', type: :investigating } do + context 'Gitaly', :orchestrated, :mtls do describe 'Using mTLS' do let(:intial_commit_message) { 'Initial commit' } let(:first_added_commit_message) { 'commit over git' } diff --git a/scripts/gitaly_test.rb b/scripts/gitaly_test.rb index f970457fea7..e348149bb46 100644 --- a/scripts/gitaly_test.rb +++ b/scripts/gitaly_test.rb @@ -52,7 +52,8 @@ module GitalyTest 'RUBYOPT' => nil, # Git hooks can't run during tests as the internal API is not running. - 'GITALY_TESTING_NO_GIT_HOOKS' => "1" + 'GITALY_TESTING_NO_GIT_HOOKS' => "1", + 'GITALY_TESTING_ENABLE_ALL_FEATURE_FLAGS' => "true" } env_hash diff --git a/spec/frontend/diffs/store/actions_spec.js b/spec/frontend/diffs/store/actions_spec.js index 1861de85ca9..f46a42fae7a 100644 --- a/spec/frontend/diffs/store/actions_spec.js +++ b/spec/frontend/diffs/store/actions_spec.js @@ -17,9 +17,6 @@ import { fetchDiffFilesBatch, fetchDiffFilesMeta, fetchCoverageFiles, - clearEtagPoll, - stopCodequalityPolling, - fetchCodequality, assignDiscussionsToDiff, removeDiscussionsFromDiff, startRenderDiffsQueue, @@ -101,7 +98,6 @@ describe('DiffsStoreActions', () => { const endpointMetadata = '/diffs/set/endpoint/metadata'; const endpointBatch = '/diffs/set/endpoint/batch'; const endpointCoverage = '/diffs/set/coverage_reports'; - const endpointCodequality = '/diffs/set/codequality_diff'; const projectPath = '/root/project'; const dismissEndpoint = '/-/user_callouts'; const showSuggestPopover = false; @@ -113,7 +109,6 @@ describe('DiffsStoreActions', () => { endpointBatch, endpointMetadata, endpointCoverage, - endpointCodequality, projectPath, dismissEndpoint, showSuggestPopover, @@ -123,7 +118,6 @@ describe('DiffsStoreActions', () => { endpointBatch: '', endpointMetadata: '', endpointCoverage: '', - endpointCodequality: '', projectPath: '', dismissEndpoint: '', showSuggestPopover: true, @@ -136,7 +130,6 @@ describe('DiffsStoreActions', () => { endpointMetadata, endpointBatch, endpointCoverage, - endpointCodequality, projectPath, dismissEndpoint, showSuggestPopover, @@ -306,47 +299,6 @@ describe('DiffsStoreActions', () => { }); }); - describe('fetchCodequality', () => { - let mock; - const endpointCodequality = '/fetch'; - - beforeEach(() => { - mock = new MockAdapter(axios); - }); - - afterEach(() => { - stopCodequalityPolling(); - clearEtagPoll(); - }); - - it('should commit SET_CODEQUALITY_DATA with received response', (done) => { - const data = { - files: { 'app.js': [{ line: 1, description: 'Unexpected alert.', severity: 'minor' }] }, - }; - - mock.onGet(endpointCodequality).reply(200, { data }); - - testAction( - fetchCodequality, - {}, - { endpointCodequality }, - [{ type: types.SET_CODEQUALITY_DATA, payload: { data } }], - [], - done, - ); - }); - - it('should show flash on API error', (done) => { - mock.onGet(endpointCodequality).reply(400); - - testAction(fetchCodequality, {}, { endpointCodequality }, [], [], () => { - expect(createFlash).toHaveBeenCalledTimes(1); - expect(createFlash).toHaveBeenCalledWith(expect.stringMatching('Something went wrong')); - done(); - }); - }); - }); - describe('setHighlightedRow', () => { it('should mark currently selected diff and set lineHash and fileHash of highlightedRow', () => { testAction(setHighlightedRow, 'ABC_123', {}, [ diff --git a/spec/frontend/diffs/store/getters_spec.js b/spec/frontend/diffs/store/getters_spec.js index aac4909b151..2e3a66d5b01 100644 --- a/spec/frontend/diffs/store/getters_spec.js +++ b/spec/frontend/diffs/store/getters_spec.js @@ -376,26 +376,6 @@ describe('Diffs Module Getters', () => { }); }); - describe('fileCodequalityDiff', () => { - beforeEach(() => { - Object.assign(localState.codequalityDiff, { - files: { 'app.js': [{ line: 1, description: 'Unexpected alert.', severity: 'minor' }] }, - }); - }); - - it('returns empty array when no codequality data is available', () => { - Object.assign(localState.codequalityDiff, {}); - - expect(getters.fileCodequalityDiff(localState)('test.js')).toEqual([]); - }); - - it('returns array when codequality data is available for given file', () => { - expect(getters.fileCodequalityDiff(localState)('app.js')).toEqual([ - { line: 1, description: 'Unexpected alert.', severity: 'minor' }, - ]); - }); - }); - describe('suggestionCommitMessage', () => { let rootState; diff --git a/spec/frontend/diffs/store/mutations_spec.js b/spec/frontend/diffs/store/mutations_spec.js index eb31724ee45..b549ca42634 100644 --- a/spec/frontend/diffs/store/mutations_spec.js +++ b/spec/frontend/diffs/store/mutations_spec.js @@ -115,19 +115,6 @@ describe('DiffsStoreMutations', () => { }); }); - describe('SET_CODEQUALITY_DATA', () => { - it('should set codequality data', () => { - const state = { codequalityDiff: {} }; - const codequality = { - files: { 'app.js': [{ line: 1, description: 'Unexpected alert.', severity: 'minor' }] }, - }; - - mutations[types.SET_CODEQUALITY_DATA](state, codequality); - - expect(state.codequalityDiff).toEqual(codequality); - }); - }); - describe('SET_DIFF_VIEW_TYPE', () => { it('should set diff view type properly', () => { const state = {}; diff --git a/spec/frontend/fixtures/api_markdown.yml b/spec/frontend/fixtures/api_markdown.yml index 4e458e364e1..a83d5374e2c 100644 --- a/spec/frontend/fixtures/api_markdown.yml +++ b/spec/frontend/fixtures/api_markdown.yml @@ -4,5 +4,47 @@ --- - name: bold markdown: '**bold**' -- name: code +- name: emphasis + markdown: '_emphasized text_' +- name: inline_code markdown: '`code`' +- name: link + markdown: '[GitLab](https://gitlab.com)' +- name: code_block + markdown: |- + ```javascript + console.log('hello world') + ``` +- name: headings + markdown: |- + # Heading 1 + + ## Heading 2 + + ### Heading 3 + + #### Heading 4 + + ##### Heading 5 + + ###### Heading 6 +- name: blockquote + markdown: |- + > This is a blockquote + > + > This is another one +- name: thematic_break + markdown: |- + --- +- name: bullet_list + markdown: |- + * list item 1 + * list item 2 + * embedded list item 3 +- name: ordered_list + markdown: |- + 1. list item 1 + 2. list item 2 + 3. list item 3 +- name: image + markdown: '![alt text](https://gitlab.com/logo.png)' diff --git a/spec/frontend/pipelines/pipelines_ci_templates_spec.js b/spec/frontend/pipelines/pipelines_ci_templates_spec.js index d52da22922a..d4cf6027ff7 100644 --- a/spec/frontend/pipelines/pipelines_ci_templates_spec.js +++ b/spec/frontend/pipelines/pipelines_ci_templates_spec.js @@ -1,4 +1,5 @@ import { shallowMount } from '@vue/test-utils'; +import ExperimentTracking from '~/experimentation/experiment_tracking'; import PipelinesCiTemplate from '~/pipelines/components/pipelines_list/pipelines_ci_templates.vue'; const addCiYmlPath = "/-/new/master?commit_message='Add%20.gitlab-ci.yml'"; @@ -8,6 +9,8 @@ const suggestedCiTemplates = [ { name: 'C++', logo: '/assets/illustrations/logos/c_plus_plus.svg' }, ]; +jest.mock('~/experimentation/experiment_tracking'); + describe('Pipelines CI Templates', () => { let wrapper; @@ -81,4 +84,28 @@ describe('Pipelines CI Templates', () => { ); }); }); + + describe('tracking', () => { + beforeEach(() => { + wrapper = createWrapper(); + }); + + it('sends an event when template is clicked', () => { + findTemplateLinks().at(0).vm.$emit('click'); + + expect(ExperimentTracking).toHaveBeenCalledWith('pipeline_empty_state_templates', { + label: 'Android', + }); + expect(ExperimentTracking.prototype.event).toHaveBeenCalledWith('template_clicked'); + }); + + it('sends an event when Hello-World template is clicked', () => { + findTestTemplateLinks().at(0).vm.$emit('click'); + + expect(ExperimentTracking).toHaveBeenCalledWith('pipeline_empty_state_templates', { + label: 'Hello-World', + }); + expect(ExperimentTracking.prototype.event).toHaveBeenCalledWith('template_clicked'); + }); + }); }); diff --git a/spec/lib/gitlab/ci/config/entry/processable_spec.rb b/spec/lib/gitlab/ci/config/entry/processable_spec.rb index 6914eb15279..016d59e98b9 100644 --- a/spec/lib/gitlab/ci/config/entry/processable_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/processable_spec.rb @@ -389,20 +389,6 @@ RSpec.describe Gitlab::Ci::Config::Entry::Processable do end end - context 'when FF ci_workflow_rules_variables is disabled' do - before do - stub_feature_flags(ci_workflow_rules_variables: false) - end - - it 'does not return job_variables and root_variables_inheritance' do - expect(entry.value).to include( - variables: { 'A' => 'job', 'B' => 'job' } - ) - expect(entry.value).not_to have_key(:job_variables) - expect(entry.value).not_to have_key(:root_variables_inheritance) - end - end - context 'when root yaml variables are used' do let(:variables) do Gitlab::Ci::Config::Entry::Variables.new( @@ -520,21 +506,6 @@ RSpec.describe Gitlab::Ci::Config::Entry::Processable do root_variables_inheritance: true ) end - - context 'when FF ci_workflow_rules_variables is disabled' do - before do - stub_feature_flags(ci_workflow_rules_variables: false) - end - - it 'does not return job_variables and root_variables_inheritance' do - expect(entry.value).to eq( - name: :rspec, - stage: 'test', - only: { refs: %w[branches tags] }, - variables: {} - ) - end - end end end end diff --git a/spec/lib/gitlab/ci/config/normalizer/matrix_strategy_spec.rb b/spec/lib/gitlab/ci/config/normalizer/matrix_strategy_spec.rb index 0e3ea697a32..e5f0341c5fe 100644 --- a/spec/lib/gitlab/ci/config/normalizer/matrix_strategy_spec.rb +++ b/spec/lib/gitlab/ci/config/normalizer/matrix_strategy_spec.rb @@ -107,54 +107,5 @@ RSpec.describe Gitlab::Ci::Config::Normalizer::MatrixStrategy do ['test: [aws, app1]', 'test: [aws, app2]', 'test: [gcp, app]', 'test: [ovh, app]'] ) end - - context 'when the FF ci_workflow_rules_variables is disabled' do - before do - stub_feature_flags(ci_workflow_rules_variables: false) - end - - it 'excludes job_variables' do - expect(subject.map(&:attributes)).to match_array( - [ - { - name: 'test: [aws, app1]', - instance: 1, - parallel: { total: 4 }, - variables: { - 'PROVIDER' => 'aws', - 'STACK' => 'app1' - } - }, - { - name: 'test: [aws, app2]', - instance: 2, - parallel: { total: 4 }, - variables: { - 'PROVIDER' => 'aws', - 'STACK' => 'app2' - } - }, - { - name: 'test: [ovh, app]', - instance: 3, - parallel: { total: 4 }, - variables: { - 'PROVIDER' => 'ovh', - 'STACK' => 'app' - } - }, - { - name: 'test: [gcp, app]', - instance: 4, - parallel: { total: 4 }, - variables: { - 'PROVIDER' => 'gcp', - 'STACK' => 'app' - } - } - ] - ) - end - end end end diff --git a/spec/lib/gitlab/web_ide/config/entry/terminal_spec.rb b/spec/lib/gitlab/web_ide/config/entry/terminal_spec.rb index b0a52a094ac..59e53f9f64a 100644 --- a/spec/lib/gitlab/web_ide/config/entry/terminal_spec.rb +++ b/spec/lib/gitlab/web_ide/config/entry/terminal_spec.rb @@ -151,26 +151,6 @@ RSpec.describe Gitlab::WebIde::Config::Entry::Terminal do } ) end - - context 'when FF ci_workflow_rules_variables is disabled' do - before do - stub_feature_flags(ci_workflow_rules_variables: false) - end - - it 'returns correct value without job_variables' do - expect(entry.value) - .to eq( - tag_list: ['webide'], - yaml_variables: [{ key: 'KEY', value: 'value', public: true }], - options: { - image: { name: "ruby:2.5" }, - services: [{ name: "mysql" }], - before_script: %w[ls pwd], - script: ['sleep 100'] - } - ) - end - end end end end diff --git a/spec/models/concerns/milestoneish_spec.rb b/spec/models/concerns/milestoneish_spec.rb index 9a1a2669c6c..46a876f34e9 100644 --- a/spec/models/concerns/milestoneish_spec.rb +++ b/spec/models/concerns/milestoneish_spec.rb @@ -2,30 +2,28 @@ require 'spec_helper' -RSpec.describe Milestone, 'Milestoneish' do - let(:author) { create(:user) } - let(:assignee) { create(:user) } - let(:non_member) { create(:user) } - let(:member) { create(:user) } - let(:guest) { create(:user) } - let(:admin) { create(:admin) } - let(:project) { create(:project, :public) } - let(:milestone) { create(:milestone, project: project) } - let(:label1) { create(:label, project: project) } - let(:label2) { create(:label, project: project) } - let!(:issue) { create(:issue, project: project, milestone: milestone, assignees: [member], labels: [label1]) } - let!(:security_issue_1) { create(:issue, :confidential, project: project, author: author, milestone: milestone, labels: [label2]) } - let!(:security_issue_2) { create(:issue, :confidential, project: project, assignees: [assignee], milestone: milestone) } - let!(:closed_issue_1) { create(:issue, :closed, project: project, milestone: milestone) } - let!(:closed_issue_2) { create(:issue, :closed, project: project, milestone: milestone) } - let!(:closed_security_issue_1) { create(:issue, :confidential, :closed, project: project, author: author, milestone: milestone) } - let!(:closed_security_issue_2) { create(:issue, :confidential, :closed, project: project, assignees: [assignee], milestone: milestone) } - let!(:closed_security_issue_3) { create(:issue, :confidential, :closed, project: project, author: author, milestone: milestone) } - let!(:closed_security_issue_4) { create(:issue, :confidential, :closed, project: project, assignees: [assignee], milestone: milestone) } - let!(:merge_request) { create(:merge_request, source_project: project, target_project: project, milestone: milestone) } - let(:label_1) { create(:label, title: 'label_1', project: project, priority: 1) } - let(:label_2) { create(:label, title: 'label_2', project: project, priority: 2) } - let(:label_3) { create(:label, title: 'label_3', project: project) } +RSpec.describe Milestone, 'Milestoneish', factory_default: :keep do + let_it_be(:author) { create(:user) } + let_it_be(:assignee) { create(:user) } + let_it_be(:non_member) { create(:user) } + let_it_be(:member) { create(:user) } + let_it_be(:guest) { create(:user) } + let_it_be(:admin) { create(:admin) } + let_it_be(:project, reload: true) { create_default(:project, :public, :empty_repo).freeze } + let_it_be(:milestone, refind: true) { create_default(:milestone, project: project) } + let_it_be(:label1) { create(:label) } + let_it_be(:label2) { create(:label) } + let_it_be(:issue, reload: true) { create(:issue, milestone: milestone, assignees: [member], labels: [label1]) } + let_it_be(:security_issue_1, reload: true) { create(:issue, :confidential, author: author, milestone: milestone, labels: [label2]) } + let_it_be(:security_issue_2, reload: true) { create(:issue, :confidential, assignees: [assignee], milestone: milestone) } + let_it_be(:closed_issue_1, reload: true) { create(:issue, :closed, milestone: milestone) } + let_it_be(:closed_issue_2, reload: true) { create(:issue, :closed, milestone: milestone) } + let_it_be(:closed_security_issue_1, reload: true) { create(:issue, :confidential, :closed, author: author, milestone: milestone) } + let_it_be(:closed_security_issue_2, reload: true) { create(:issue, :confidential, :closed, assignees: [assignee], milestone: milestone) } + let_it_be(:merge_request) { create(:merge_request, source_project: project, target_project: project, milestone: milestone) } + let_it_be(:label_1) { create(:label, title: 'label_1', priority: 1) } + let_it_be(:label_2) { create(:label, title: 'label_2', priority: 2) } + let_it_be(:label_3) { create(:label, title: 'label_3') } before do project.add_developer(member) @@ -63,7 +61,7 @@ RSpec.describe Milestone, 'Milestoneish' do end end - context 'attributes visibility' do + context 'with attributes visibility' do using RSpec::Parameterized::TableSyntax let(:users) do @@ -167,8 +165,6 @@ RSpec.describe Milestone, 'Milestoneish' do end describe '#merge_requests_visible_to_user' do - let(:merge_request) { create(:merge_request, source_project: project, milestone: milestone) } - context 'when project is private' do before do project.update!(visibility_level: Gitlab::VisibilityLevel::PRIVATE) @@ -211,10 +207,11 @@ RSpec.describe Milestone, 'Milestoneish' do end context 'when milestone is at parent level group' do - let(:parent_group) { create(:group) } - let(:group) { create(:group, parent: parent_group) } - let(:project) { create(:project, namespace: group) } - let(:milestone) { create(:milestone, group: parent_group) } + let_it_be(:parent_group) { create(:group) } + let_it_be(:group) { create(:group, parent: parent_group) } + let_it_be(:project) { create(:project, :empty_repo, namespace: group) } + let_it_be(:milestone) { create(:milestone, group: parent_group) } + let_it_be(:merge_request) { create(:merge_request, source_project: project, milestone: milestone) } it 'does not return any merge request for a non member' do merge_requests = milestone.merge_requests_visible_to_user(non_member) @@ -243,7 +240,7 @@ RSpec.describe Milestone, 'Milestoneish' do end describe '#percent_complete', :use_clean_rails_memory_store_caching do - context 'division by zero' do + context 'with division by zero' do let(:new_milestone) { build_stubbed(:milestone) } it { expect(new_milestone.percent_complete).to eq(0) } @@ -252,13 +249,13 @@ RSpec.describe Milestone, 'Milestoneish' do describe '#closed_issues_count' do it 'counts all closed issues including confidential' do - expect(milestone.closed_issues_count).to eq 6 + expect(milestone.closed_issues_count).to eq 4 end end describe '#total_issues_count' do it 'counts all issues including confidential' do - expect(milestone.total_issues_count).to eq 9 + expect(milestone.total_issues_count).to eq 7 end end diff --git a/spec/services/merge_requests/resolve_todos_service_spec.rb b/spec/services/merge_requests/resolve_todos_service_spec.rb new file mode 100644 index 00000000000..3e6f2ea3f5d --- /dev/null +++ b/spec/services/merge_requests/resolve_todos_service_spec.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe MergeRequests::ResolveTodosService do + let_it_be(:merge_request) { create(:merge_request) } + let_it_be(:user) { create(:user) } + + let(:service) { described_class.new(merge_request, user) } + + describe '#async_execute' do + def async_execute + service.async_execute + end + + it 'performs MergeRequests::ResolveTodosWorker asynchronously' do + expect(MergeRequests::ResolveTodosWorker) + .to receive(:perform_async) + .with( + merge_request.id, + user.id + ) + + async_execute + end + + context 'when resolve_merge_request_todos_async feature is disabled' do + before do + stub_feature_flags(resolve_merge_request_todos_async: false) + end + + it 'calls #execute' do + expect(service).to receive(:execute) + + async_execute + end + end + end + + describe '#execute' do + it 'marks pending todo as done' do + pending_todo = create(:todo, :pending, user: user, project: merge_request.project, target: merge_request) + + service.execute + + expect(pending_todo.reload).to be_done + end + end +end diff --git a/spec/services/merge_requests/update_service_spec.rb b/spec/services/merge_requests/update_service_spec.rb index 24b7c3b933b..9346c92f98b 100644 --- a/spec/services/merge_requests/update_service_spec.rb +++ b/spec/services/merge_requests/update_service_spec.rb @@ -590,48 +590,54 @@ RSpec.describe MergeRequests::UpdateService, :mailer do let!(:pending_todo) { create(:todo, :assigned, user: user, project: project, target: merge_request, author: user2) } context 'when the title change' do - before do - update_merge_request({ title: 'New title' }) - end + it 'calls MergeRequest::ResolveTodosService#async_execute' do + expect_next_instance_of(MergeRequests::ResolveTodosService, merge_request, user) do |service| + expect(service).to receive(:async_execute) + end - it 'marks pending todos as done' do - expect(pending_todo.reload).to be_done + update_merge_request({ title: 'New title' }) end it 'does not create any new todos' do + update_merge_request({ title: 'New title' }) + expect(Todo.count).to eq(1) end end context 'when the description change' do - before do - update_merge_request({ description: "Also please fix #{user2.to_reference} #{user3.to_reference}" }) - end + it 'calls MergeRequest::ResolveTodosService#async_execute' do + expect_next_instance_of(MergeRequests::ResolveTodosService, merge_request, user) do |service| + expect(service).to receive(:async_execute) + end - it 'marks pending todos as done' do - expect(pending_todo.reload).to be_done + update_merge_request({ description: "Also please fix #{user2.to_reference} #{user3.to_reference}" }) end it 'creates only 1 new todo' do + update_merge_request({ description: "Also please fix #{user2.to_reference} #{user3.to_reference}" }) + expect(Todo.count).to eq(2) end end context 'when is reassigned' do - before do - update_merge_request({ assignee_ids: [user2.id] }) - end + it 'calls MergeRequest::ResolveTodosService#async_execute' do + expect_next_instance_of(MergeRequests::ResolveTodosService, merge_request, user) do |service| + expect(service).to receive(:async_execute) + end - it 'marks previous assignee pending todos as done' do - expect(pending_todo.reload).to be_done + update_merge_request({ assignee_ids: [user2.id] }) end end context 'when reviewers gets changed' do - it 'marks pending todo as done' do - update_merge_request({ reviewer_ids: [user2.id] }) + it 'calls MergeRequest::ResolveTodosService#async_execute' do + expect_next_instance_of(MergeRequests::ResolveTodosService, merge_request, user) do |service| + expect(service).to receive(:async_execute) + end - expect(pending_todo.reload).to be_done + update_merge_request({ reviewer_ids: [user2.id] }) end it 'creates a pending todo for new review request' do @@ -709,10 +715,12 @@ RSpec.describe MergeRequests::UpdateService, :mailer do end end - it 'marks pending todos as done' do - update_merge_request({ milestone: create(:milestone, project: project) }) + it 'calls MergeRequests::ResolveTodosService#async_execute' do + expect_next_instance_of(MergeRequests::ResolveTodosService, merge_request, user) do |service| + expect(service).to receive(:async_execute) + end - expect(pending_todo.reload).to be_done + update_merge_request({ milestone: create(:milestone, project: project) }) end it 'sends notifications for subscribers of changed milestone', :sidekiq_might_not_need_inline do @@ -726,17 +734,19 @@ RSpec.describe MergeRequests::UpdateService, :mailer do end context 'when the labels change' do - before do - travel_to(1.minute.from_now) do - update_merge_request({ label_ids: [label.id] }) + it 'calls MergeRequests::ResolveTodosService#async_execute' do + expect_next_instance_of(MergeRequests::ResolveTodosService, merge_request, user) do |service| + expect(service).to receive(:async_execute) end - end - it 'marks pending todos as done' do - expect(pending_todo.reload).to be_done + update_merge_request({ label_ids: [label.id] }) end it 'updates updated_at' do + travel_to(1.minute.from_now) do + update_merge_request({ label_ids: [label.id] }) + end + expect(merge_request.reload.updated_at).to be > Time.current end end @@ -751,24 +761,26 @@ RSpec.describe MergeRequests::UpdateService, :mailer do end context 'when the target branch change' do - before do - update_merge_request({ target_branch: 'target' }) - end + it 'calls MergeRequests::ResolveTodosService#async_execute' do + expect_next_instance_of(MergeRequests::ResolveTodosService, merge_request, user) do |service| + expect(service).to receive(:async_execute) + end - it 'marks pending todos as done' do - expect(pending_todo.reload).to be_done + update_merge_request({ target_branch: 'target' }) end end context 'when auto merge is enabled and target branch changed' do before do AutoMergeService.new(project, user, { sha: merge_request.diff_head_sha }).execute(merge_request, AutoMergeService::STRATEGY_MERGE_WHEN_PIPELINE_SUCCEEDS) - - update_merge_request({ target_branch: 'target' }) end - it 'marks pending todos as done' do - expect(pending_todo.reload).to be_done + it 'calls MergeRequests::ResolveTodosService#async_execute' do + expect_next_instance_of(MergeRequests::ResolveTodosService, merge_request, user) do |service| + expect(service).to receive(:async_execute) + end + + update_merge_request({ target_branch: 'target' }) end end end diff --git a/spec/workers/merge_requests/resolve_todos_worker_spec.rb b/spec/workers/merge_requests/resolve_todos_worker_spec.rb new file mode 100644 index 00000000000..223b8b6803c --- /dev/null +++ b/spec/workers/merge_requests/resolve_todos_worker_spec.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe MergeRequests::ResolveTodosWorker do + include AfterNextHelpers + + let_it_be(:merge_request) { create(:merge_request) } + let_it_be(:user) { create(:user) } + + let(:worker) { described_class.new } + + it_behaves_like 'an idempotent worker' do + let(:job_args) { [merge_request.id, user.id] } + end + + describe '#perform' do + it 'calls MergeRequests::ResolveTodosService#execute' do + expect_next(::MergeRequests::ResolveTodosService, merge_request, user) + .to receive(:execute) + + worker.perform(merge_request.id, user.id) + end + + context 'with a non-existing merge request' do + it 'does nothing' do + expect(::MergeRequests::ResolveTodosService).not_to receive(:new) + + worker.perform(non_existing_record_id, user.id) + end + end + + context 'with a non-existing user' do + it 'does nothing' do + expect(::MergeRequests::ResolveTodosService).not_to receive(:new) + + worker.perform(merge_request.id, non_existing_record_id) + end + end + end +end diff --git a/yarn.lock b/yarn.lock index 7d72d00c912..d704d66184c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4703,10 +4703,10 @@ eslint-plugin-jest@^23.8.2: dependencies: "@typescript-eslint/experimental-utils" "^2.5.0" -eslint-plugin-no-jquery@2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-no-jquery/-/eslint-plugin-no-jquery-2.5.0.tgz#6c12e3aae172bfd3363b7ac8c3f3e944704867f4" - integrity sha512-RrQ380mUJJKdjgpQ/tZAJ3B3W1n3LbVmULooS2Pv5pUDcc5uVHVSJMTdUlsbvQyfo6hWP2LJ4FbOoDzENWcF7A== +eslint-plugin-no-jquery@2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-no-jquery/-/eslint-plugin-no-jquery-2.6.0.tgz#7892cb7c086f7813156bca6bc48429825428e9eb" + integrity sha512-xC7pbNHJMdyxqhzcNMRrmC5/tbt1T4KCKXjOqUpKm/CaRryGKS5iWztzWPrL0KwyI3R3ub6goHFmIQS19f+mZA== eslint-plugin-promise@^4.2.1: version "4.2.1" @@ -4761,10 +4761,10 @@ eslint-visitor-keys@^2.0.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz#21fdc8fbcd9c795cc0321f0563702095751511a8" integrity sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ== -eslint@7.21.0: - version "7.21.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.21.0.tgz#4ecd5b8c5b44f5dedc9b8a110b01bbfeb15d1c83" - integrity sha512-W2aJbXpMNofUp0ztQaF40fveSsJBjlSCSWpy//gzfTvwC+USs/nceBrKmlJOiM8r1bLwP2EuYkCqArn/6QTIgg== +eslint@7.24.0: + version "7.24.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.24.0.tgz#2e44fa62d93892bfdb100521f17345ba54b8513a" + integrity sha512-k9gaHeHiFmGCDQ2rEfvULlSLruz6tgfA8DEn+rY9/oYPFFTlz55mM/Q/Rij1b2Y42jwZiK3lXvNTw6w6TXzcKQ== dependencies: "@babel/code-frame" "7.12.11" "@eslint/eslintrc" "^0.4.0" @@ -4783,7 +4783,7 @@ eslint@7.21.0: file-entry-cache "^6.0.1" functional-red-black-tree "^1.0.1" glob-parent "^5.0.0" - globals "^12.1.0" + globals "^13.6.0" ignore "^4.0.6" import-fresh "^3.0.0" imurmurhash "^0.1.4" @@ -4791,7 +4791,7 @@ eslint@7.21.0: js-yaml "^3.13.1" json-stable-stringify-without-jsonify "^1.0.1" levn "^0.4.1" - lodash "^4.17.20" + lodash "^4.17.21" minimatch "^3.0.4" natural-compare "^1.4.0" optionator "^0.9.1" @@ -5619,6 +5619,13 @@ globals@^12.1.0: dependencies: type-fest "^0.8.1" +globals@^13.6.0: + version "13.8.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.8.0.tgz#3e20f504810ce87a8d72e55aecf8435b50f4c1b3" + integrity sha512-rHtdA6+PDBIjeEvA91rpqzEvk/k3/i7EeNQiryiWuJH0Hw9cpyJMAt2jtbAwUaRdhD+573X4vWw6IcjKPasi9Q== + dependencies: + type-fest "^0.20.2" + globby@^11.0.2: version "11.0.2" resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.2.tgz#1af538b766a3b540ebfb58a32b2e2d5897321d83" @@ -7833,10 +7840,10 @@ lodash.values@^4.3.0: resolved "https://registry.yarnpkg.com/lodash.values/-/lodash.values-4.3.0.tgz#a3a6c2b0ebecc5c2cba1c17e6e620fe81b53d347" integrity sha1-o6bCsOvsxcLLocF+bmIP6BtT00c= -lodash@^4.0.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@~4.17.10: - version "4.17.20" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" - integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== +lodash@^4.0.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@~4.17.10: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== log-symbols@^2.1.0: version "2.2.0" @@ -11781,6 +11788,11 @@ type-fest@^0.18.0: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.18.1.tgz#db4bc151a4a2cf4eebf9add5db75508db6cc841f" integrity sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw== +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + type-fest@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b" |