diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-07-04 15:10:11 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-07-04 15:10:11 +0300 |
commit | cef4494e260d221524fc4e7e1d06d7554fdc7daa (patch) | |
tree | 711ecf05d532c728c8f255fb208c20d68d05113b | |
parent | 5f95234f7babb69685710dbfc637f29eeac2a917 (diff) |
Add latest changes from gitlab-org/gitlab@master
49 files changed, 370 insertions, 280 deletions
diff --git a/.rubocop_todo/layout/first_hash_element_indentation.yml b/.rubocop_todo/layout/first_hash_element_indentation.yml index 007616b40b1..5f586cc6206 100644 --- a/.rubocop_todo/layout/first_hash_element_indentation.yml +++ b/.rubocop_todo/layout/first_hash_element_indentation.yml @@ -9,7 +9,6 @@ Layout/FirstHashElementIndentation: - 'app/controllers/projects/badges_controller.rb' - 'app/controllers/projects/merge_requests_controller.rb' - 'app/controllers/repositories/lfs_locks_api_controller.rb' - - 'app/experiments/concerns/project_commit_count.rb' - 'app/graphql/mutations/notes/create/diff_note.rb' - 'app/graphql/mutations/notes/create/image_diff_note.rb' - 'app/graphql/mutations/notes/create/note.rb' diff --git a/.rubocop_todo/layout/line_length.yml b/.rubocop_todo/layout/line_length.yml index 99d866627d0..ed2245f39e0 100644 --- a/.rubocop_todo/layout/line_length.yml +++ b/.rubocop_todo/layout/line_length.yml @@ -3210,7 +3210,6 @@ Layout/LineLength: - 'spec/controllers/uploads_controller_spec.rb' - 'spec/db/schema_spec.rb' - 'spec/deprecation_toolkit_env.rb' - - 'spec/experiments/concerns/project_commit_count_spec.rb' - 'spec/factories/ci/job_artifacts.rb' - 'spec/factories/ci/pipelines.rb' - 'spec/factories/ci/reports/codequality_degradations.rb' diff --git a/.rubocop_todo/lint/empty_block.yml b/.rubocop_todo/lint/empty_block.yml index 5751ca7641f..dbcef42eab4 100644 --- a/.rubocop_todo/lint/empty_block.yml +++ b/.rubocop_todo/lint/empty_block.yml @@ -4,7 +4,6 @@ Lint/EmptyBlock: - 'app/controllers/groups/boards_controller.rb' - 'app/controllers/projects/boards_controller.rb' - 'app/controllers/projects/pipelines_controller.rb' - - 'app/experiments/logged_out_marketing_header_experiment.rb' - 'config/application.rb' - 'ee/app/controllers/projects/learn_gitlab_controller.rb' - 'ee/spec/factories/incident_management/escalation_rules.rb' diff --git a/.rubocop_todo/rspec/described_class.yml b/.rubocop_todo/rspec/described_class.yml index 94ef19d7cfe..7f0db541ab0 100644 --- a/.rubocop_todo/rspec/described_class.yml +++ b/.rubocop_todo/rspec/described_class.yml @@ -46,7 +46,6 @@ RSpec/DescribedClass: - 'spec/config/settings_spec.rb' - 'spec/controllers/repositories/git_http_controller_spec.rb' - 'spec/experiments/application_experiment_spec.rb' - - 'spec/experiments/concerns/project_commit_count_spec.rb' - 'spec/frontend/fixtures/timezones.rb' - 'spec/graphql/gitlab_schema_spec.rb' - 'spec/graphql/graphql_triggers_spec.rb' diff --git a/.rubocop_todo/rspec/missing_feature_category.yml b/.rubocop_todo/rspec/missing_feature_category.yml index b03146e74ae..5dab0b6c5e1 100644 --- a/.rubocop_todo/rspec/missing_feature_category.yml +++ b/.rubocop_todo/rspec/missing_feature_category.yml @@ -1801,8 +1801,6 @@ RSpec/MissingFeatureCategory: - 'spec/dependencies/omniauth_saml_spec.rb' - 'spec/docs_screenshots/container_registry_docs.rb' - 'spec/docs_screenshots/wiki_docs.rb' - - 'spec/experiments/concerns/project_commit_count_spec.rb' - - 'spec/experiments/force_company_trial_experiment_spec.rb' - 'spec/experiments/in_product_guidance_environments_webide_experiment_spec.rb' - 'spec/experiments/ios_specific_templates_experiment_spec.rb' - 'spec/features/admin/dashboard_spec.rb' diff --git a/.rubocop_todo/rspec/verified_doubles.yml b/.rubocop_todo/rspec/verified_doubles.yml index d5430dabbf0..3b4d4bc9e94 100644 --- a/.rubocop_todo/rspec/verified_doubles.yml +++ b/.rubocop_todo/rspec/verified_doubles.yml @@ -260,7 +260,6 @@ RSpec/VerifiedDoubles: - 'spec/controllers/projects/snippets_controller_spec.rb' - 'spec/controllers/sessions_controller_spec.rb' - 'spec/dependencies/omniauth_saml_spec.rb' - - 'spec/experiments/concerns/project_commit_count_spec.rb' - 'spec/factories/ci/job_artifacts.rb' - 'spec/features/admin/admin_system_info_spec.rb' - 'spec/features/clusters/create_agent_spec.rb' diff --git a/app/assets/javascripts/content_editor/components/formatting_toolbar.vue b/app/assets/javascripts/content_editor/components/formatting_toolbar.vue index b6c16e9f306..4f26ed7fac5 100644 --- a/app/assets/javascripts/content_editor/components/formatting_toolbar.vue +++ b/app/assets/javascripts/content_editor/components/formatting_toolbar.vue @@ -1,5 +1,7 @@ <script> import CommentTemplatesDropdown from '~/vue_shared/components/markdown/comment_templates_dropdown.vue'; +import { __, sprintf } from '~/locale'; +import { getModifierKey } from '~/constants'; import trackUIControl from '../services/track_ui_control'; import ToolbarButton from './toolbar_button.vue'; import ToolbarAttachmentButton from './toolbar_attachment_button.vue'; @@ -32,6 +34,27 @@ export default { required: false, }, }, + data() { + const modifierKey = getModifierKey(); + const shiftKey = modifierKey === '⌘' ? '⇧' : 'Shift+'; + + return { + i18n: { + bold: sprintf(__('Bold (%{modifierKey}B)'), { modifierKey }), + italic: sprintf(__('Italic (%{modifierKey}I)'), { modifierKey }), + strike: sprintf(__('Strikethrough (%{modifierKey}%{shiftKey}X)'), { + modifierKey, + shiftKey, + }), + quote: __('Insert a quote'), + code: __('Code'), + link: sprintf(__('Insert link (%{modifierKey}K)'), { modifierKey }), + bulletList: __('Add a bullet list'), + numberedList: __('Add a numbered list'), + taskList: __('Add a checklist'), + }, + }; + }, methods: { trackToolbarControlExecution({ contentType, value }) { trackUIControl({ property: contentType, value }); @@ -58,7 +81,7 @@ export default { content-type="bold" icon-name="bold" editor-command="toggleBold" - :label="__('Bold text')" + :label="i18n.bold" @execute="trackToolbarControlExecution" /> <toolbar-button @@ -66,7 +89,7 @@ export default { content-type="italic" icon-name="italic" editor-command="toggleItalic" - :label="__('Italic text')" + :label="i18n.italic" @execute="trackToolbarControlExecution" /> <toolbar-button @@ -74,7 +97,7 @@ export default { content-type="strike" icon-name="strikethrough" editor-command="toggleStrike" - :label="__('Strikethrough')" + :label="i18n.strike" @execute="trackToolbarControlExecution" /> <toolbar-button @@ -82,7 +105,7 @@ export default { content-type="blockquote" icon-name="quote" editor-command="toggleBlockquote" - :label="__('Insert a quote')" + :label="i18n.quote" @execute="trackToolbarControlExecution" /> <toolbar-button @@ -90,7 +113,7 @@ export default { content-type="code" icon-name="code" editor-command="toggleCode" - :label="__('Code')" + :label="i18n.code" @execute="trackToolbarControlExecution" /> <toolbar-button @@ -98,7 +121,7 @@ export default { content-type="link" icon-name="link" editor-command="editLink" - :label="__('Insert link')" + :label="i18n.link" @execute="trackToolbarControlExecution" /> <toolbar-button @@ -107,7 +130,7 @@ export default { icon-name="list-bulleted" class="gl-display-none gl-sm-display-inline" editor-command="toggleBulletList" - :label="__('Add a bullet list')" + :label="i18n.bulletList" @execute="trackToolbarControlExecution" /> <toolbar-button @@ -116,7 +139,7 @@ export default { icon-name="list-numbered" class="gl-display-none gl-sm-display-inline" editor-command="toggleOrderedList" - :label="__('Add a numbered list')" + :label="i18n.numberedList" @execute="trackToolbarControlExecution" /> <toolbar-button @@ -125,7 +148,7 @@ export default { icon-name="list-task" class="gl-display-none gl-sm-display-inline" editor-command="toggleTaskList" - :label="__('Add a checklist')" + :label="i18n.taskList" @execute="trackToolbarControlExecution" /> <toolbar-table-button data-testid="table" @execute="trackToolbarControlExecution" /> diff --git a/app/assets/javascripts/content_editor/components/toolbar_table_button.vue b/app/assets/javascripts/content_editor/components/toolbar_table_button.vue index 771455dfe66..ab1546b9016 100644 --- a/app/assets/javascripts/content_editor/components/toolbar_table_button.vue +++ b/app/assets/javascripts/content_editor/components/toolbar_table_button.vue @@ -1,5 +1,6 @@ <script> -import { GlDisclosureDropdown, GlButton, GlTooltipDirective as GlTooltip } from '@gitlab/ui'; +import { GlDisclosureDropdown, GlButton, GlTooltip } from '@gitlab/ui'; +import { uniqueId } from 'lodash'; import { __, sprintf } from '~/locale'; import { clamp } from '../services/utils'; @@ -14,13 +15,12 @@ export default { components: { GlButton, GlDisclosureDropdown, - }, - directives: { GlTooltip, }, inject: ['tiptapEditor'], data() { return { + toggleId: uniqueId('dropdown-toggle-btn-'), maxRows: MIN_ROWS, maxCols: MIN_COLS, rows: 1, @@ -82,44 +82,47 @@ export default { }; </script> <template> - <gl-disclosure-dropdown - ref="dropdown" - v-gl-tooltip - size="small" - category="tertiary" - icon="table" - no-caret - :aria-label="__('Insert table')" - :toggle-text="__('Insert table')" - positioning-strategy="fixed" - class="content-editor-table-dropdown gl-mr-3" - text-sr-only - :fluid-width="true" - @shown="setFocus(1, 1)" - > - <div - class="gl-p-3 gl-pt-2" - role="grid" - :aria-colcount="$options.MAX_COLS" - :aria-rowcount="$options.MAX_ROWS" + <div class="gl-display-inline-flex gl-vertical-align-middle"> + <gl-disclosure-dropdown + ref="dropdown" + :toggle-id="toggleId" + size="small" + category="tertiary" + icon="table" + no-caret + :aria-label="__('Insert table')" + :toggle-text="__('Insert table')" + positioning-strategy="fixed" + class="content-editor-table-dropdown gl-mr-3" + text-sr-only + :fluid-width="true" + @shown="setFocus(1, 1)" > - <div v-for="r of list(maxRows)" :key="r" class="gl-display-flex" role="row"> - <div v-for="c of list(maxCols)" :key="c" role="gridcell"> - <gl-button - :ref="`table-${r}-${c}`" - :class="{ 'active gl-bg-blue-50!': r <= rows && c <= cols }" - :aria-label="getButtonLabel(r, c)" - class="table-creator-grid-item gl-display-inline gl-rounded-0! gl-w-6! gl-h-6! gl-p-0!" - @mouseover="setRowsAndCols(r, c)" - @focus="setRowsAndCols(r, c)" - @click="insertTable()" - @keydown="onKeydown($event.key)" - /> + <div + class="gl-p-3 gl-pt-2" + role="grid" + :aria-colcount="$options.MAX_COLS" + :aria-rowcount="$options.MAX_ROWS" + > + <div v-for="r of list(maxRows)" :key="r" class="gl-display-flex" role="row"> + <div v-for="c of list(maxCols)" :key="c" role="gridcell"> + <gl-button + :ref="`table-${r}-${c}`" + :class="{ 'active gl-bg-blue-50!': r <= rows && c <= cols }" + :aria-label="getButtonLabel(r, c)" + class="table-creator-grid-item gl-display-inline gl-rounded-0! gl-w-6! gl-h-6! gl-p-0!" + @mouseover="setRowsAndCols(r, c)" + @focus="setRowsAndCols(r, c)" + @click="insertTable()" + @keydown="onKeydown($event.key)" + /> + </div> </div> </div> - </div> - <div class="gl-border-t gl-px-4 gl-pt-3 gl-pb-2"> - {{ getButtonLabel(rows, cols) }} - </div> - </gl-disclosure-dropdown> + <div class="gl-border-t gl-px-4 gl-pt-3 gl-pb-2"> + {{ getButtonLabel(rows, cols) }} + </div> + </gl-disclosure-dropdown> + <gl-tooltip :target="toggleId" placement="top">{{ __('Insert table') }}</gl-tooltip> + </div> </template> diff --git a/app/assets/javascripts/pages/projects/blob/show/index.js b/app/assets/javascripts/pages/projects/blob/show/index.js index f8dcf1a5c9c..0b0399ef271 100644 --- a/app/assets/javascripts/pages/projects/blob/show/index.js +++ b/app/assets/javascripts/pages/projects/blob/show/index.js @@ -18,6 +18,7 @@ import { generateRefDestinationPath } from '~/repository/utils/ref_switcher_util import RefSelector from '~/ref/components/ref_selector.vue'; import { joinPaths, visitUrl } from '~/lib/utils/url_utility'; import { parseBoolean } from '~/lib/utils/common_utils'; +import HighlightWorker from '~/vue_shared/components/source_viewer/workers/highlight_worker?worker'; Vue.use(Vuex); Vue.use(VueApollo); @@ -78,6 +79,7 @@ if (viewBlobEl) { router, apolloProvider, provide: { + highlightWorker: gon.features.highlightJsWorker ? new HighlightWorker() : null, targetBranch, originalBranch, resourceId, diff --git a/app/assets/javascripts/repository/components/blob_content_viewer.vue b/app/assets/javascripts/repository/components/blob_content_viewer.vue index e056a822c8b..3d30b42b2aa 100644 --- a/app/assets/javascripts/repository/components/blob_content_viewer.vue +++ b/app/assets/javascripts/repository/components/blob_content_viewer.vue @@ -15,6 +15,7 @@ import CodeIntelligence from '~/code_navigation/components/app.vue'; import LineHighlighter from '~/blob/line_highlighter'; import blobInfoQuery from 'shared_queries/repository/blob_info.query.graphql'; import { addBlameLink } from '~/blob/blob_blame_link'; +import highlightMixin from '~/repository/mixins/highlight_mixin'; import projectInfoQuery from '../queries/project_info.query.graphql'; import getRefMixin from '../mixins/get_ref'; import userInfoQuery from '../queries/user_info.query.graphql'; @@ -36,7 +37,7 @@ export default { CodeIntelligence, AiGenie: () => import('ee_component/ai/components/ai_genie.vue'), }, - mixins: [getRefMixin, glFeatureFlagMixin()], + mixins: [getRefMixin, glFeatureFlagMixin(), highlightMixin], inject: { originalBranch: { default: '', @@ -81,7 +82,10 @@ export default { shouldFetchRawText: Boolean(this.glFeatures.highlightJs), }; }, - result() { + result({ data }) { + const blob = data.project?.repository?.blobs?.nodes[0] || {}; + this.initHighlightWorker(blob); + const urlHash = getLocationHash(); const plain = this.$route?.query?.plain; @@ -170,7 +174,14 @@ export default { }, blobViewer() { const { fileType } = this.viewer; - return this.shouldLoadLegacyViewer ? null : loadViewer(fileType, this.isUsingLfs); + return this.shouldLoadLegacyViewer + ? null + : loadViewer( + fileType, + this.isUsingLfs, + this.glFeatures.highlightJsWorker, + this.blobInfo.language, + ); }, shouldLoadLegacyViewer() { const isTextFile = this.viewer.fileType === TEXT_FILE_TYPE && !this.glFeatures.highlightJs; @@ -386,7 +397,14 @@ export default { :loading="isLoadingLegacyViewer" :data-loading="isRenderingLegacyTextViewer" /> - <component :is="blobViewer" v-else :blob="blobInfo" class="blob-viewer" @error="onError" /> + <component + :is="blobViewer" + v-else + :blob="blobInfo" + :chunks="chunks" + class="blob-viewer" + @error="onError" + /> <code-intelligence v-if="blobViewer || legacyViewerLoaded" :code-navigation-path="blobInfo.codeNavigationPath" diff --git a/app/assets/javascripts/repository/components/blob_viewers/index.js b/app/assets/javascripts/repository/components/blob_viewers/index.js index b749702972f..368f42e0064 100644 --- a/app/assets/javascripts/repository/components/blob_viewers/index.js +++ b/app/assets/javascripts/repository/components/blob_viewers/index.js @@ -15,9 +15,15 @@ const viewers = { geo_json: () => import('./geo_json/geo_json_viewer.vue'), }; -export const loadViewer = (type, isUsingLfs) => { +export const loadViewer = (type, isUsingLfs, hljsWorkerEnabled, language) => { let viewer = viewers[type]; + if (hljsWorkerEnabled && language === 'json') { + // The New Source Viewer currently only supports JSON files. + // More language support will be added in: https://gitlab.com/gitlab-org/gitlab/-/issues/415753 + viewer = () => import('~/vue_shared/components/source_viewer/source_viewer_new.vue'); + } + if (!viewer && isUsingLfs) { viewer = viewers.lfs; } diff --git a/app/assets/javascripts/repository/index.js b/app/assets/javascripts/repository/index.js index befd731a61b..c1e0104c6ac 100644 --- a/app/assets/javascripts/repository/index.js +++ b/app/assets/javascripts/repository/index.js @@ -8,6 +8,7 @@ import initWebIdeLink from '~/pages/projects/shared/web_ide_link'; import PerformancePlugin from '~/performance/vue_performance_plugin'; import createStore from '~/code_navigation/store'; import RefSelector from '~/ref/components/ref_selector.vue'; +import HighlightWorker from '~/vue_shared/components/source_viewer/workers/highlight_worker?worker'; import App from './components/app.vue'; import Breadcrumbs from './components/breadcrumbs.vue'; import DirectoryDownloadLinks from './components/directory_download_links.vue'; @@ -290,7 +291,12 @@ export default function setupVueRepositoryList() { store: createStore(), router, apolloProvider, - provide: { resourceId, userId, explainCodeAvailable: parseBoolean(explainCodeAvailable) }, + provide: { + resourceId, + userId, + explainCodeAvailable: parseBoolean(explainCodeAvailable), + highlightWorker: gon.features.highlightJsWorker ? new HighlightWorker() : null, + }, render(h) { return h(App); }, diff --git a/app/assets/javascripts/repository/mixins/highlight_mixin.js b/app/assets/javascripts/repository/mixins/highlight_mixin.js index 95d0c55bb04..232cb0dac03 100644 --- a/app/assets/javascripts/repository/mixins/highlight_mixin.js +++ b/app/assets/javascripts/repository/mixins/highlight_mixin.js @@ -1,4 +1,3 @@ -import { nextTick } from 'vue'; import { LEGACY_FALLBACKS, EVENT_ACTION, @@ -39,7 +38,7 @@ export default { this?.onError(); }, initHighlightWorker({ rawTextBlob, language, simpleViewer }) { - if (simpleViewer?.fileType !== TEXT_FILE_TYPE) return; + if (simpleViewer?.fileType !== TEXT_FILE_TYPE || !this.glFeatures.highlightJsWorker) return; if (this.isUnsupportedLanguage(language)) { this.handleUnsupportedLanguage(language); @@ -97,7 +96,7 @@ export default { } // Line numbers in the DOM needs to update first based on changes made to `chunks`. - await nextTick(); + await this.$nextTick(); const lineHighlighter = new LineHighlighter({ scrollBehavior: 'auto' }); lineHighlighter.highlightHash(hash); diff --git a/app/assets/javascripts/vue_shared/components/markdown/header.vue b/app/assets/javascripts/vue_shared/components/markdown/header.vue index c794ed951ef..0899b752cbc 100644 --- a/app/assets/javascripts/vue_shared/components/markdown/header.vue +++ b/app/assets/javascripts/vue_shared/components/markdown/header.vue @@ -97,10 +97,12 @@ export default { }, }, data() { + const modifierKey = getModifierKey(); return { tag: '> ', suggestPopoverVisible: false, - modifierKey: getModifierKey(), + modifierKey, + shiftKey: modifierKey === '⌘' ? '⇧' : 'Shift+', }; }, computed: { @@ -346,8 +348,9 @@ export default { tag="~~" :button-title=" /* eslint-disable @gitlab/vue-no-new-non-primitive-in-template */ - sprintf(s__('MarkdownEditor|Add strikethrough text (%{modifierKey}⇧X)'), { - modifierKey /* eslint-enable @gitlab/vue-no-new-non-primitive-in-template */, + sprintf(s__('MarkdownEditor|Add strikethrough text (%{modifierKey}%{shiftKey}X)'), { + modifierKey, + shiftKey /* eslint-enable @gitlab/vue-no-new-non-primitive-in-template */, }) " :shortcuts="$options.shortcuts.strikethrough" diff --git a/app/assets/javascripts/vue_shared/components/source_viewer/plugins/index.js b/app/assets/javascripts/vue_shared/components/source_viewer/plugins/index.js index d694adf7147..3f8a9258fc3 100644 --- a/app/assets/javascripts/vue_shared/components/source_viewer/plugins/index.js +++ b/app/assets/javascripts/vue_shared/components/source_viewer/plugins/index.js @@ -1,6 +1,7 @@ import wrapChildNodes from './wrap_child_nodes'; import linkDependencies from './link_dependencies'; import wrapBidiChars from './wrap_bidi_chars'; +import wrapLines from './wrap_lines'; export const HLJS_ON_AFTER_HIGHLIGHT = 'after:highlight'; @@ -11,10 +12,11 @@ export const HLJS_ON_AFTER_HIGHLIGHT = 'after:highlight'; * * @param {Object} hljs - the Highlight.js instance. */ -export const registerPlugins = (hljs, fileType, rawContent) => { +export const registerPlugins = (hljs, fileType, rawContent, shouldWrapLines) => { hljs.addPlugin({ [HLJS_ON_AFTER_HIGHLIGHT]: wrapChildNodes }); hljs.addPlugin({ [HLJS_ON_AFTER_HIGHLIGHT]: wrapBidiChars }); hljs.addPlugin({ [HLJS_ON_AFTER_HIGHLIGHT]: (result) => linkDependencies(result, fileType, rawContent), }); + if (shouldWrapLines) hljs.addPlugin({ [HLJS_ON_AFTER_HIGHLIGHT]: wrapLines }); }; diff --git a/app/assets/javascripts/vue_shared/components/source_viewer/plugins/wrap_lines.js b/app/assets/javascripts/vue_shared/components/source_viewer/plugins/wrap_lines.js new file mode 100644 index 00000000000..384ada30001 --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/source_viewer/plugins/wrap_lines.js @@ -0,0 +1,20 @@ +/** + * Highlight.js plugin for wrapping lines in the correct classes and attributes. + * Needed for things like hash highlighting to work. + * + * Plugin API: https://github.com/highlightjs/highlight.js/blob/main/docs/plugin-api.rst + * + * @param {Object} Result - an object that represents the highlighted result from Highlight.js + */ + +function wrapLine(content, number, language) { + return `<div id="LC${number}" lang="${language}" class="line">${content}</div>`; +} + +export default (result) => { + // eslint-disable-next-line no-param-reassign + result.value = result.value + .split(/\r?\n/) + .map((content, index) => wrapLine(content, index + 1, result.language)) + .join('\n'); +}; diff --git a/app/assets/javascripts/vue_shared/components/source_viewer/source_viewer_new.vue b/app/assets/javascripts/vue_shared/components/source_viewer/source_viewer_new.vue index 7e18c8414d5..4d4d15a12b4 100644 --- a/app/assets/javascripts/vue_shared/components/source_viewer/source_viewer_new.vue +++ b/app/assets/javascripts/vue_shared/components/source_viewer/source_viewer_new.vue @@ -19,9 +19,6 @@ export default { SafeHtml, }, mixins: [Tracking.mixin()], - inject: { - highlightWorker: { default: null }, - }, props: { blob: { type: Object, diff --git a/app/assets/javascripts/vue_shared/components/source_viewer/workers/highlight_utils.js b/app/assets/javascripts/vue_shared/components/source_viewer/workers/highlight_utils.js index 142c135e9c1..8d8e945cd5f 100644 --- a/app/assets/javascripts/vue_shared/components/source_viewer/workers/highlight_utils.js +++ b/app/assets/javascripts/vue_shared/components/source_viewer/workers/highlight_utils.js @@ -1,9 +1,13 @@ -import hljs from 'highlight.js'; +import hljs from 'highlight.js/lib/core'; +import json from 'highlight.js/lib/languages/json'; import { registerPlugins } from '../plugins/index'; import { LINES_PER_CHUNK, NEWLINE, ROUGE_TO_HLJS_LANGUAGE_MAP } from '../constants'; -const initHighlightJs = (fileType, content) => { - registerPlugins(hljs, fileType, content); +const initHighlightJs = (fileType, content, language) => { + // The Highlight Worker is currently scoped to JSON files. + // See the following issue for more: https://gitlab.com/gitlab-org/gitlab/-/issues/415753 + hljs.registerLanguage(language, json); + registerPlugins(hljs, fileType, content, true); }; const splitByLineBreaks = (content = '') => content.split(/\r?\n/); diff --git a/app/assets/javascripts/vue_shared/components/source_viewer/workers/highlight.js b/app/assets/javascripts/vue_shared/components/source_viewer/workers/highlight_worker.js index 535e857d7a9..535e857d7a9 100644 --- a/app/assets/javascripts/vue_shared/components/source_viewer/workers/highlight.js +++ b/app/assets/javascripts/vue_shared/components/source_viewer/workers/highlight_worker.js diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb index a60cc5301e2..b41e4d11d24 100644 --- a/app/controllers/projects/blob_controller.rb +++ b/app/controllers/projects/blob_controller.rb @@ -49,6 +49,7 @@ class Projects::BlobController < Projects::ApplicationController before_action do push_frontend_feature_flag(:highlight_js, @project) + push_frontend_feature_flag(:highlight_js_worker, @project) push_frontend_feature_flag(:explain_code_chat, current_user) push_licensed_feature(:file_locks) if @project.licensed_feature_available?(:file_locks) end diff --git a/app/controllers/projects/tree_controller.rb b/app/controllers/projects/tree_controller.rb index d2a820d93b0..b961339111b 100644 --- a/app/controllers/projects/tree_controller.rb +++ b/app/controllers/projects/tree_controller.rb @@ -19,6 +19,7 @@ class Projects::TreeController < Projects::ApplicationController before_action do push_frontend_feature_flag(:highlight_js, @project) + push_frontend_feature_flag(:highlight_js_worker, @project) push_frontend_feature_flag(:explain_code_chat, current_user) push_licensed_feature(:file_locks) if @project.licensed_feature_available?(:file_locks) end diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index bc4831d7772..51f6158d9c0 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -38,6 +38,7 @@ class ProjectsController < Projects::ApplicationController before_action do push_frontend_feature_flag(:highlight_js, @project) + push_frontend_feature_flag(:highlight_js_worker, @project) push_frontend_feature_flag(:remove_monitor_metrics, @project) push_frontend_feature_flag(:explain_code_chat, current_user) push_frontend_feature_flag(:ci_namespace_catalog_experimental, @project) diff --git a/app/experiments/concerns/project_commit_count.rb b/app/experiments/concerns/project_commit_count.rb deleted file mode 100644 index 3f08538c21f..00000000000 --- a/app/experiments/concerns/project_commit_count.rb +++ /dev/null @@ -1,21 +0,0 @@ -# frozen_string_literal: true - -module ProjectCommitCount - include Gitlab::Git::WrapsGitalyErrors - - def commit_count_for(project, default_count: 0, max_count: nil, **exception_details) - raw_repo = project.repository&.raw_repository - root_ref = raw_repo&.root_ref - - return default_count unless root_ref - - Gitlab::GitalyClient::CommitService.new(raw_repo).commit_count(root_ref, { - all: true, # include all branches - max_count: max_count # limit as an optimization - }) - rescue StandardError => e - Gitlab::ErrorTracking.track_exception(e, exception_details) - - default_count - end -end diff --git a/app/graphql/resolvers/alert_management/http_integrations_resolver.rb b/app/graphql/resolvers/alert_management/http_integrations_resolver.rb index 225e20bab83..ac04e0967e6 100644 --- a/app/graphql/resolvers/alert_management/http_integrations_resolver.rb +++ b/app/graphql/resolvers/alert_management/http_integrations_resolver.rb @@ -35,7 +35,7 @@ module Resolvers end def http_integrations - ::AlertManagement::HttpIntegrationsFinder.new(project, {}).execute + ::AlertManagement::HttpIntegrationsFinder.new(project, { type_identifier: :http }).execute end end end diff --git a/app/graphql/resolvers/alert_management/integrations_resolver.rb b/app/graphql/resolvers/alert_management/integrations_resolver.rb index a97650e95d9..9b20d3367f1 100644 --- a/app/graphql/resolvers/alert_management/integrations_resolver.rb +++ b/app/graphql/resolvers/alert_management/integrations_resolver.rb @@ -40,7 +40,7 @@ module Resolvers def http_integrations return [] unless http_integrations_allowed? - ::AlertManagement::HttpIntegrationsFinder.new(project, {}).execute + ::AlertManagement::HttpIntegrationsFinder.new(project, { type_identifier: :http }).execute end def prometheus_integrations_allowed? diff --git a/app/graphql/resolvers/concerns/issues/look_ahead_preloads.rb b/app/graphql/resolvers/concerns/issues/look_ahead_preloads.rb index 2ea7a02bf15..d9bcf39b818 100644 --- a/app/graphql/resolvers/concerns/issues/look_ahead_preloads.rb +++ b/app/graphql/resolvers/concerns/issues/look_ahead_preloads.rb @@ -20,17 +20,15 @@ module Issues end def preloads - preload_hash = { + { alert_management_alert: [:alert_management_alert], assignees: [:assignees], participants: Issue.participant_includes, timelogs: [:timelogs], customer_relations_contacts: { customer_relations_contacts: [:group] }, - escalation_status: [:incident_management_issuable_escalation_status] + escalation_status: [:incident_management_issuable_escalation_status], + type: :work_item_type } - preload_hash[:type] = :work_item_type if Feature.enabled?(:issue_type_uses_work_item_types_table) - - preload_hash end end end diff --git a/app/models/issue.rb b/app/models/issue.rb index 0afe8916455..453c451cebf 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -204,24 +204,17 @@ class Issue < ApplicationRecord scope :with_issue_type, ->(types) { types = Array(types) - if Feature.enabled?(:issue_type_uses_work_item_types_table) - # Using != 1 since we also want the guard clause to handle empty arrays - return joins(:work_item_type).where(work_item_types: { base_type: types }) if types.size != 1 + # Using != 1 since we also want the guard clause to handle empty arrays + return joins(:work_item_type).where(work_item_types: { base_type: types }) if types.size != 1 - where( - '"issues"."work_item_type_id" = (?)', - WorkItems::Type.by_type(types.first).select(:id).limit(1) - ) - else - where(issue_type: types) - end + # This optimization helps the planer use the correct indexes when filtering by a single type + where( + '"issues"."work_item_type_id" = (?)', + WorkItems::Type.by_type(types.first).select(:id).limit(1) + ) } scope :without_issue_type, ->(types) { - if Feature.enabled?(:issue_type_uses_work_item_types_table) - joins(:work_item_type).where.not(work_item_types: { base_type: types }) - else - where.not(issue_type: types) - end + joins(:work_item_type).where.not(work_item_types: { base_type: types }) } scope :public_only, -> { where(confidential: false) } @@ -756,11 +749,7 @@ class Issue < ApplicationRecord end def issue_type - if ::Feature.enabled?(:issue_type_uses_work_item_types_table) - work_item_type_with_default.base_type - else - super - end + work_item_type_with_default.base_type end def unsubscribe_email_participant(email) diff --git a/config/application.rb b/config/application.rb index 03c7a1ae24d..d20b60b9217 100644 --- a/config/application.rb +++ b/config/application.rb @@ -18,10 +18,7 @@ Bundler.require(*Rails.groups) module Gitlab class Application < Rails::Application - config.load_defaults 6.1 - - config.active_support.hash_digest_class = ::OpenSSL::Digest::SHA256 - + config.load_defaults 7.0 # This section contains configuration from Rails upgrades to override the new defaults so that we # keep existing behavior. # @@ -31,6 +28,30 @@ module Gitlab # # To switch a setting to the new default value, we just need to delete the specific line here. + # Rails 7.0 + config.action_controller.raise_on_open_redirects = false + config.action_controller.wrap_parameters_by_default = false + config.action_dispatch.default_headers = { "X-Frame-Options" => "SAMEORIGIN", + "X-XSS-Protection" => "1; mode=block", + "X-Content-Type-Options" => "nosniff", + "X-Download-Options" => "noopen", + "X-Permitted-Cross-Domain-Policies" => "none", + "Referrer-Policy" => "strict-origin-when-cross-origin" } + + config.action_dispatch.return_only_request_media_type_on_content_type = true + config.action_mailer.smtp_timeout = nil # New default is 5 + config.action_view.button_to_generates_button_tag = nil # New default is true + config.active_record.automatic_scope_inversing = nil # New default is true + config.active_record.verify_foreign_keys_for_fixtures = nil # New default is true + config.active_record.partial_inserts = true # New default is false + config.active_support.cache_format_version = nil # New default is 7.0 + config.active_support.disable_to_s_conversion = false # New default is true + config.active_support.executor_around_test_case = nil # New default is true + config.active_support.isolation_level = nil # New default is thread + config.active_support.key_generator_hash_digest_class = nil # New default is OpenSSL::Digest::SHA256 + config.active_support.remove_deprecated_time_with_zone_name = nil # New default is true + config.active_support.use_rfc4122_namespaced_uuids = nil # New default is true + # Rails 6.1 config.action_dispatch.cookies_same_site_protection = nil # New default is :lax ActiveSupport.utc_to_local_returns_utc_offset_times = false diff --git a/config/feature_flags/development/issue_type_uses_work_item_types_table.yml b/config/feature_flags/development/highlight_js_worker.yml index 4ce66b7ab33..ee74cbb7004 100644 --- a/config/feature_flags/development/issue_type_uses_work_item_types_table.yml +++ b/config/feature_flags/development/highlight_js_worker.yml @@ -1,8 +1,8 @@ --- -name: issue_type_uses_work_item_types_table -introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/107690 -rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/386603 -milestone: '15.8' +name: highlight_js_worker +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/124276 +rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/415755 +milestone: '16.2' type: development -group: group::project management +group: group::source code default_enabled: false diff --git a/config/webpack.config.js b/config/webpack.config.js index 39052d29287..1c6ac0bc843 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -371,6 +371,20 @@ module.exports = { loader: 'babel-loader', }, { + test: /_worker\.js$/, + resourceQuery: /worker/, + use: [ + { + loader: 'worker-loader', + options: { + name: '[name].[contenthash:8].worker.js', + inline: IS_DEV_SERVER, + }, + }, + 'babel-loader', + ], + }, + { test: /mermaid\/.*\.js?$/, include: /node_modules/, loader: 'babel-loader', @@ -439,20 +453,6 @@ module.exports = { options: { limit: 2048 }, }, { - test: /_worker\.js$/, - resourceQuery: /worker/, - use: [ - { - loader: 'worker-loader', - options: { - name: '[name].[contenthash:8].worker.js', - inline: IS_DEV_SERVER, - }, - }, - 'babel-loader', - ], - }, - { test: /\.(worker(\.min)?\.js|pdf)$/, exclude: /node_modules/, loader: 'file-loader', diff --git a/doc/development/integrations/secure.md b/doc/development/integrations/secure.md index ee94e57a247..08316230954 100644 --- a/doc/development/integrations/secure.md +++ b/doc/development/integrations/secure.md @@ -626,19 +626,14 @@ This is addressed in [issue #7586](https://gitlab.com/gitlab-org/gitlab/-/issues See also [deduplication process](../../user/application_security/vulnerability_report/pipeline.md#deduplication-process). -##### Severity and confidence +##### Severity -The `severity` field describes how much the vulnerability impacts the software, -whereas the `confidence` field describes how reliable the assessment of the vulnerability is. +The `severity` field describes how badly the vulnerability impacts the software. The severity is used to sort the vulnerabilities in the security dashboard. The severity ranges from `Info` to `Critical`, but it can also be `Unknown`. Valid values are: `Unknown`, `Info`, `Low`, `Medium`, `High`, or `Critical` -The confidence ranges from `Low` to `Confirmed`, but it can also be `Unknown`, -`Experimental` or even `Ignore` if the vulnerability is to be ignored. -Valid values are: `Ignore`, `Unknown`, `Experimental`, `Low`, `Medium`, `High`, or `Confirmed` - `Unknown` values means that data is unavailable to determine it's actual value. Therefore, it may be `high`, `medium`, or `low`, and needs to be investigated. We have [provided a chart](../../user/application_security/sast/analyzers.md#data-provided-by-analyzers) of the available SAST Analyzers and what data is currently available. diff --git a/doc/user/enterprise_user/index.md b/doc/user/enterprise_user/index.md index ea320402dd7..a59a4213f74 100644 --- a/doc/user/enterprise_user/index.md +++ b/doc/user/enterprise_user/index.md @@ -10,7 +10,7 @@ type: reference Enterprise users have user accounts that are administered by an organization that has purchased a [GitLab subscription](../../subscriptions/index.md). -Enterprise users are identified by the [**Enterprise** badge](../project/badges.md) +Enterprise users are identified by the **Enterprise** badge next to their names on the [Members list](../group/index.md#filter-and-sort-members-in-a-group). ## Provision an enterprise user diff --git a/doc/user/search/index.md b/doc/user/search/index.md index 0645fd56b73..10f8dd61497 100644 --- a/doc/user/search/index.md +++ b/doc/user/search/index.md @@ -99,6 +99,32 @@ To filter code search results by one or more languages: 1. On the code search page, on the left sidebar, select one or more languages. 1. On the left sidebar, select **Apply**. +## Exclude search results + +### From archived projects + +> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121981) in GitLab 16.1 [with a flag](../../administration/feature_flags.md) named `search_projects_hide_archived`. Disabled by default. + +FLAG: +On self-managed GitLab, by default this feature is not available. To make it available, +ask an administrator to [enable the feature flag](../../administration/feature_flags.md) named `search_projects_hide_archived`. On GitLab.com, this feature is not available. + +Archived projects are included in search results by default. To exclude archived projects, ensure the `search_projects_hide_archived` flag is enabled. + +To include archived projects with `search_projects_hide_archived` enabled, you must add the parameter `include_archived=true` to the URL. + +### From issues in archived projects + +> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/124846) in GitLab 16.2 [with a flag](../../administration/feature_flags.md) named `search_issues_hide_archived_projects`. Disabled by default. + +FLAG: +On self-managed GitLab, by default this feature is not available. To make it available, +ask an administrator to [enable the feature flag](../../administration/feature_flags.md) named `search_issues_hide_archived_projects`. On GitLab.com, this feature is not available. + +Issues in archived projects are included in search results by default. To exclude issues in archived projects, ensure the `search_issues_hide_archived_projects` flag is enabled. + +To include issues in archived projects with `search_issues_hide_archived_projects` enabled, you must add the parameter `include_archived=true` to the URL. + ## Search for a project by full path > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/108906) in GitLab 15.9 [with a flag](../../administration/feature_flags.md) named `full_path_project_search`. Disabled by default. @@ -112,18 +138,6 @@ For example: - `gitlab-org/gitlab` searches for the `gitlab` project in the `gitlab-org` namespace. - `gitlab-org/` displays autocomplete suggestions for projects that belong to the `gitlab-org` namespace. -### Exclude archived projects from project search results - -> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121981) in GitLab 16.1 [with a flag](../../administration/feature_flags.md) named `search_projects_hide_archived`. Disabled by default. - -FLAG: -On self-managed GitLab, by default this feature is not available. To make it available, -ask an administrator to [enable the feature flag](../../administration/feature_flags.md) named `search_projects_hide_archived`. On GitLab.com, this feature is not available. - -Archived projects are included in project search results by default. To exclude archived projects, ensure the `search_projects_hide_archived` flag is enabled. - -To include archived projects with `search_projects_hide_archived` enabled, you must add the parameter `include_archived=true` to the URL. - ## Search for a commit SHA To search for a commit SHA: diff --git a/lib/gitlab/ci/project_config/bridge.rb b/lib/gitlab/ci/project_config/bridge.rb index c342ab2c215..45aa330508f 100644 --- a/lib/gitlab/ci/project_config/bridge.rb +++ b/lib/gitlab/ci/project_config/bridge.rb @@ -10,6 +10,11 @@ module Gitlab pipeline_source_bridge.yaml_for_downstream end + # Bridge.yaml_for_downstream injects an `include` + def internal_include_prepended? + true + end + def source :bridge_source end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index b7d1c1db37e..1ed0a415ad2 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -7904,6 +7904,9 @@ msgstr "" msgid "Board|Loading epics" msgstr "" +msgid "Bold (%{modifierKey}B)" +msgstr "" + msgid "Bold text" msgstr "" @@ -24345,7 +24348,7 @@ msgstr "" msgid "Insert comment template" msgstr "" -msgid "Insert link" +msgid "Insert link (%{modifierKey}K)" msgstr "" msgid "Insert or edit diagram" @@ -25456,6 +25459,9 @@ msgstr "" msgid "It's you" msgstr "" +msgid "Italic (%{modifierKey}I)" +msgstr "" + msgid "Italic text" msgstr "" @@ -27838,6 +27844,9 @@ msgstr "" msgid "MarkdownEditor|Add italic text (%{modifier_key}I)" msgstr "" +msgid "MarkdownEditor|Add strikethrough text (%{modifierKey}%{shiftKey}X)" +msgstr "" + msgid "MarkdownEditor|Add strikethrough text (%{modifierKey}⇧X)" msgstr "" @@ -44394,7 +44403,7 @@ msgstr "" msgid "Store your files, plan your work, collaborate on code, and more." msgstr "" -msgid "Strikethrough" +msgid "Strikethrough (%{modifierKey}%{shiftKey}X)" msgstr "" msgid "Strikethrough text" diff --git a/spec/experiments/concerns/project_commit_count_spec.rb b/spec/experiments/concerns/project_commit_count_spec.rb deleted file mode 100644 index f5969ad6241..00000000000 --- a/spec/experiments/concerns/project_commit_count_spec.rb +++ /dev/null @@ -1,41 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe ProjectCommitCount do - let(:klass) { Class.include(ProjectCommitCount) } - let(:instance) { klass.new } - - describe '#commit_count_for' do - subject { instance.commit_count_for(project, default_count: 42, caller_info: :identifiable) } - - let(:project) { create(:project, :repository) } - - context 'when a root_ref exists' do - it 'returns commit count from GitlayClient' do - allow(Gitlab::GitalyClient).to receive(:call).and_call_original - allow(Gitlab::GitalyClient).to receive(:call).with(anything, :commit_service, :count_commits, anything, anything) - .and_return(double(count: 4)) - - expect(subject).to eq(4) - end - end - - context 'when a root_ref does not exist' do - let(:project) { create(:project, :empty_repo) } - - it 'returns the default_count' do - expect(subject).to eq(42) - end - end - - it "handles exceptions by logging them with exception_details and returns the default_count" do - allow(Gitlab::GitalyClient).to receive(:call).and_call_original - allow(Gitlab::GitalyClient).to receive(:call).with(anything, :commit_service, :count_commits, anything, anything).and_raise(e = StandardError.new('_message_')) - - expect(Gitlab::ErrorTracking).to receive(:track_exception).with(e, { caller_info: :identifiable }) - - expect(subject).to eq(42) - end - end -end diff --git a/spec/frontend/content_editor/components/formatting_toolbar_spec.js b/spec/frontend/content_editor/components/formatting_toolbar_spec.js index 0e9dc8d6184..bff53375340 100644 --- a/spec/frontend/content_editor/components/formatting_toolbar_spec.js +++ b/spec/frontend/content_editor/components/formatting_toolbar_spec.js @@ -31,11 +31,12 @@ describe('content_editor/components/formatting_toolbar', () => { describe.each` testId | controlProps ${'text-styles'} | ${{}} - ${'bold'} | ${{ contentType: 'bold', iconName: 'bold', label: 'Bold text', editorCommand: 'toggleBold' }} - ${'italic'} | ${{ contentType: 'italic', iconName: 'italic', label: 'Italic text', editorCommand: 'toggleItalic' }} - ${'strike'} | ${{ contentType: 'strike', iconName: 'strikethrough', label: 'Strikethrough', editorCommand: 'toggleStrike' }} + ${'bold'} | ${{ contentType: 'bold', iconName: 'bold', label: 'Bold (Ctrl+B)', editorCommand: 'toggleBold' }} + ${'italic'} | ${{ contentType: 'italic', iconName: 'italic', label: 'Italic (Ctrl+I)', editorCommand: 'toggleItalic' }} + ${'strike'} | ${{ contentType: 'strike', iconName: 'strikethrough', label: 'Strikethrough (Ctrl+Shift+X)', editorCommand: 'toggleStrike' }} ${'blockquote'} | ${{ contentType: 'blockquote', iconName: 'quote', label: 'Insert a quote', editorCommand: 'toggleBlockquote' }} ${'code'} | ${{ contentType: 'code', iconName: 'code', label: 'Code', editorCommand: 'toggleCode' }} + ${'link'} | ${{ contentType: 'link', iconName: 'link', label: 'Insert link (Ctrl+K)', editorCommand: 'editLink' }} ${'link'} | ${{}} ${'bullet-list'} | ${{ contentType: 'bulletList', iconName: 'list-bulleted', label: 'Add a bullet list', editorCommand: 'toggleBulletList' }} ${'ordered-list'} | ${{ contentType: 'orderedList', iconName: 'list-numbered', label: 'Add a numbered list', editorCommand: 'toggleOrderedList' }} @@ -70,6 +71,24 @@ describe('content_editor/components/formatting_toolbar', () => { }); }); + describe('MacOS shortcuts', () => { + beforeEach(() => { + window.gl = { client: { isMac: true } }; + + buildWrapper(); + }); + + it.each` + testId | label + ${'bold'} | ${'Bold (⌘B)'} + ${'italic'} | ${'Italic (⌘I)'} + ${'strike'} | ${'Strikethrough (⌘⇧X)'} + ${'link'} | ${'Insert link (⌘K)'} + `('shows label $label for $testId', ({ testId, label }) => { + expect(wrapper.findByTestId(testId).props('label')).toBe(label); + }); + }); + describe('when attachment button is hidden', () => { it('does not show the attachment button', () => { buildWrapper({ props: { hideAttachmentButton: true } }); diff --git a/spec/frontend/repository/components/blob_content_viewer_spec.js b/spec/frontend/repository/components/blob_content_viewer_spec.js index 6a5ee8ba827..5b9542150f1 100644 --- a/spec/frontend/repository/components/blob_content_viewer_spec.js +++ b/spec/frontend/repository/components/blob_content_viewer_spec.js @@ -152,6 +152,7 @@ const createComponent = async (mockData = {}, mountFn = shallowMount, mockRoute ...inject, glFeatures: { highlightJs, + highlightJsWorker: false, }, }, }), @@ -405,7 +406,7 @@ describe('Blob content viewer component', () => { await waitForPromises(); - expect(loadViewer).toHaveBeenCalledWith(viewer, false); + expect(loadViewer).toHaveBeenCalledWith(viewer, false, false, 'javascript'); expect(wrapper.findComponent(loadViewerReturnValue).exists()).toBe(true); }); }); diff --git a/spec/frontend/repository/mixins/highlight_mixin_spec.js b/spec/frontend/repository/mixins/highlight_mixin_spec.js index 5f872749581..56df6d99bd3 100644 --- a/spec/frontend/repository/mixins/highlight_mixin_spec.js +++ b/spec/frontend/repository/mixins/highlight_mixin_spec.js @@ -31,7 +31,10 @@ describe('HighlightMixin', () => { const dummyComponent = { mixins: [highlightMixin], - inject: { highlightWorker: { default: workerMock } }, + inject: { + highlightWorker: { default: workerMock }, + glFeatures: { default: { highlightJsWorker: true } }, + }, template: '<div>{{chunks[0]?.highlightedContent}}</div>', created() { this.initHighlightWorker({ rawTextBlob, simpleViewer, language }); diff --git a/spec/frontend/search/topbar/components/app_spec.js b/spec/frontend/search/topbar/components/app_spec.js index 423ec6ff63b..9dc14b97ce0 100644 --- a/spec/frontend/search/topbar/components/app_spec.js +++ b/spec/frontend/search/topbar/components/app_spec.js @@ -3,6 +3,7 @@ import { shallowMount } from '@vue/test-utils'; import Vue from 'vue'; import Vuex from 'vuex'; import { MOCK_QUERY } from 'jest/search/mock_data'; +import { stubComponent } from 'helpers/stub_component'; import GlobalSearchTopbar from '~/search/topbar/components/app.vue'; import GroupFilter from '~/search/topbar/components/group_filter.vue'; import ProjectFilter from '~/search/topbar/components/project_filter.vue'; @@ -93,11 +94,20 @@ describe('GlobalSearchTopbar', () => { }); it('dispatched correct click action', () => { - const draweToggleSpy = jest.fn(); - wrapper.vm.$refs.markdownDrawer.toggleDrawer = draweToggleSpy; + const drawerToggleSpy = jest.fn(); + + createComponent( + { query: { repository_ref: '' } }, + { elasticsearchEnabled: true, defaultBranchName: '' }, + { + MarkdownDrawer: stubComponent(MarkdownDrawer, { + methods: { toggleDrawer: drawerToggleSpy }, + }), + }, + ); findSyntaxOptionButton().vm.$emit('click'); - expect(draweToggleSpy).toHaveBeenCalled(); + expect(drawerToggleSpy).toHaveBeenCalled(); }); }); diff --git a/spec/frontend/vue_shared/components/markdown/header_spec.js b/spec/frontend/vue_shared/components/markdown/header_spec.js index 4738fd44128..eb728879fb7 100644 --- a/spec/frontend/vue_shared/components/markdown/header_spec.js +++ b/spec/frontend/vue_shared/components/markdown/header_spec.js @@ -72,6 +72,39 @@ describe('Markdown field header component', () => { }); }); + it('renders correct title on non MacOS systems', () => { + window.gl = { + client: { + isMac: false, + }, + }; + + createWrapper(); + + const buttons = [ + 'Insert suggestion', + 'Add bold text (Ctrl+B)', + 'Add italic text (Ctrl+I)', + 'Add strikethrough text (Ctrl+Shift+X)', + 'Insert a quote', + 'Insert code', + 'Add a link (Ctrl+K)', + 'Add a bullet list', + 'Add a numbered list', + 'Add a checklist', + 'Indent line (Ctrl+])', + 'Outdent line (Ctrl+[)', + 'Add a collapsible section', + 'Add a table', + 'Go full screen', + ]; + const elements = findToolbarButtons(); + + elements.wrappers.forEach((buttonEl, index) => { + expect(buttonEl.props('buttonTitle')).toBe(buttons[index]); + }); + }); + it('renders "Attach a file or image" button using gl-button', () => { const button = wrapper.findByTestId('button-attach-file'); diff --git a/spec/frontend/vue_shared/components/source_viewer/highlight_util_spec.js b/spec/frontend/vue_shared/components/source_viewer/highlight_util_spec.js index d2dd4afe09e..49e3083f8ed 100644 --- a/spec/frontend/vue_shared/components/source_viewer/highlight_util_spec.js +++ b/spec/frontend/vue_shared/components/source_viewer/highlight_util_spec.js @@ -1,10 +1,11 @@ -import hljs from 'highlight.js'; +import hljs from 'highlight.js/lib/core'; import { registerPlugins } from '~/vue_shared/components/source_viewer/plugins/index'; import { highlight } from '~/vue_shared/components/source_viewer/workers/highlight_utils'; import { LINES_PER_CHUNK, NEWLINE } from '~/vue_shared/components/source_viewer/constants'; -jest.mock('highlight.js', () => ({ +jest.mock('highlight.js/lib/core', () => ({ highlight: jest.fn().mockReturnValue({ value: 'highlighted content' }), + registerLanguage: jest.fn(), })); jest.mock('~/vue_shared/components/source_viewer/plugins/index', () => ({ @@ -14,11 +15,15 @@ jest.mock('~/vue_shared/components/source_viewer/plugins/index', () => ({ const fileType = 'text'; const rawContent = 'function test() { return true }; \n // newline'; const highlightedContent = 'highlighted content'; -const language = 'javascript'; +const language = 'json'; describe('Highlight utility', () => { beforeEach(() => highlight(fileType, rawContent, language)); + it('registers the language', () => { + expect(hljs.registerLanguage).toHaveBeenCalledWith(language, expect.any(Function)); + }); + it('registers the plugins', () => { expect(registerPlugins).toHaveBeenCalled(); }); diff --git a/spec/frontend/vue_shared/components/source_viewer/plugins/wrap_lines_spec.js b/spec/frontend/vue_shared/components/source_viewer/plugins/wrap_lines_spec.js new file mode 100644 index 00000000000..def76856dba --- /dev/null +++ b/spec/frontend/vue_shared/components/source_viewer/plugins/wrap_lines_spec.js @@ -0,0 +1,12 @@ +import wrapLines from '~/vue_shared/components/source_viewer/plugins/wrap_lines'; + +describe('Highlight.js plugin for wrapping lines', () => { + it('mutates the input value by wrapping each line in a div with the correct attributes', () => { + const inputValue = `// some content`; + const outputValue = `<div id="LC1" lang="javascript" class="line">${inputValue}</div>`; + const hljsResultMock = { value: inputValue, language: 'javascript' }; + + wrapLines(hljsResultMock); + expect(hljsResultMock.value).toBe(outputValue); + }); +}); diff --git a/spec/graphql/resolvers/alert_management/http_integrations_resolver_spec.rb b/spec/graphql/resolvers/alert_management/http_integrations_resolver_spec.rb index 0f40565c5d3..80234aaaacf 100644 --- a/spec/graphql/resolvers/alert_management/http_integrations_resolver_spec.rb +++ b/spec/graphql/resolvers/alert_management/http_integrations_resolver_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Resolvers::AlertManagement::HttpIntegrationsResolver do +RSpec.describe Resolvers::AlertManagement::HttpIntegrationsResolver, feature_category: :incident_management do include GraphqlHelpers let_it_be(:guest) { create(:user) } @@ -13,6 +13,7 @@ RSpec.describe Resolvers::AlertManagement::HttpIntegrationsResolver do let_it_be(:active_http_integration) { create(:alert_management_http_integration, project: project) } let_it_be(:inactive_http_integration) { create(:alert_management_http_integration, :inactive, project: project) } let_it_be(:other_proj_integration) { create(:alert_management_http_integration) } + let_it_be(:migrated_integration) { create(:alert_management_prometheus_integration, :legacy, project: project) } let(:params) { {} } diff --git a/spec/graphql/resolvers/alert_management/integrations_resolver_spec.rb b/spec/graphql/resolvers/alert_management/integrations_resolver_spec.rb index 11114d41522..ed2e7d35ee3 100644 --- a/spec/graphql/resolvers/alert_management/integrations_resolver_spec.rb +++ b/spec/graphql/resolvers/alert_management/integrations_resolver_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Resolvers::AlertManagement::IntegrationsResolver do +RSpec.describe Resolvers::AlertManagement::IntegrationsResolver, feature_category: :incident_management do include GraphqlHelpers let_it_be(:current_user) { create(:user) } @@ -13,6 +13,7 @@ RSpec.describe Resolvers::AlertManagement::IntegrationsResolver do let_it_be(:inactive_http_integration) { create(:alert_management_http_integration, :inactive, project: project) } let_it_be(:other_proj_integration) { create(:alert_management_http_integration, project: project2) } let_it_be(:other_proj_prometheus_integration) { create(:prometheus_integration, project: project2) } + let_it_be(:migrated_integration) { create(:alert_management_prometheus_integration, :legacy, project: project) } let(:params) { {} } diff --git a/spec/lib/gitlab/ci/pipeline/chain/config/content_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/config/content_spec.rb index a9a52972294..9c268d9039e 100644 --- a/spec/lib/gitlab/ci/pipeline/chain/config/content_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/chain/config/content_spec.rb @@ -26,7 +26,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Config::Content, feature_category: : expect(pipeline.config_source).to eq 'bridge_source' expect(command.config_content).to eq 'the-yaml' - expect(command.pipeline_config.internal_include_prepended?).to eq(false) + expect(command.pipeline_config.internal_include_prepended?).to eq(true) end end diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb index 09c135a2e78..ecf9e4480eb 100644 --- a/spec/models/issue_spec.rb +++ b/spec/models/issue_spec.rb @@ -467,18 +467,6 @@ RSpec.describe Issue, feature_category: :team_planning do expect(described_class.with_issue_type([]).to_sql).to include('WHERE 1=0') end end - - context 'when the issue_type_uses_work_item_types_table feature flag is disabled' do - before do - stub_feature_flags(issue_type_uses_work_item_types_table: false) - end - - it 'uses the issue_type column for filtering' do - expect do - described_class.with_issue_type(:issue).to_a - end.to make_queries_matching(/"issues"\."issue_type" = 0/) - end - end end describe '.without_issue_type' do @@ -506,18 +494,6 @@ RSpec.describe Issue, feature_category: :team_planning do }x ) end - - context 'when the issue_type_uses_work_item_types_table feature flag is disabled' do - before do - stub_feature_flags(issue_type_uses_work_item_types_table: false) - end - - it 'uses the issue_type column for filtering' do - expect do - described_class.without_issue_type(:issue).to_a - end.to make_queries_matching(/"issues"\."issue_type" != 0/) - end - end end describe '.order_severity' do @@ -1879,39 +1855,17 @@ RSpec.describe Issue, feature_category: :team_planning do describe '#issue_type' do let_it_be(:issue) { create(:issue) } - context 'when the issue_type_uses_work_item_types_table feature flag is enabled' do - it 'gets the type field from the work_item_types table' do - expect(issue).to receive_message_chain(:work_item_type, :base_type) - - issue.issue_type - end - - context 'when the issue is not persisted' do - it 'uses the default work item type' do - non_persisted_issue = build(:issue, work_item_type: nil) + it 'gets the type field from the work_item_types table' do + expect(issue).to receive_message_chain(:work_item_type, :base_type) - expect(non_persisted_issue.issue_type).to eq(described_class::DEFAULT_ISSUE_TYPE.to_s) - end - end + issue.issue_type end - context 'when the issue_type_uses_work_item_types_table feature flag is disabled' do - before do - stub_feature_flags(issue_type_uses_work_item_types_table: false) - end - - it 'does not get the value from the work_item_types table' do - expect(issue).not_to receive(:work_item_type) - - issue.issue_type - end - - context 'when the issue is not persisted' do - it 'uses the default work item type' do - non_persisted_issue = build(:issue, work_item_type: nil) + context 'when the issue is not persisted' do + it 'uses the default work item type' do + non_persisted_issue = build(:issue, work_item_type: nil) - expect(non_persisted_issue.issue_type).to eq(described_class::DEFAULT_ISSUE_TYPE.to_s) - end + expect(non_persisted_issue.issue_type).to eq(described_class::DEFAULT_ISSUE_TYPE.to_s) end end end diff --git a/spec/simplecov_env.rb b/spec/simplecov_env.rb index 3de44482e2e..78a78f5bcbf 100644 --- a/spec/simplecov_env.rb +++ b/spec/simplecov_env.rb @@ -62,16 +62,21 @@ module SimpleCovEnv add_group 'Channels', 'app/channels' # Matches EE files as well add_group 'Components', 'app/components' # Matches EE files as well + add_group 'Config', %w[/config /ee/config] add_group 'Controllers', 'app/controllers' # Matches EE files as well + add_group 'Elastic migrations', 'ee/elastic' + add_group 'Enums', 'app/enums' # Matches EE files as well add_group 'Events', 'app/events' # Matches EE files as well add_group 'Experiments', 'app/experiments' # Matches EE files as well add_group 'Finders', 'app/finders' # Matches EE files as well + add_group 'Fixtures', 'db/fixtures' # Matches EE files as well add_group 'GraphQL', 'app/graphql' # Matches EE files as well add_group 'Helpers', 'app/helpers' # Matches EE files as well add_group 'Mailers', 'app/mailers' # Matches EE files as well add_group 'Models', 'app/models' # Matches EE files as well add_group 'Policies', 'app/policies' # Matches EE files as well add_group 'Presenters', 'app/presenters' # Matches EE files as well + add_group 'Replicators', 'app/replicators' # Matches EE files as well add_group 'Serializers', 'app/serializers' # Matches EE files as well add_group 'Services', 'app/services' # Matches EE files as well add_group 'Uploaders', 'app/uploaders' # Matches EE files as well @@ -79,9 +84,9 @@ module SimpleCovEnv add_group 'Views', 'app/views' # Matches EE files as well add_group 'Workers', 'app/workers' # Matches EE files as well add_group 'Initializers', %w[config/initializers config/initializers_before_autoloader] # Matches EE files as well - add_group 'Migrations', %w[db/migrate db/optional_migrations db/post_migrate] # Matches EE files as well + add_group 'Migrations', %w[db/migrate db/optional_migrations db/post_migrate db/geo/migrate db/geo/post_migrate] # Matches EE files as well add_group 'Libraries', %w[/lib /ee/lib] - add_group 'Tooling', %w[/haml_lint /rubocop /tooling] + add_group 'Tooling', %w[/haml_lint /rubocop /scripts /tooling] merge_timeout 365 * 24 * 3600 end diff --git a/spec/support/rspec_order_todo.yml b/spec/support/rspec_order_todo.yml index c3e0dc43c9e..9747dbea646 100644 --- a/spec/support/rspec_order_todo.yml +++ b/spec/support/rspec_order_todo.yml @@ -3536,8 +3536,6 @@ - './spec/db/schema_spec.rb' - './spec/dependencies/omniauth_saml_spec.rb' - './spec/experiments/application_experiment_spec.rb' -- './spec/experiments/concerns/project_commit_count_spec.rb' -- './spec/experiments/force_company_trial_experiment_spec.rb' - './spec/experiments/in_product_guidance_environments_webide_experiment_spec.rb' - './spec/experiments/ios_specific_templates_experiment_spec.rb' - './spec/features/abuse_report_spec.rb' |