diff options
| author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-03-31 12:08:17 +0000 |
|---|---|---|
| committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-03-31 12:08:17 +0000 |
| commit | 5820d448c17f93606afb52d878c00d84681764e0 (patch) | |
| tree | 98835aafc3d77377ba402baeb2b5110b2467bda1 | |
| parent | b654eb44a85fa358ce466b8d6cf772a660478fa9 (diff) | |
| download | gitlab-ce-5820d448c17f93606afb52d878c00d84681764e0.tar.gz | |
Add latest changes from gitlab-org/gitlab@master
108 files changed, 790 insertions, 370 deletions
diff --git a/.stylelintrc b/.stylelintrc index 6e3999fec3b..458fd51bdd7 100644 --- a/.stylelintrc +++ b/.stylelintrc @@ -9,8 +9,8 @@ "app/assets/stylesheets/lazy_bundles/cropper.css" ], "plugins":[ - "./scripts/frontend/stylelint/stylelint-duplicate-selectors.js", - "./scripts/frontend/stylelint/stylelint-utility-classes.js", + "./scripts/frontend/stylelint/stylelint_duplicate_selectors.js", + "./scripts/frontend/stylelint/stylelint_utility_classes.js", ], "rules":{ "stylelint-gitlab/utility-classes":[true,{ "severity": "warning" }], diff --git a/app/assets/javascripts/analytics/shared/utils.js b/app/assets/javascripts/analytics/shared/utils.js index dde429ab278..71b7ca29bad 100644 --- a/app/assets/javascripts/analytics/shared/utils.js +++ b/app/assets/javascripts/analytics/shared/utils.js @@ -19,6 +19,7 @@ export const toYmd = (date) => dateFormat(date, dateFormats.isoDate); * @returns {Object} */ export const extractFilterQueryParameters = (url = '') => { + /* eslint-disable camelcase */ const { source_branch_name = null, target_branch_name = null, @@ -27,6 +28,7 @@ export const extractFilterQueryParameters = (url = '') => { assignee_username = [], label_name = [], } = urlQueryToFilter(url); + /* eslint-enable camelcase */ return { selectedSourceBranch: source_branch_name, diff --git a/app/assets/javascripts/behaviors/secret_values.js b/app/assets/javascripts/behaviors/secret_values.js index a34d5dcaef8..b6ed14611cd 100644 --- a/app/assets/javascripts/behaviors/secret_values.js +++ b/app/assets/javascripts/behaviors/secret_values.js @@ -1,5 +1,5 @@ -import { parseBoolean } from '../lib/utils/common_utils'; -import { n__ } from '../locale'; +import { parseBoolean } from '~/lib/utils/common_utils'; +import { n__ } from '~/locale'; export default class SecretValues { constructor({ diff --git a/app/assets/javascripts/branches/divergence_graph.js b/app/assets/javascripts/branches/divergence_graph.js index 31cf9a18077..17fd3939441 100644 --- a/app/assets/javascripts/branches/divergence_graph.js +++ b/app/assets/javascripts/branches/divergence_graph.js @@ -1,7 +1,7 @@ import Vue from 'vue'; import createFlash from '~/flash'; -import axios from '../lib/utils/axios_utils'; -import { __ } from '../locale'; +import axios from '~/lib/utils/axios_utils'; +import { __ } from '~/locale'; import DivergenceGraph from './components/divergence_graph.vue'; export function createGraphVueApp(el, data, maxCommits, defaultBranch) { diff --git a/app/assets/javascripts/ci_variable_list/ci_variable_list.js b/app/assets/javascripts/ci_variable_list/ci_variable_list.js index 055e2f83e33..574a5e7fd99 100644 --- a/app/assets/javascripts/ci_variable_list/ci_variable_list.js +++ b/app/assets/javascripts/ci_variable_list/ci_variable_list.js @@ -1,8 +1,8 @@ import $ from 'jquery'; -import SecretValues from '../behaviors/secret_values'; -import CreateItemDropdown from '../create_item_dropdown'; -import { parseBoolean } from '../lib/utils/common_utils'; -import { s__ } from '../locale'; +import SecretValues from '~/behaviors/secret_values'; +import CreateItemDropdown from '~/create_item_dropdown'; +import { parseBoolean } from '~/lib/utils/common_utils'; +import { s__ } from '~/locale'; const ALL_ENVIRONMENTS_STRING = s__('CiVariable|All environments'); diff --git a/app/assets/javascripts/clusters/clusters_bundle.js b/app/assets/javascripts/clusters/clusters_bundle.js index 8dcab55ac61..a8fef372637 100644 --- a/app/assets/javascripts/clusters/clusters_bundle.js +++ b/app/assets/javascripts/clusters/clusters_bundle.js @@ -4,10 +4,10 @@ import Vue from 'vue'; import createFlash from '~/flash'; import AccessorUtilities from '~/lib/utils/accessor'; import initProjectSelectDropdown from '~/project_select'; -import Poll from '../lib/utils/poll'; -import { s__ } from '../locale'; -import PersistentUserCallout from '../persistent_user_callout'; -import initSettingsPanels from '../settings_panels'; +import Poll from '~/lib/utils/poll'; +import { s__ } from '~/locale'; +import PersistentUserCallout from '~/persistent_user_callout'; +import initSettingsPanels from '~/settings_panels'; import RemoveClusterConfirmation from './components/remove_cluster_confirmation.vue'; import ClustersService from './services/clusters_service'; import ClustersStore from './stores/clusters_store'; diff --git a/app/assets/javascripts/confidential_merge_request/components/project_form_group.vue b/app/assets/javascripts/confidential_merge_request/components/project_form_group.vue index 59066162960..622fd1e381a 100644 --- a/app/assets/javascripts/confidential_merge_request/components/project_form_group.vue +++ b/app/assets/javascripts/confidential_merge_request/components/project_form_group.vue @@ -1,8 +1,8 @@ <script> import { GlIcon, GlLink, GlSprintf } from '@gitlab/ui'; import createFlash from '~/flash'; -import Api from '../../api'; -import { __ } from '../../locale'; +import Api from '~/api'; +import { __ } from '~/locale'; import state from '../state'; import Dropdown from './dropdown.vue'; diff --git a/app/assets/javascripts/deprecated_notes.js b/app/assets/javascripts/deprecated_notes.js index 2301ec95167..73d872cf962 100644 --- a/app/assets/javascripts/deprecated_notes.js +++ b/app/assets/javascripts/deprecated_notes.js @@ -1,4 +1,4 @@ -/* eslint-disable no-restricted-properties, babel/camelcase, +/* eslint-disable no-restricted-properties, camelcase, no-unused-expressions, default-case, consistent-return, no-param-reassign, no-shadow, no-useless-escape, diff --git a/app/assets/javascripts/environments/mixins/environments_mixin.js b/app/assets/javascripts/environments/mixins/environments_mixin.js index 0f9741784d6..8957a3074ed 100644 --- a/app/assets/javascripts/environments/mixins/environments_mixin.js +++ b/app/assets/javascripts/environments/mixins/environments_mixin.js @@ -4,11 +4,11 @@ import { isEqual, isFunction, omitBy } from 'lodash'; import Visibility from 'visibilityjs'; import createFlash from '~/flash'; -import Poll from '../../lib/utils/poll'; -import { getParameterByName } from '../../lib/utils/url_utility'; -import { s__, __ } from '../../locale'; -import tabs from '../../vue_shared/components/navigation_tabs.vue'; -import tablePagination from '../../vue_shared/components/pagination/table_pagination.vue'; +import Poll from '~/lib/utils/poll'; +import { getParameterByName } from '~/lib/utils/url_utility'; +import { s__, __ } from '~/locale'; +import tabs from '~/vue_shared/components/navigation_tabs.vue'; +import tablePagination from '~/vue_shared/components/pagination/table_pagination.vue'; import container from '../components/container.vue'; import environmentTable from '../components/environments_table.vue'; import eventHub from '../event_hub'; diff --git a/app/assets/javascripts/feature_highlight/feature_highlight_helper.js b/app/assets/javascripts/feature_highlight/feature_highlight_helper.js index 747f368b671..b26a96499ba 100644 --- a/app/assets/javascripts/feature_highlight/feature_highlight_helper.js +++ b/app/assets/javascripts/feature_highlight/feature_highlight_helper.js @@ -1,6 +1,6 @@ import createFlash from '~/flash'; -import axios from '../lib/utils/axios_utils'; -import { __ } from '../locale'; +import axios from '~/lib/utils/axios_utils'; +import { __ } from '~/locale'; export const getSelector = (highlightId) => `.js-feature-highlight[data-highlight=${highlightId}]`; diff --git a/app/assets/javascripts/groups/components/group_folder.vue b/app/assets/javascripts/groups/components/group_folder.vue index 5f169832ee4..042d818338a 100644 --- a/app/assets/javascripts/groups/components/group_folder.vue +++ b/app/assets/javascripts/groups/components/group_folder.vue @@ -1,6 +1,6 @@ <script> import { GlIcon } from '@gitlab/ui'; -import { n__ } from '../../locale'; +import { n__ } from '~/locale'; import { MAX_CHILDREN_COUNT } from '../constants'; export default { diff --git a/app/assets/javascripts/groups/constants.js b/app/assets/javascripts/groups/constants.js index 005bac1e7b5..cacba2dfd23 100644 --- a/app/assets/javascripts/groups/constants.js +++ b/app/assets/javascripts/groups/constants.js @@ -1,4 +1,4 @@ -import { __, s__ } from '../locale'; +import { __, s__ } from '~/locale'; export const MAX_CHILDREN_COUNT = 20; diff --git a/app/assets/javascripts/ide/components/commit_sidebar/message_field.vue b/app/assets/javascripts/ide/components/commit_sidebar/message_field.vue index 8f0e5aef456..2799ea1378e 100644 --- a/app/assets/javascripts/ide/components/commit_sidebar/message_field.vue +++ b/app/assets/javascripts/ide/components/commit_sidebar/message_field.vue @@ -1,6 +1,6 @@ <script> import { GlIcon, GlPopover } from '@gitlab/ui'; -import { __, sprintf } from '../../../locale'; +import { __, sprintf } from '~/locale'; import { MAX_TITLE_LENGTH, MAX_BODY_LENGTH } from '../../constants'; export default { diff --git a/app/assets/javascripts/ide/components/jobs/detail.vue b/app/assets/javascripts/ide/components/jobs/detail.vue index 55ae5501cdb..8d6a0b99e0c 100644 --- a/app/assets/javascripts/ide/components/jobs/detail.vue +++ b/app/assets/javascripts/ide/components/jobs/detail.vue @@ -2,7 +2,7 @@ import { GlTooltipDirective, GlButton, GlIcon, GlSafeHtmlDirective } from '@gitlab/ui'; import { throttle } from 'lodash'; import { mapActions, mapState } from 'vuex'; -import { __ } from '../../../locale'; +import { __ } from '~/locale'; import JobDescription from './detail/description.vue'; import ScrollButton from './detail/scroll_button.vue'; diff --git a/app/assets/javascripts/ide/components/jobs/detail/scroll_button.vue b/app/assets/javascripts/ide/components/jobs/detail/scroll_button.vue index 6e1929a1948..bcbc68421c2 100644 --- a/app/assets/javascripts/ide/components/jobs/detail/scroll_button.vue +++ b/app/assets/javascripts/ide/components/jobs/detail/scroll_button.vue @@ -1,6 +1,6 @@ <script> import { GlIcon, GlTooltipDirective } from '@gitlab/ui'; -import { __ } from '../../../../locale'; +import { __ } from '~/locale'; const directions = { up: 'up', diff --git a/app/assets/javascripts/ide/stores/actions/tree.js b/app/assets/javascripts/ide/stores/actions/tree.js index f46d3cbe946..20d8dc3381d 100644 --- a/app/assets/javascripts/ide/stores/actions/tree.js +++ b/app/assets/javascripts/ide/stores/actions/tree.js @@ -5,7 +5,7 @@ import { WEBIDE_MARK_FETCH_FILES_START, } from '~/performance/constants'; import { performanceMarkAndMeasure } from '~/performance/utils'; -import { __ } from '../../../locale'; +import { __ } from '~/locale'; import { decorateFiles } from '../../lib/files'; import service from '../../services'; import * as types from '../mutation_types'; diff --git a/app/assets/javascripts/ide/stores/modules/commit/getters.js b/app/assets/javascripts/ide/stores/modules/commit/getters.js index 05e3601f381..0e7254e67be 100644 --- a/app/assets/javascripts/ide/stores/modules/commit/getters.js +++ b/app/assets/javascripts/ide/stores/modules/commit/getters.js @@ -1,4 +1,4 @@ -import { __ } from '../../../../locale'; +import { __ } from '~/locale'; import { COMMIT_TO_NEW_BRANCH } from './constants'; const BRANCH_SUFFIX_COUNT = 5; diff --git a/app/assets/javascripts/ide/stores/modules/merge_requests/actions.js b/app/assets/javascripts/ide/stores/modules/merge_requests/actions.js index 8446b93d14a..3408245b245 100644 --- a/app/assets/javascripts/ide/stores/modules/merge_requests/actions.js +++ b/app/assets/javascripts/ide/stores/modules/merge_requests/actions.js @@ -1,5 +1,5 @@ -import Api from '../../../../api'; -import { __ } from '../../../../locale'; +import Api from '~/api'; +import { __ } from '~/locale'; import { scopes } from './constants'; import * as types from './mutation_types'; diff --git a/app/assets/javascripts/ide/stores/modules/pipelines/actions.js b/app/assets/javascripts/ide/stores/modules/pipelines/actions.js index 51872993f16..62476b7fc63 100644 --- a/app/assets/javascripts/ide/stores/modules/pipelines/actions.js +++ b/app/assets/javascripts/ide/stores/modules/pipelines/actions.js @@ -1,8 +1,8 @@ import axios from 'axios'; import Visibility from 'visibilityjs'; -import httpStatus from '../../../../lib/utils/http_status'; -import Poll from '../../../../lib/utils/poll'; -import { __ } from '../../../../locale'; +import httpStatus from '~/lib/utils/http_status'; +import Poll from '~/lib/utils/poll'; +import { __ } from '~/locale'; import { rightSidebarViews } from '../../../constants'; import service from '../../../services'; import * as types from './mutation_types'; diff --git a/app/assets/javascripts/import_entities/constants.js b/app/assets/javascripts/import_entities/constants.js index 156e92e2d00..1ab5413a5cc 100644 --- a/app/assets/javascripts/import_entities/constants.js +++ b/app/assets/javascripts/import_entities/constants.js @@ -1,4 +1,4 @@ -import { __ } from '../locale'; +import { __ } from '~/locale'; // The `scheduling` status is only present on the client-side, // it is used as the status when we are requesting to start an import. diff --git a/app/assets/javascripts/jobs/components/environments_block.vue b/app/assets/javascripts/jobs/components/environments_block.vue index 9d451f94e8a..da72cbeb856 100644 --- a/app/assets/javascripts/jobs/components/environments_block.vue +++ b/app/assets/javascripts/jobs/components/environments_block.vue @@ -2,7 +2,7 @@ import { GlSprintf, GlLink } from '@gitlab/ui'; import { isEmpty } from 'lodash'; import CiIcon from '~/vue_shared/components/ci_icon.vue'; -import { __ } from '../../locale'; +import { __ } from '~/locale'; export default { creatingEnvironment: 'creating', diff --git a/app/assets/javascripts/lib/utils/datetime/date_calculation_utility.js b/app/assets/javascripts/lib/utils/datetime/date_calculation_utility.js index 8dbadbe4bfc..4e7086e62c5 100644 --- a/app/assets/javascripts/lib/utils/datetime/date_calculation_utility.js +++ b/app/assets/javascripts/lib/utils/datetime/date_calculation_utility.js @@ -1,5 +1,5 @@ import { isNumber } from 'lodash'; -import { __, n__ } from '../../../locale'; +import { __, n__ } from '~/locale'; import { getDayName, parseSeconds } from './date_format_utility'; const DAYS_IN_WEEK = 7; diff --git a/app/assets/javascripts/lib/utils/datetime/date_format_utility.js b/app/assets/javascripts/lib/utils/datetime/date_format_utility.js index 8b048cd51dd..830f4604382 100644 --- a/app/assets/javascripts/lib/utils/datetime/date_format_utility.js +++ b/app/assets/javascripts/lib/utils/datetime/date_format_utility.js @@ -2,7 +2,7 @@ import dateFormat from 'dateformat'; import { isString, mapValues, reduce, isDate, unescape } from 'lodash'; import { roundToNearestHalf } from '~/lib/utils/common_utils'; import { sanitize } from '~/lib/dompurify'; -import { s__, n__, __, sprintf } from '../../../locale'; +import { s__, n__, __, sprintf } from '~/locale'; /** * Returns i18n month names array. diff --git a/app/assets/javascripts/lib/utils/datetime/timeago_utility.js b/app/assets/javascripts/lib/utils/datetime/timeago_utility.js index 2b898d8b6a5..095a29a2eff 100644 --- a/app/assets/javascripts/lib/utils/datetime/timeago_utility.js +++ b/app/assets/javascripts/lib/utils/datetime/timeago_utility.js @@ -1,5 +1,5 @@ import * as timeago from 'timeago.js'; -import { languageCode, s__, createDateTimeFormat } from '../../../locale'; +import { languageCode, s__, createDateTimeFormat } from '~/locale'; import { formatDate } from './date_format_utility'; /** diff --git a/app/assets/javascripts/lib/utils/webpack.js b/app/assets/javascripts/lib/utils/webpack.js index a88f1bd82fc..38d2f3d7551 100644 --- a/app/assets/javascripts/lib/utils/webpack.js +++ b/app/assets/javascripts/lib/utils/webpack.js @@ -10,5 +10,5 @@ export function resetServiceWorkersPublicPath() { // see: https://webpack.js.org/guides/public-path/ const relativeRootPath = (gon && gon.relative_url_root) || ''; const webpackAssetPath = joinPaths(relativeRootPath, '/assets/webpack/'); - __webpack_public_path__ = webpackAssetPath; // eslint-disable-line babel/camelcase + __webpack_public_path__ = webpackAssetPath; // eslint-disable-line camelcase } diff --git a/app/assets/javascripts/merge_conflicts/utils.js b/app/assets/javascripts/merge_conflicts/utils.js index e42703ef0a5..cf7a7c304e3 100644 --- a/app/assets/javascripts/merge_conflicts/utils.js +++ b/app/assets/javascripts/merge_conflicts/utils.js @@ -9,7 +9,7 @@ import { export const getFilePath = (file) => { const { old_path, new_path } = file; - // eslint-disable-next-line babel/camelcase + // eslint-disable-next-line camelcase return old_path === new_path ? new_path : `${old_path} → ${new_path}`; }; @@ -71,7 +71,7 @@ export const getLineForParallelView = (line, id, lineType, isHead) => { isHead: hasConflict && isHead, isOrigin: hasConflict && !isHead, hasMatch: lineType === 'match', - // eslint-disable-next-line babel/camelcase + // eslint-disable-next-line camelcase lineNumber: isHead ? new_line : old_line, section: isHead ? 'head' : 'origin', richText: rich_text, diff --git a/app/assets/javascripts/monitoring/components/charts/bar.vue b/app/assets/javascripts/monitoring/components/charts/bar.vue index 1e0f4b10297..df91bd078d1 100644 --- a/app/assets/javascripts/monitoring/components/charts/bar.vue +++ b/app/assets/javascripts/monitoring/components/charts/bar.vue @@ -36,12 +36,12 @@ export default { return xLabel; }, yAxisTitle() { - const { y_label = '' } = this.graphData; - return y_label; // eslint-disable-line babel/camelcase + const { y_label: yLabel = '' } = this.graphData; + return yLabel; }, xAxisType() { - const { x_type = 'value' } = this.graphData; - return x_type; // eslint-disable-line babel/camelcase + const { x_type: xType = 'value' } = this.graphData; + return xType; }, dataZoomConfig() { const handleIcon = this.svgs['scroll-handle']; diff --git a/app/assets/javascripts/monitoring/components/dashboards_dropdown.vue b/app/assets/javascripts/monitoring/components/dashboards_dropdown.vue index 1238996154d..568c66cf152 100644 --- a/app/assets/javascripts/monitoring/components/dashboards_dropdown.vue +++ b/app/assets/javascripts/monitoring/components/dashboards_dropdown.vue @@ -48,8 +48,8 @@ export default { }, filteredDashboards() { - return this.allDashboards.filter(({ display_name = '' }) => - display_name.toLowerCase().includes(this.searchTerm.toLowerCase()), + return this.allDashboards.filter(({ display_name: displayName = '' }) => + displayName.toLowerCase().includes(this.searchTerm.toLowerCase()), ); }, shouldShowNoMsgContainer() { diff --git a/app/assets/javascripts/monitoring/stores/actions.js b/app/assets/javascripts/monitoring/stores/actions.js index 7b9680aece1..5c99dbc0d98 100644 --- a/app/assets/javascripts/monitoring/stores/actions.js +++ b/app/assets/javascripts/monitoring/stores/actions.js @@ -2,8 +2,8 @@ import * as Sentry from '@sentry/browser'; import createFlash from '~/flash'; import axios from '~/lib/utils/axios_utils'; import { convertToFixedRange } from '~/lib/utils/datetime_range'; -import { convertObjectPropsToCamelCase } from '../../lib/utils/common_utils'; -import { s__, sprintf } from '../../locale'; +import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; +import { s__, sprintf } from '~/locale'; import { ENVIRONMENT_AVAILABLE_STATE, OVERVIEW_DASHBOARD_PATH, VARIABLE_TYPES } from '../constants'; import trackDashboardLoad from '../monitoring_tracking_helper'; import getAnnotations from '../queries/get_annotations.query.graphql'; diff --git a/app/assets/javascripts/monitoring/stores/utils.js b/app/assets/javascripts/monitoring/stores/utils.js index 20f7c5cdb60..c425c819c65 100644 --- a/app/assets/javascripts/monitoring/stores/utils.js +++ b/app/assets/javascripts/monitoring/stores/utils.js @@ -29,7 +29,7 @@ export const gqClient = createGqClient( * @param {String} metric.id - User-defined identifier * @returns {Object} - normalized metric with a uniqueID */ -// eslint-disable-next-line babel/camelcase +// eslint-disable-next-line camelcase export const uniqMetricsId = ({ metric_id, id }) => `${metric_id || NOT_IN_DB_PREFIX}_${id}`; /** @@ -169,10 +169,10 @@ export const mapPanelToViewModel = ({ id = null, title = '', type, - x_axis = {}, + x_axis = {}, // eslint-disable-line camelcase x_label, y_label, - y_axis = {}, + y_axis = {}, // eslint-disable-line camelcase field, metrics = [], links = [], @@ -184,11 +184,11 @@ export const mapPanelToViewModel = ({ }) => { // Both `x_axis.name` and `x_label` are supported for now // https://gitlab.com/gitlab-org/gitlab/issues/210521 - const xAxis = mapXAxisToViewModel({ name: x_label, ...x_axis }); // eslint-disable-line babel/camelcase + const xAxis = mapXAxisToViewModel({ name: x_label, ...x_axis }); // eslint-disable-line camelcase // Both `y_axis.name` and `y_label` are supported for now // https://gitlab.com/gitlab-org/gitlab/issues/208385 - const yAxis = mapYAxisToViewModel({ name: y_label, ...y_axis }); // eslint-disable-line babel/camelcase + const yAxis = mapYAxisToViewModel({ name: y_label, ...y_axis }); // eslint-disable-line camelcase return { id, @@ -295,7 +295,7 @@ export const mapToDashboardViewModel = ({ dashboard = '', templating = {}, links = [], - panel_groups = [], + panel_groups = [], // eslint-disable-line camelcase }) => { return { dashboard, diff --git a/app/assets/javascripts/monitoring/utils.js b/app/assets/javascripts/monitoring/utils.js index 336b613b620..221f28e923b 100644 --- a/app/assets/javascripts/monitoring/utils.js +++ b/app/assets/javascripts/monitoring/utils.js @@ -294,7 +294,7 @@ export const expandedPanelPayloadFromUrl = (dashboard, search = window.location. if (params.group || params.title || params.y_label) { const panelGroup = dashboard.panelGroups.find(({ group }) => params.group === group); const panel = panelGroup.panels.find( - // eslint-disable-next-line babel/camelcase + // eslint-disable-next-line camelcase ({ y_label, title }) => y_label === params.y_label && title === params.title, ); diff --git a/app/assets/javascripts/network/branch_graph.js b/app/assets/javascripts/network/branch_graph.js index 71894b4ff3e..5ae68d22667 100644 --- a/app/assets/javascripts/network/branch_graph.js +++ b/app/assets/javascripts/network/branch_graph.js @@ -1,8 +1,8 @@ /* eslint-disable func-names, consistent-return */ import $ from 'jquery'; -import axios from '../lib/utils/axios_utils'; -import { __ } from '../locale'; +import axios from '~/lib/utils/axios_utils'; +import { __ } from '~/locale'; import Raphael from './raphael'; export default class BranchGraph { diff --git a/app/assets/javascripts/notes/components/noteable_note.vue b/app/assets/javascripts/notes/components/noteable_note.vue index 2290adfdce6..eec6b9ba542 100644 --- a/app/assets/javascripts/notes/components/noteable_note.vue +++ b/app/assets/javascripts/notes/components/noteable_note.vue @@ -10,8 +10,8 @@ import httpStatusCodes from '~/lib/utils/http_status'; import { ignoreWhilePending } from '~/lib/utils/ignore_while_pending'; import { truncateSha } from '~/lib/utils/text_utility'; import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue'; -import { __, s__, sprintf } from '../../locale'; -import userAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue'; +import { __, s__, sprintf } from '~/locale'; +import userAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue'; import eventHub from '../event_hub'; import noteable from '../mixins/noteable'; import resolvable from '../mixins/resolvable'; diff --git a/app/assets/javascripts/packages_and_registries/infrastructure_registry/list/stores/actions.js b/app/assets/javascripts/packages_and_registries/infrastructure_registry/list/stores/actions.js index 488860e5bc2..408d34fbe93 100644 --- a/app/assets/javascripts/packages_and_registries/infrastructure_registry/list/stores/actions.js +++ b/app/assets/javascripts/packages_and_registries/infrastructure_registry/list/stores/actions.js @@ -26,6 +26,7 @@ export const receivePackagesListSuccess = ({ commit }, { data, headers }) => { export const requestPackagesList = ({ dispatch, state }, params = {}) => { dispatch('setLoading', true); + // eslint-disable-next-line camelcase const { page = DEFAULT_PAGE, per_page = DEFAULT_PAGE_SIZE } = params; const { sort, orderBy } = state.sorting; const type = state.config.forceTerraform diff --git a/app/assets/javascripts/pages/admin/application_settings/payload_downloader.js b/app/assets/javascripts/pages/admin/application_settings/payload_downloader.js index 67eee2c3209..7c81cf80dc6 100644 --- a/app/assets/javascripts/pages/admin/application_settings/payload_downloader.js +++ b/app/assets/javascripts/pages/admin/application_settings/payload_downloader.js @@ -1,6 +1,6 @@ import createFlash from '~/flash'; -import axios from '../../../lib/utils/axios_utils'; -import { __ } from '../../../locale'; +import axios from '~/lib/utils/axios_utils'; +import { __ } from '~/locale'; export default class PayloadDownloader { constructor(trigger) { diff --git a/app/assets/javascripts/pages/admin/application_settings/payload_previewer.js b/app/assets/javascripts/pages/admin/application_settings/payload_previewer.js index c017cf0afa2..ae08806fe4c 100644 --- a/app/assets/javascripts/pages/admin/application_settings/payload_previewer.js +++ b/app/assets/javascripts/pages/admin/application_settings/payload_previewer.js @@ -1,6 +1,6 @@ import createFlash from '~/flash'; -import axios from '../../../lib/utils/axios_utils'; -import { __ } from '../../../locale'; +import axios from '~/lib/utils/axios_utils'; +import { __ } from '~/locale'; export default class PayloadPreviewer { constructor(trigger) { diff --git a/app/assets/javascripts/pipelines/stores/test_reports/actions.js b/app/assets/javascripts/pipelines/stores/test_reports/actions.js index 7b28d48b5b6..b7f590a7b3c 100644 --- a/app/assets/javascripts/pipelines/stores/test_reports/actions.js +++ b/app/assets/javascripts/pipelines/stores/test_reports/actions.js @@ -30,6 +30,7 @@ export const fetchTestSuite = ({ state, commit, dispatch }, index) => { dispatch('toggleLoading'); + // eslint-disable-next-line camelcase const { build_ids = [] } = state.testReports?.test_suites?.[index] || {}; // Replacing `/:suite_name.json` with the name of the suite. Including the extra characters // to ensure that we replace exactly the template part of the URL string diff --git a/app/assets/javascripts/pipelines/stores/test_reports/utils.js b/app/assets/javascripts/pipelines/stores/test_reports/utils.js index 63a58798958..6b616601bc5 100644 --- a/app/assets/javascripts/pipelines/stores/test_reports/utils.js +++ b/app/assets/javascripts/pipelines/stores/test_reports/utils.js @@ -1,4 +1,4 @@ -import { __, sprintf } from '../../../locale'; +import { __, sprintf } from '~/locale'; import { TestStatus } from '../../constants'; /** diff --git a/app/assets/javascripts/repository/components/breadcrumbs.vue b/app/assets/javascripts/repository/components/breadcrumbs.vue index bc9f82d985b..84c9f9d0bbe 100644 --- a/app/assets/javascripts/repository/components/breadcrumbs.vue +++ b/app/assets/javascripts/repository/components/breadcrumbs.vue @@ -9,7 +9,7 @@ import { } from '@gitlab/ui'; import permissionsQuery from 'shared_queries/repository/permissions.query.graphql'; import { joinPaths, escapeFileUrl } from '~/lib/utils/url_utility'; -import { __ } from '../../locale'; +import { __ } from '~/locale'; import getRefMixin from '../mixins/get_ref'; import projectPathQuery from '../queries/project_path.query.graphql'; import projectShortPathQuery from '../queries/project_short_path.query.graphql'; diff --git a/app/assets/javascripts/repository/components/table/index.vue b/app/assets/javascripts/repository/components/table/index.vue index 0a2ed753e38..c2323d6b286 100644 --- a/app/assets/javascripts/repository/components/table/index.vue +++ b/app/assets/javascripts/repository/components/table/index.vue @@ -1,7 +1,7 @@ <script> import { GlDeprecatedSkeletonLoading as GlSkeletonLoading, GlButton } from '@gitlab/ui'; import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; -import { sprintf, __ } from '../../../locale'; +import { sprintf, __ } from '~/locale'; import getRefMixin from '../../mixins/get_ref'; import projectPathQuery from '../../queries/project_path.query.graphql'; import TableHeader from './header.vue'; diff --git a/app/assets/javascripts/repository/components/tree_content.vue b/app/assets/javascripts/repository/components/tree_content.vue index 130ebf77361..2200e999c75 100644 --- a/app/assets/javascripts/repository/components/tree_content.vue +++ b/app/assets/javascripts/repository/components/tree_content.vue @@ -2,7 +2,7 @@ import paginatedTreeQuery from 'shared_queries/repository/paginated_tree.query.graphql'; import createFlash from '~/flash'; import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; -import { __ } from '../../locale'; +import { __ } from '~/locale'; import { TREE_PAGE_SIZE, TREE_INITIAL_FETCH_COUNT, diff --git a/app/assets/javascripts/serverless/components/missing_prometheus.vue b/app/assets/javascripts/serverless/components/missing_prometheus.vue index 0023c64e3e4..d9e6bb5009e 100644 --- a/app/assets/javascripts/serverless/components/missing_prometheus.vue +++ b/app/assets/javascripts/serverless/components/missing_prometheus.vue @@ -1,7 +1,7 @@ <script> import { GlButton, GlLink } from '@gitlab/ui'; import { mapState } from 'vuex'; -import { s__ } from '../../locale'; +import { s__ } from '~/locale'; export default { components: { diff --git a/app/assets/javascripts/sidebar/components/assignees/uncollapsed_assignee_list.vue b/app/assets/javascripts/sidebar/components/assignees/uncollapsed_assignee_list.vue index 558fe8ca2aa..131d1d2df1f 100644 --- a/app/assets/javascripts/sidebar/components/assignees/uncollapsed_assignee_list.vue +++ b/app/assets/javascripts/sidebar/components/assignees/uncollapsed_assignee_list.vue @@ -109,20 +109,23 @@ export default { :key="user.id" :class="{ 'user-item': !showVerticalList, + 'gl-display-inline-block': !showVerticalList, + 'gl-display-flex': showVerticalList, 'gl-mb-3': index !== users.length - 1 && showVerticalList, }" - class="gl-display-inline-block" > <attention-requested-toggle v-if="showVerticalList" :user="user" type="assignee" + class="gl-mr-2" @toggle-attention-requested="toggleAttentionRequested" /> <assignee-avatar-link :user="user" :issuable-type="issuableType" :tooltip-has-name="!showVerticalList" + class="gl-word-break-word" > <div v-if="showVerticalList" diff --git a/app/assets/javascripts/sidebar/components/attention_requested_toggle.vue b/app/assets/javascripts/sidebar/components/attention_requested_toggle.vue index 6ba88939373..cdc1c65a516 100644 --- a/app/assets/javascripts/sidebar/components/attention_requested_toggle.vue +++ b/app/assets/javascripts/sidebar/components/attention_requested_toggle.vue @@ -70,19 +70,21 @@ export default { </script> <template> - <span - v-gl-tooltip.left.viewport="tooltipTitle" - class="gl-display-inline-block js-attention-request-toggle" - > - <gl-button - :loading="loading" - :variant="user.attention_requested ? 'warning' : 'default'" - :icon="user.attention_requested ? 'attention-solid' : 'attention'" - :aria-label="tooltipTitle" - :class="{ 'gl-pointer-events-none': !user.can_update_merge_request }" - size="small" - category="tertiary" - @click="toggleAttentionRequired" - /> - </span> + <div> + <span + v-gl-tooltip.left.viewport="tooltipTitle" + class="gl-display-inline-block js-attention-request-toggle" + > + <gl-button + :loading="loading" + :variant="user.attention_requested ? 'warning' : 'default'" + :icon="user.attention_requested ? 'attention-solid' : 'attention'" + :aria-label="tooltipTitle" + :class="{ 'gl-pointer-events-none': !user.can_update_merge_request }" + size="small" + category="tertiary" + @click="toggleAttentionRequired" + /> + </span> + </div> </template> diff --git a/app/assets/javascripts/sidebar/components/lock/edit_form_buttons.vue b/app/assets/javascripts/sidebar/components/lock/edit_form_buttons.vue index 42d2e456a07..2ab46a7a655 100644 --- a/app/assets/javascripts/sidebar/components/lock/edit_form_buttons.vue +++ b/app/assets/javascripts/sidebar/components/lock/edit_form_buttons.vue @@ -3,7 +3,7 @@ import { GlButton } from '@gitlab/ui'; import $ from 'jquery'; import { mapActions } from 'vuex'; import createFlash from '~/flash'; -import { __, sprintf } from '../../../locale'; +import { __, sprintf } from '~/locale'; import eventHub from '../../event_hub'; export default { diff --git a/app/assets/javascripts/sidebar/components/reviewers/reviewer_avatar_link.vue b/app/assets/javascripts/sidebar/components/reviewers/reviewer_avatar_link.vue index 361a082def6..a11468c8761 100644 --- a/app/assets/javascripts/sidebar/components/reviewers/reviewer_avatar_link.vue +++ b/app/assets/javascripts/sidebar/components/reviewers/reviewer_avatar_link.vue @@ -73,10 +73,10 @@ export default { v-gl-tooltip="tooltipOption" :href="reviewerUrl" :title="tooltipTitle" - class="d-inline-block" + class="gl-display-inline-block" > <!-- use d-flex so that slot can be appropriately styled --> - <span class="gl-display-flex gl-align-items-center"> + <span class="gl-display-flex"> <reviewer-avatar :user="user" :img-size="32" :issuable-type="issuableType" /> <slot :user="user"></slot> </span> diff --git a/app/assets/javascripts/sidebar/components/reviewers/uncollapsed_reviewer_list.vue b/app/assets/javascripts/sidebar/components/reviewers/uncollapsed_reviewer_list.vue index 9485802d3da..430017246c1 100644 --- a/app/assets/javascripts/sidebar/components/reviewers/uncollapsed_reviewer_list.vue +++ b/app/assets/javascripts/sidebar/components/reviewers/uncollapsed_reviewer_list.vue @@ -96,14 +96,21 @@ export default { :key="user.id" :class="{ 'gl-mb-3': index !== users.length - 1 }" data-testid="reviewer" + class="gl-display-flex" > <attention-requested-toggle v-if="glFeatures.mrAttentionRequests" :user="user" type="reviewer" + class="gl-mr-2" @toggle-attention-requested="toggleAttentionRequested" /> - <reviewer-avatar-link :user="user" :root-path="rootPath" :issuable-type="issuableType"> + <reviewer-avatar-link + :user="user" + :root-path="rootPath" + :issuable-type="issuableType" + class="gl-word-break-word gl-mr-2" + > <div class="gl-ml-3 gl-line-height-normal gl-display-grid"> <span>{{ user.name }}</span> <span>@{{ user.username }}</span> @@ -115,7 +122,7 @@ export default { :size="16" :title="approvedByTooltipTitle(user)" name="status-success" - class="float-right gl-my-2 gl-ml-2 gl-text-green-500" + class="float-right gl-my-2 gl-ml-auto gl-text-green-500 gl-flex-shrink-0" data-testid="re-approved" /> <gl-icon diff --git a/app/assets/javascripts/sidebar/components/time_tracking/help_state.vue b/app/assets/javascripts/sidebar/components/time_tracking/help_state.vue index bb90ef8e444..91c15061fb9 100644 --- a/app/assets/javascripts/sidebar/components/time_tracking/help_state.vue +++ b/app/assets/javascripts/sidebar/components/time_tracking/help_state.vue @@ -1,7 +1,7 @@ <script> import { GlButton, GlSafeHtmlDirective } from '@gitlab/ui'; import { joinPaths } from '~/lib/utils/url_utility'; -import { sprintf, s__ } from '../../../locale'; +import { sprintf, s__ } from '~/locale'; export default { name: 'TimeTrackingHelpState', diff --git a/app/assets/javascripts/users_select/index.js b/app/assets/javascripts/users_select/index.js index 656c851aa3d..f7a5589af90 100644 --- a/app/assets/javascripts/users_select/index.js +++ b/app/assets/javascripts/users_select/index.js @@ -1,4 +1,4 @@ -/* eslint-disable func-names, prefer-rest-params, consistent-return, no-shadow, no-self-compare, no-unused-expressions, yoda, prefer-spread, babel/camelcase, no-param-reassign */ +/* eslint-disable func-names, prefer-rest-params, consistent-return, no-shadow, no-self-compare, no-unused-expressions, yoda, prefer-spread, camelcase, no-param-reassign */ /* global Issuable */ /* global emitSidebarEvent */ @@ -11,10 +11,10 @@ import { import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown'; import { isUserBusy } from '~/set_status_modal/utils'; import { fixTitle, dispose } from '~/tooltips'; -import axios from '../lib/utils/axios_utils'; -import { parseBoolean, spriteIcon } from '../lib/utils/common_utils'; -import { loadCSSFile } from '../lib/utils/css_utils'; -import { s__, __, sprintf } from '../locale'; +import axios from '~/lib/utils/axios_utils'; +import { parseBoolean, spriteIcon } from '~/lib/utils/common_utils'; +import { loadCSSFile } from '~/lib/utils/css_utils'; +import { s__, __, sprintf } from '~/locale'; import { getAjaxUsersSelectOptions, getAjaxUsersSelectParams } from './utils'; // TODO: remove eventHub hack after code splitting refactor diff --git a/app/assets/javascripts/vue_merge_request_widget/components/source_branch_removal_status.vue b/app/assets/javascripts/vue_merge_request_widget/components/source_branch_removal_status.vue index caafd6b995e..e86724d133a 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/source_branch_removal_status.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/source_branch_removal_status.vue @@ -1,6 +1,6 @@ <script> import { GlIcon, GlTooltipDirective } from '@gitlab/ui'; -import { __ } from '../../locale'; +import { __ } from '~/locale'; export default { i18n: { diff --git a/app/assets/javascripts/vue_shared/components/header_ci_component.vue b/app/assets/javascripts/vue_shared/components/header_ci_component.vue index 9bff469b670..2622bdfb8cb 100644 --- a/app/assets/javascripts/vue_shared/components/header_ci_component.vue +++ b/app/assets/javascripts/vue_shared/components/header_ci_component.vue @@ -8,8 +8,8 @@ import { GlTooltip, } from '@gitlab/ui'; import { isGid, getIdFromGraphQLId } from '~/graphql_shared/utils'; -import { glEmojiTag } from '../../emoji'; -import { __, sprintf } from '../../locale'; +import { glEmojiTag } from '~/emoji'; +import { __, sprintf } from '~/locale'; import CiIconBadge from './ci_badge_link.vue'; import TimeagoTooltip from './time_ago_tooltip.vue'; diff --git a/app/assets/javascripts/vue_shared/components/source_viewer/components/chunk_line.vue b/app/assets/javascripts/vue_shared/components/source_viewer/components/chunk_line.vue index ab989ae6f9e..1b8e4bcfec6 100644 --- a/app/assets/javascripts/vue_shared/components/source_viewer/components/chunk_line.vue +++ b/app/assets/javascripts/vue_shared/components/source_viewer/components/chunk_line.vue @@ -1,5 +1,7 @@ <script> import { GlLink, GlSafeHtmlDirective } from '@gitlab/ui'; +import { setAttributes } from '~/lib/utils/dom_utils'; +import { BIDI_CHARS, BIDI_CHARS_CLASS_LIST, BIDI_CHAR_TOOLTIP } from '../constants'; export default { components: { @@ -22,6 +24,34 @@ export default { required: true, }, }, + computed: { + formattedContent() { + let { content } = this; + + BIDI_CHARS.forEach((bidiChar) => { + if (content.includes(bidiChar)) { + content = content.replace(bidiChar, this.wrapBidiChar(bidiChar)); + } + }); + + return content; + }, + }, + methods: { + wrapBidiChar(bidiChar) { + const span = document.createElement('span'); + + setAttributes(span, { + class: BIDI_CHARS_CLASS_LIST, + title: BIDI_CHAR_TOOLTIP, + 'data-testid': 'bidi-wrapper', + }); + + span.innerText = bidiChar; + + return span.outerHTML; + }, + }, }; </script> <template> @@ -39,6 +69,6 @@ export default { <pre class="code highlight gl-p-0! gl-w-full gl-overflow-visible! gl-ml-11!" - ><code><span :id="`LC${number}`" v-safe-html="content" :lang="language" class="line" data-testid="content"></span></code></pre> + ><code><span :id="`LC${number}`" v-safe-html="formattedContent" :lang="language" class="line" data-testid="content"></span></code></pre> </div> </template> diff --git a/app/assets/javascripts/vue_shared/components/source_viewer/constants.js b/app/assets/javascripts/vue_shared/components/source_viewer/constants.js index b5ce214e577..bed6dd4d5c6 100644 --- a/app/assets/javascripts/vue_shared/components/source_viewer/constants.js +++ b/app/assets/javascripts/vue_shared/components/source_viewer/constants.js @@ -1,3 +1,5 @@ +import { __ } from '~/locale'; + // Language map from Rouge::Lexer to highlight.js // Rouge::Lexer - We use it on the BE to determine the language of a source file (https://github.com/rouge-ruby/rouge/blob/master/docs/Languages.md). // Highlight.js - We use it on the FE to highlight the syntax of a source file (https://github.com/highlightjs/highlight.js/tree/main/src/languages). @@ -111,3 +113,24 @@ export const ROUGE_TO_HLJS_LANGUAGE_MAP = { }; export const LINES_PER_CHUNK = 70; + +export const BIDI_CHARS = [ + '\u202A', // Left-to-Right Embedding (Try treating following text as left-to-right) + '\u202B', // Right-to-Left Embedding (Try treating following text as right-to-left) + '\u202D', // Left-to-Right Override (Force treating following text as left-to-right) + '\u202E', // Right-to-Left Override (Force treating following text as right-to-left) + '\u2066', // Left-to-Right Isolate (Force treating following text as left-to-right without affecting adjacent text) + '\u2067', // Right-to-Left Isolate (Force treating following text as right-to-left without affecting adjacent text) + '\u2068', // First Strong Isolate (Force treating following text in direction indicated by the next character) + '\u202C', // Pop Directional Formatting (Terminate nearest LRE, RLE, LRO, or RLO) + '\u2069', // Pop Directional Isolate (Terminate nearest LRI or RLI) + '\u061C', // Arabic Letter Mark (Right-to-left zero-width Arabic character) + '\u200F', // Right-to-Left Mark (Right-to-left zero-width character non-Arabic character) + '\u200E', // Left-to-Right Mark (Left-to-right zero-width character) +]; + +export const BIDI_CHARS_CLASS_LIST = 'unicode-bidi has-tooltip'; + +export const BIDI_CHAR_TOOLTIP = __( + 'Potentially unwanted character detected: Unicode BiDi Control', +); diff --git a/app/assets/javascripts/vue_shared/translate.js b/app/assets/javascripts/vue_shared/translate.js index 616848639f1..bc1f8865261 100644 --- a/app/assets/javascripts/vue_shared/translate.js +++ b/app/assets/javascripts/vue_shared/translate.js @@ -1,4 +1,4 @@ -import { __, n__, s__, sprintf } from '../locale'; +import { __, n__, s__, sprintf } from '~/locale'; export default (Vue) => { Vue.mixin({ diff --git a/app/assets/javascripts/webpack.js b/app/assets/javascripts/webpack.js index b901f17790f..1c6e632135d 100644 --- a/app/assets/javascripts/webpack.js +++ b/app/assets/javascripts/webpack.js @@ -8,5 +8,5 @@ */ if (gon && gon.webpack_public_path) { - __webpack_public_path__ = gon.webpack_public_path; // eslint-disable-line babel/camelcase + __webpack_public_path__ = gon.webpack_public_path; // eslint-disable-line camelcase } diff --git a/app/models/group.rb b/app/models/group.rb index b6c128c31a7..c6fe01690ca 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -96,6 +96,8 @@ class Group < Namespace has_many :group_callouts, class_name: 'Users::GroupCallout', foreign_key: :group_id + has_one :group_feature, inverse_of: :group, class_name: 'Groups::FeatureSetting' + delegate :prevent_sharing_groups_outside_hierarchy, :new_user_signups_cap, :setup_for_company, :jobs_to_be_done, to: :namespace_settings delegate :runner_token_expiration_interval, :runner_token_expiration_interval=, :runner_token_expiration_interval_human_readable, :runner_token_expiration_interval_human_readable=, to: :namespace_settings, allow_nil: true delegate :subgroup_runner_token_expiration_interval, :subgroup_runner_token_expiration_interval=, :subgroup_runner_token_expiration_interval_human_readable, :subgroup_runner_token_expiration_interval_human_readable=, to: :namespace_settings, allow_nil: true @@ -119,6 +121,8 @@ class Group < Namespace message: Gitlab::Regex.group_name_regex_message }, if: :name_changed? + validates :group_feature, presence: true + add_authentication_token_field :runners_token, encrypted: -> { Feature.enabled?(:groups_tokens_optional_encryption, default_enabled: true) ? :optional : :required }, prefix: RunnersTokenPrefixable::RUNNERS_TOKEN_PREFIX @@ -127,6 +131,7 @@ class Group < Namespace after_destroy :post_destroy_hook after_save :update_two_factor_requirement after_update :path_changed_hook, if: :saved_change_to_path? + after_create -> { create_or_load_association(:group_feature) } scope :with_users, -> { includes(:users) } @@ -796,6 +801,10 @@ class Group < Namespace super || build_dependency_proxy_setting end + def group_feature + super || build_group_feature + end + def crm_enabled? crm_settings&.enabled? end diff --git a/app/models/groups/feature_setting.rb b/app/models/groups/feature_setting.rb new file mode 100644 index 00000000000..5db5cda2d56 --- /dev/null +++ b/app/models/groups/feature_setting.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +module Groups + class FeatureSetting < ApplicationRecord + self.primary_key = :group_id + self.table_name = 'group_features' + + belongs_to :group + + validates :group, presence: true + end +end diff --git a/app/models/vulnerability.rb b/app/models/vulnerability.rb index a5881e80e88..8bb598ee316 100644 --- a/app/models/vulnerability.rb +++ b/app/models/vulnerability.rb @@ -5,6 +5,8 @@ class Vulnerability < ApplicationRecord include EachBatch include IgnorableColumns + alias_attribute :vulnerability_id, :id + def self.link_reference_pattern nil end diff --git a/app/views/profiles/keys/_form.html.haml b/app/views/profiles/keys/_form.html.haml index bebbe49a485..941b8545745 100644 --- a/app/views/profiles/keys/_form.html.haml +++ b/app/views/profiles/keys/_form.html.haml @@ -9,9 +9,9 @@ %p.form-text.text-muted= s_('Profiles|Begins with %{ssh_key_algorithms}.') % { ssh_key_algorithms: ssh_key_allowed_algorithms } .form-row .col.form-group - = f.label :title, _('Title'), class: 'label-bold' - = f.text_field :title, class: "form-control gl-form-input input-lg qa-key-title-field", required: true, placeholder: s_('Profiles|e.g. My MacBook key') - %p.form-text.text-muted= s_('Profiles|Give your individual key a title. This will be publicly visible.') + = f.label :title, s_('Profiles|Title'), class: 'label-bold' + = f.text_field :title, class: "form-control gl-form-input input-lg qa-key-title-field", required: true, placeholder: s_('Profiles|Example: MacBook key') + %p.form-text.text-muted= s_('Profiles|Key titles are publicly visible.') .col.form-group = f.label :expires_at, s_('Profiles|Expiration date'), class: 'label-bold' diff --git a/db/migrate/20220302110724_add_group_features_table.rb b/db/migrate/20220302110724_add_group_features_table.rb new file mode 100644 index 00000000000..9d9204afec2 --- /dev/null +++ b/db/migrate/20220302110724_add_group_features_table.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +class AddGroupFeaturesTable < Gitlab::Database::Migration[1.0] + enable_lock_retries! + + def up + create_table :group_features, id: false do |t| + t.references :group, index: false, foreign_key: { to_table: :namespaces, on_delete: :cascade }, null: false + t.timestamps_with_timezone null: false + t.integer :wiki_access_level, default: Featurable::ENABLED, null: false, limit: 2 + end + + execute('ALTER TABLE group_features ADD PRIMARY KEY (group_id)') + end + + def down + drop_table :group_features + end +end diff --git a/db/post_migrate/20220302114046_backfill_group_features.rb b/db/post_migrate/20220302114046_backfill_group_features.rb new file mode 100644 index 00000000000..dd8961b8bee --- /dev/null +++ b/db/post_migrate/20220302114046_backfill_group_features.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +class BackfillGroupFeatures < Gitlab::Database::Migration[1.0] + disable_ddl_transaction! + + MIGRATION = 'BackfillGroupFeatures' + INTERVAL = 2.minutes + BATCH_SIZE = 10_000 + SUB_BATCH_SIZE = 1_000 + + def up + queue_batched_background_migration( + MIGRATION, + :namespaces, + :id, + BATCH_SIZE, + job_interval: INTERVAL, + batch_size: BATCH_SIZE, + max_batch_size: BATCH_SIZE, + sub_batch_size: SUB_BATCH_SIZE + ) + end + + def down + Gitlab::Database::BackgroundMigration::BatchedMigration + .for_configuration(MIGRATION, :namespaces, :id, [BATCH_SIZE]) + .delete_all + end +end diff --git a/db/schema_migrations/20220302110724 b/db/schema_migrations/20220302110724 new file mode 100644 index 00000000000..700a39b85c5 --- /dev/null +++ b/db/schema_migrations/20220302110724 @@ -0,0 +1 @@ +4f565a313c37d12f24afe26a9e344d4273c54d0f080b3108d56ed98bf7299ecc
\ No newline at end of file diff --git a/db/schema_migrations/20220302114046 b/db/schema_migrations/20220302114046 new file mode 100644 index 00000000000..40488b47eb2 --- /dev/null +++ b/db/schema_migrations/20220302114046 @@ -0,0 +1 @@ +4e2de14559b47a9bf3fa8910fdb84ff62cb18442620f4147e40e8026bf4bcf1b
\ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 5943265a785..fbae8724a83 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -15679,6 +15679,13 @@ CREATE SEQUENCE group_deploy_tokens_id_seq ALTER SEQUENCE group_deploy_tokens_id_seq OWNED BY group_deploy_tokens.id; +CREATE TABLE group_features ( + group_id bigint NOT NULL, + created_at timestamp with time zone NOT NULL, + updated_at timestamp with time zone NOT NULL, + wiki_access_level smallint DEFAULT 20 NOT NULL +); + CREATE TABLE group_group_links ( id bigint NOT NULL, created_at timestamp with time zone NOT NULL, @@ -24529,6 +24536,9 @@ ALTER TABLE ONLY group_deploy_keys ALTER TABLE ONLY group_deploy_tokens ADD CONSTRAINT group_deploy_tokens_pkey PRIMARY KEY (id); +ALTER TABLE ONLY group_features + ADD CONSTRAINT group_features_pkey PRIMARY KEY (group_id); + ALTER TABLE ONLY group_group_links ADD CONSTRAINT group_group_links_pkey PRIMARY KEY (id); @@ -32199,6 +32209,9 @@ ALTER TABLE ONLY requirements ALTER TABLE ONLY metrics_dashboard_annotations ADD CONSTRAINT fk_rails_345ab51043 FOREIGN KEY (cluster_id) REFERENCES clusters(id) ON DELETE CASCADE; +ALTER TABLE ONLY group_features + ADD CONSTRAINT fk_rails_356514082b FOREIGN KEY (group_id) REFERENCES namespaces(id) ON DELETE CASCADE; + ALTER TABLE ONLY wiki_page_slugs ADD CONSTRAINT fk_rails_358b46be14 FOREIGN KEY (wiki_page_meta_id) REFERENCES wiki_page_meta(id) ON DELETE CASCADE; diff --git a/lib/backup/database.rb b/lib/backup/database.rb index afc84a4b913..0894de74e58 100644 --- a/lib/backup/database.rb +++ b/lib/backup/database.rb @@ -25,7 +25,7 @@ module Backup end override :dump - def dump(db_file_name) + def dump(db_file_name, backup_id) FileUtils.mkdir_p(File.dirname(db_file_name)) FileUtils.rm_f(db_file_name) compress_rd, compress_wr = IO.pipe diff --git a/lib/backup/files.rb b/lib/backup/files.rb index 7fa07e40cee..bd0c6668213 100644 --- a/lib/backup/files.rb +++ b/lib/backup/files.rb @@ -21,7 +21,7 @@ module Backup # Copy files from public/files to backup/files override :dump - def dump(backup_tarball) + def dump(backup_tarball, backup_id) FileUtils.mkdir_p(Gitlab.config.backup.path) FileUtils.rm_f(backup_tarball) diff --git a/lib/backup/gitaly_backup.rb b/lib/backup/gitaly_backup.rb index 22045b781e8..93342e789e9 100644 --- a/lib/backup/gitaly_backup.rb +++ b/lib/backup/gitaly_backup.rb @@ -9,16 +9,14 @@ module Backup # @param [StringIO] progress IO interface to output progress # @param [Integer] max_parallelism max parallelism when running backups # @param [Integer] storage_parallelism max parallelism per storage (is affected by max_parallelism) - # @param [String] backup_id unique identifier for the backup def initialize(progress, max_parallelism: nil, storage_parallelism: nil, incremental: false, backup_id: nil) @progress = progress @max_parallelism = max_parallelism @storage_parallelism = storage_parallelism @incremental = incremental - @backup_id = backup_id end - def start(type, backup_repos_path) + def start(type, backup_repos_path, backup_id: nil) raise Error, 'already started' if started? command = case type @@ -37,7 +35,7 @@ module Backup args += ['-layout', 'pointer'] if type == :create args += ['-incremental'] if @incremental - args += ['-id', @backup_id] if @backup_id + args += ['-id', backup_id] if backup_id end end diff --git a/lib/backup/manager.rb b/lib/backup/manager.rb index 2d7277c7f8d..6172feed082 100644 --- a/lib/backup/manager.rb +++ b/lib/backup/manager.rb @@ -113,7 +113,7 @@ module Backup end puts_time "Dumping #{definition.task.human_name} ... ".color(:blue) - definition.task.dump(File.join(Gitlab.config.backup.path, definition.destination_path)) + definition.task.dump(File.join(Gitlab.config.backup.path, definition.destination_path), backup_id) puts_time "Dumping #{definition.task.human_name} ... ".color(:blue) + "done".color(:green) rescue Backup::DatabaseBackupError, Backup::FileBackupError => e diff --git a/lib/backup/repositories.rb b/lib/backup/repositories.rb index 5a78de8e8af..33d252bc11e 100644 --- a/lib/backup/repositories.rb +++ b/lib/backup/repositories.rb @@ -13,8 +13,8 @@ module Backup end override :dump - def dump(path) - strategy.start(:create, path) + def dump(path, backup_id) + strategy.start(:create, path, backup_id: backup_id) enqueue_consecutive ensure diff --git a/lib/backup/task.rb b/lib/backup/task.rb index 15cd2aa64d3..3756e5ae84a 100644 --- a/lib/backup/task.rb +++ b/lib/backup/task.rb @@ -12,7 +12,10 @@ module Backup end # dump task backup to `path` - def dump(path) + # + # @param [String] path fully qualified backup task destination + # @param [String] backup_id unique identifier for the backup + def dump(path, backup_id) raise NotImplementedError end diff --git a/lib/gitlab/background_migration/backfill_group_features.rb b/lib/gitlab/background_migration/backfill_group_features.rb new file mode 100644 index 00000000000..084c788c8cb --- /dev/null +++ b/lib/gitlab/background_migration/backfill_group_features.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +module Gitlab + module BackgroundMigration + # Backfill group_features for an array of groups + class BackfillGroupFeatures < ::Gitlab::BackgroundMigration::BaseJob + include Gitlab::Database::DynamicModelHelpers + + def perform(start_id, end_id, batch_table, batch_column, sub_batch_size, pause_ms, batch_size) + pause_ms = 0 if pause_ms < 0 + + parent_batch_relation = relation_scoped_to_range(batch_table, batch_column, start_id, end_id) + parent_batch_relation.each_batch(column: batch_column, of: sub_batch_size, order_hint: :type) do |sub_batch| + batch_metrics.time_operation(:upsert_group_features) do + upsert_group_features(sub_batch, batch_size) + end + + sleep(pause_ms * 0.001) + end + end + + def batch_metrics + @batch_metrics ||= Gitlab::Database::BackgroundMigration::BatchMetrics.new + end + + private + + def relation_scoped_to_range(source_table, source_key_column, start_id, stop_id) + define_batchable_model(source_table, connection: connection) + .where(source_key_column => start_id..stop_id) + .where(type: 'Group') + end + + def upsert_group_features(relation, batch_size) + connection.execute( + <<~SQL + INSERT INTO group_features (group_id, created_at, updated_at) + SELECT namespaces.id as group_id, now(), now() + FROM namespaces + WHERE namespaces.type = 'Group' AND namespaces.id IN(#{relation.select(:id).limit(batch_size).to_sql}) + ON CONFLICT (group_id) DO NOTHING; + SQL + ) + end + end + end +end diff --git a/lib/gitlab/ci/config/external/file/base.rb b/lib/gitlab/ci/config/external/file/base.rb index 7d3fddd850d..7c45961b738 100644 --- a/lib/gitlab/ci/config/external/file/base.rb +++ b/lib/gitlab/ci/config/external/file/base.rb @@ -16,8 +16,6 @@ module Gitlab @params = params @context = context @errors = [] - - validate! end def matching? @@ -48,6 +46,15 @@ module Gitlab expanded_content_hash end + def validate! + context.logger.instrument(:config_file_validation) do + validate_execution_time! + validate_location! + validate_content! if errors.none? + validate_hash! if errors.none? + end + end + protected def expanded_content_hash @@ -66,13 +73,6 @@ module Gitlab nil end - def validate! - validate_execution_time! - validate_location! - validate_content! if errors.none? - validate_hash! if errors.none? - end - def validate_execution_time! context.check_execution_time! end diff --git a/lib/gitlab/ci/config/external/file/project.rb b/lib/gitlab/ci/config/external/file/project.rb index 114d493381c..b719a1675cd 100644 --- a/lib/gitlab/ci/config/external/file/project.rb +++ b/lib/gitlab/ci/config/external/file/project.rb @@ -31,7 +31,7 @@ module Gitlab def validate_content! if !can_access_local_content? - errors.push("Project `#{project_name}` not found or access denied!") + errors.push("Project `#{project_name}` not found or access denied! Make sure any includes in the pipeline configuration are correctly defined.") elsif sha.nil? errors.push("Project `#{project_name}` reference `#{ref_name}` does not exist!") elsif content.nil? diff --git a/lib/gitlab/ci/config/external/mapper.rb b/lib/gitlab/ci/config/external/mapper.rb index 7f1de6ce1ab..fb62b48c076 100644 --- a/lib/gitlab/ci/config/external/mapper.rb +++ b/lib/gitlab/ci/config/external/mapper.rb @@ -50,6 +50,7 @@ module Gitlab .map(&method(:expand_variables)) .each(&method(:verify_duplicates!)) .map(&method(:select_first_matching)) + .each(&method(:verify!)) end def normalize_location(location) @@ -147,6 +148,10 @@ module Gitlab matching.first end + def verify!(location_object) + location_object.validate! + end + def expand_variables(data) logger.instrument(:config_mapper_variables) do expand_variables_without_instrumentation(data) diff --git a/lib/gitlab/database/gitlab_schemas.yml b/lib/gitlab/database/gitlab_schemas.yml index 850eadf9b89..275171d9ed5 100644 --- a/lib/gitlab/database/gitlab_schemas.yml +++ b/lib/gitlab/database/gitlab_schemas.yml @@ -240,6 +240,7 @@ group_deletion_schedules: :gitlab_main group_deploy_keys: :gitlab_main group_deploy_keys_groups: :gitlab_main group_deploy_tokens: :gitlab_main +group_features: :gitlab_main group_group_links: :gitlab_main group_import_states: :gitlab_main group_merge_request_approval_settings: :gitlab_main diff --git a/lib/gitlab/usage/service_ping/instrumented_payload.rb b/lib/gitlab/usage/service_ping/instrumented_payload.rb index e04e2e589b2..6cc67321ba1 100644 --- a/lib/gitlab/usage/service_ping/instrumented_payload.rb +++ b/lib/gitlab/usage/service_ping/instrumented_payload.rb @@ -22,7 +22,7 @@ module Gitlab private - # Not all metrics defintions have instrumentation classes + # Not all metrics definitions have instrumentation classes # The value can be computed only for those that have it def instrumented_metrics_defintions Gitlab::Usage::MetricDefinition.with_instrumentation_class diff --git a/lib/tasks/dev.rake b/lib/tasks/dev.rake index a9af2afa068..fe5755e8e71 100644 --- a/lib/tasks/dev.rake +++ b/lib/tasks/dev.rake @@ -30,8 +30,10 @@ namespace :dev do databases = ActiveRecord::Tasks::DatabaseTasks.setup_initial_database_yaml namespace :copy_db do + ALLOWED_DATABASES = %w[ci].freeze + ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |name| - next if name == 'main' + next unless ALLOWED_DATABASES.include?(name) desc "Copies the #{name} database from the main database" task name => :environment do diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 12241764339..c6af956f4d7 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -28661,6 +28661,9 @@ msgstr "" msgid "Profiles|Enter your pronouns to let people know how to refer to you" msgstr "" +msgid "Profiles|Example: MacBook key" +msgstr "" + msgid "Profiles|Expiration date" msgstr "" @@ -28682,9 +28685,6 @@ msgstr "" msgid "Profiles|GitLab is unable to verify your identity automatically. For security purposes, you must set a password by %{openingTag}resetting your password%{closingTag} to delete your account." msgstr "" -msgid "Profiles|Give your individual key a title. This will be publicly visible." -msgstr "" - msgid "Profiles|If after setting a password, the option to delete your account is still not available, please email %{data_request} to begin the account deletion process." msgstr "" @@ -28721,6 +28721,9 @@ msgstr "" msgid "Profiles|Key can still be used after expiration." msgstr "" +msgid "Profiles|Key titles are publicly visible." +msgstr "" + msgid "Profiles|Key usable beyond expiration date." msgstr "" @@ -28826,6 +28829,9 @@ msgstr "" msgid "Profiles|Time settings" msgstr "" +msgid "Profiles|Title" +msgstr "" + msgid "Profiles|Two-Factor Authentication" msgstr "" @@ -28907,9 +28913,6 @@ msgstr "" msgid "Profiles|Your status" msgstr "" -msgid "Profiles|e.g. My MacBook key" -msgstr "" - msgid "Profiles|https://website.com" msgstr "" diff --git a/package.json b/package.json index fc8d43d6a1f..99db42bdc8f 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "storybook:install": "yarn --cwd ./storybook install", "storybook:build": "yarn --cwd ./storybook build", "storybook:start": "./scripts/frontend/start_storybook.sh", - "stylelint-create-utility-map": "node scripts/frontend/stylelint/stylelint-utility-map.js", + "stylelint-create-utility-map": "node scripts/frontend/stylelint/stylelint_utility_map.js", "webpack": "NODE_OPTIONS=\"--max-old-space-size=3584\" webpack --config config/webpack.config.js", "webpack-vendor": "NODE_OPTIONS=\"--max-old-space-size=3584\" webpack --config config/webpack.vendor.config.js", "webpack-prod": "NODE_OPTIONS=\"--max-old-space-size=3584\" NODE_ENV=production webpack --config config/webpack.config.js" @@ -199,7 +199,7 @@ }, "devDependencies": { "@babel/plugin-transform-modules-commonjs": "^7.10.1", - "@gitlab/eslint-plugin": "11.0.0", + "@gitlab/eslint-plugin": "12.0.1", "@gitlab/stylelint-config": "4.0.0", "@graphql-eslint/eslint-plugin": "3.0.0", "@testing-library/dom": "^7.16.2", diff --git a/scripts/frontend/stylelint/stylelint-duplicate-selectors.js b/scripts/frontend/stylelint/stylelint_duplicate_selectors.js index 982ddf524a3..77c1f1292b7 100644 --- a/scripts/frontend/stylelint/stylelint-duplicate-selectors.js +++ b/scripts/frontend/stylelint/stylelint_duplicate_selectors.js @@ -1,5 +1,5 @@ const stylelint = require('stylelint'); -const utils = require('./stylelint-utils'); +const utils = require('./stylelint_utils'); const ruleName = 'stylelint-gitlab/duplicate-selectors'; diff --git a/scripts/frontend/stylelint/stylelint-utility-classes.js b/scripts/frontend/stylelint/stylelint_utility_classes.js index 14827145b54..ad2b2ddbb20 100644 --- a/scripts/frontend/stylelint/stylelint-utility-classes.js +++ b/scripts/frontend/stylelint/stylelint_utility_classes.js @@ -1,6 +1,6 @@ const stylelint = require('stylelint'); -const utils = require('./stylelint-utils'); -const utilityClasses = require('./utility-classes-map'); +const utils = require('./stylelint_utils'); +const utilityClasses = require('./utility_classes_map'); const ruleName = 'stylelint-gitlab/utility-classes'; diff --git a/scripts/frontend/stylelint/stylelint-utility-map.js b/scripts/frontend/stylelint/stylelint_utility_map.js index 676f83cd067..187b2065823 100644 --- a/scripts/frontend/stylelint/stylelint-utility-map.js +++ b/scripts/frontend/stylelint/stylelint_utility_map.js @@ -4,13 +4,13 @@ const postcss = require('postcss'); const prettier = require('prettier'); const sass = require('sass'); -const utils = require('./stylelint-utils'); +const utils = require('./stylelint_utils'); const ROOT_PATH = path.resolve(__dirname, '../../..'); -const hashMapPath = path.resolve(__dirname, './utility-classes-map.js'); +const hashMapPath = path.resolve(__dirname, './utility_classes_map.js'); // -// This creates a JS based hash map (saved in utility-classes-map.js) of the different values in the utility classes +// This creates a JS based hash map (saved in utility_classes_map.js) of the different values in the utility classes // sass.render( { diff --git a/scripts/frontend/stylelint/stylelint-utils.js b/scripts/frontend/stylelint/stylelint_utils.js index c9d9c7d9aad..c9d9c7d9aad 100644 --- a/scripts/frontend/stylelint/stylelint-utils.js +++ b/scripts/frontend/stylelint/stylelint_utils.js diff --git a/scripts/frontend/stylelint/utility-classes-map.js b/scripts/frontend/stylelint/utility_classes_map.js index a174812ff93..a174812ff93 100644 --- a/scripts/frontend/stylelint/utility-classes-map.js +++ b/scripts/frontend/stylelint/utility_classes_map.js diff --git a/spec/frontend/__helpers__/mock_dom_observer.js b/spec/frontend/__helpers__/mock_dom_observer.js index dd26b594ad9..bc2646be4c2 100644 --- a/spec/frontend/__helpers__/mock_dom_observer.js +++ b/spec/frontend/__helpers__/mock_dom_observer.js @@ -22,14 +22,14 @@ class MockObserver { takeRecords() {} - // eslint-disable-next-line babel/camelcase + // eslint-disable-next-line camelcase $_triggerObserve(node, { entry = {}, options = {} } = {}) { if (this.$_hasObserver(node, options)) { this.$_cb([{ target: node, ...entry }]); } } - // eslint-disable-next-line babel/camelcase + // eslint-disable-next-line camelcase $_hasObserver(node, options = {}) { return this.$_observers.some( ([obvNode, obvOptions]) => node === obvNode && isMatch(options, obvOptions), diff --git a/spec/frontend/vue_shared/components/source_viewer/components/chunk_line_spec.js b/spec/frontend/vue_shared/components/source_viewer/components/chunk_line_spec.js index 4aa0aea9605..eb2eec92534 100644 --- a/spec/frontend/vue_shared/components/source_viewer/components/chunk_line_spec.js +++ b/spec/frontend/vue_shared/components/source_viewer/components/chunk_line_spec.js @@ -1,6 +1,11 @@ import { GlLink } from '@gitlab/ui'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import ChunkLine from '~/vue_shared/components/source_viewer/components/chunk_line.vue'; +import { + BIDI_CHARS, + BIDI_CHARS_CLASS_LIST, + BIDI_CHAR_TOOLTIP, +} from '~/vue_shared/components/source_viewer/constants'; const DEFAULT_PROPS = { number: 2, @@ -17,6 +22,7 @@ describe('Chunk Line component', () => { const findLink = () => wrapper.findComponent(GlLink); const findContent = () => wrapper.findByTestId('content'); + const findWrappedBidiChars = () => wrapper.findAllByTestId('bidi-wrapper'); beforeEach(() => { createComponent(); @@ -25,6 +31,22 @@ describe('Chunk Line component', () => { afterEach(() => wrapper.destroy()); describe('rendering', () => { + it('wraps BiDi characters', () => { + const content = `// some content ${BIDI_CHARS.toString()} with BiDi chars`; + createComponent({ content }); + const wrappedBidiChars = findWrappedBidiChars(); + + expect(wrappedBidiChars.length).toBe(BIDI_CHARS.length); + + wrappedBidiChars.wrappers.forEach((_, i) => { + expect(wrappedBidiChars.at(i).text()).toBe(BIDI_CHARS[i]); + expect(wrappedBidiChars.at(i).attributes()).toMatchObject({ + class: BIDI_CHARS_CLASS_LIST, + title: BIDI_CHAR_TOOLTIP, + }); + }); + }); + it('renders a line number', () => { expect(findLink().attributes()).toMatchObject({ 'data-line-number': `${DEFAULT_PROPS.number}`, diff --git a/spec/lib/backup/artifacts_spec.rb b/spec/lib/backup/artifacts_spec.rb index d830692d96b..f9cd21d5f79 100644 --- a/spec/lib/backup/artifacts_spec.rb +++ b/spec/lib/backup/artifacts_spec.rb @@ -18,7 +18,7 @@ RSpec.describe Backup::Artifacts do expect(backup).to receive(:tar).and_return('blabla-tar') expect(backup).to receive(:run_pipeline!).with([%w(blabla-tar --exclude=lost+found --exclude=./tmp -C /var/gitlab-artifacts -cf - .), 'gzip -c -1'], any_args).and_return([[true, true], '']) expect(backup).to receive(:pipeline_succeeded?).and_return(true) - backup.dump('artifacts.tar.gz') + backup.dump('artifacts.tar.gz', 'backup_id') end end end diff --git a/spec/lib/backup/files_spec.rb b/spec/lib/backup/files_spec.rb index bbc465a26c9..b3e71d5b0bf 100644 --- a/spec/lib/backup/files_spec.rb +++ b/spec/lib/backup/files_spec.rb @@ -118,14 +118,14 @@ RSpec.describe Backup::Files do end it 'raises no errors' do - expect { subject.dump('registry.tar.gz') }.not_to raise_error + expect { subject.dump('registry.tar.gz', 'backup_id') }.not_to raise_error end it 'excludes tmp dirs from archive' do expect(subject).to receive(:tar).and_return('blabla-tar') expect(subject).to receive(:run_pipeline!).with([%w(blabla-tar --exclude=lost+found --exclude=./@pages.tmp -C /var/gitlab-pages -cf - .), 'gzip -c -1'], any_args) - subject.dump('registry.tar.gz') + subject.dump('registry.tar.gz', 'backup_id') end it 'raises an error on failure' do @@ -133,7 +133,7 @@ RSpec.describe Backup::Files do expect(subject).to receive(:pipeline_succeeded?).and_return(false) expect do - subject.dump('registry.tar.gz') + subject.dump('registry.tar.gz', 'backup_id') end.to raise_error(/Failed to create compressed file/) end @@ -149,7 +149,7 @@ RSpec.describe Backup::Files do .with(%w(rsync -a --delete --exclude=lost+found --exclude=/gitlab-pages/@pages.tmp /var/gitlab-pages /var/gitlab-backup)) .and_return(['', 0]) - subject.dump('registry.tar.gz') + subject.dump('registry.tar.gz', 'backup_id') end it 'retries if rsync fails due to vanishing files' do @@ -158,7 +158,7 @@ RSpec.describe Backup::Files do .and_return(['rsync failed', 24], ['', 0]) expect do - subject.dump('registry.tar.gz') + subject.dump('registry.tar.gz', 'backup_id') end.to output(/files vanished during rsync, retrying/).to_stdout end @@ -168,7 +168,7 @@ RSpec.describe Backup::Files do .and_return(['rsync failed', 1]) expect do - subject.dump('registry.tar.gz') + subject.dump('registry.tar.gz', 'backup_id') end.to output(/rsync failed/).to_stdout .and raise_error(/Failed to create compressed file/) end diff --git a/spec/lib/backup/gitaly_backup_spec.rb b/spec/lib/backup/gitaly_backup_spec.rb index c1b232290dc..399e4ffa72b 100644 --- a/spec/lib/backup/gitaly_backup_spec.rb +++ b/spec/lib/backup/gitaly_backup_spec.rb @@ -25,11 +25,11 @@ RSpec.describe Backup::GitalyBackup do progress.close end - subject { described_class.new(progress, max_parallelism: max_parallelism, storage_parallelism: storage_parallelism, backup_id: backup_id) } + subject { described_class.new(progress, max_parallelism: max_parallelism, storage_parallelism: storage_parallelism) } context 'unknown' do it 'fails to start unknown' do - expect { subject.start(:unknown, destination) }.to raise_error(::Backup::Error, 'unknown backup type: unknown') + expect { subject.start(:unknown, destination, backup_id: backup_id) }.to raise_error(::Backup::Error, 'unknown backup type: unknown') end end @@ -44,7 +44,7 @@ RSpec.describe Backup::GitalyBackup do expect(Open3).to receive(:popen2).with(expected_env, anything, 'create', '-path', anything, '-layout', 'pointer', '-id', backup_id).and_call_original - subject.start(:create, destination) + subject.start(:create, destination, backup_id: backup_id) subject.enqueue(project, Gitlab::GlRepository::PROJECT) subject.enqueue(project, Gitlab::GlRepository::WIKI) subject.enqueue(project, Gitlab::GlRepository::DESIGN) @@ -65,7 +65,7 @@ RSpec.describe Backup::GitalyBackup do it 'passes parallel option through' do expect(Open3).to receive(:popen2).with(expected_env, anything, 'create', '-path', anything, '-parallel', '3', '-layout', 'pointer', '-id', backup_id).and_call_original - subject.start(:create, destination) + subject.start(:create, destination, backup_id: backup_id) subject.finish! end end @@ -76,7 +76,7 @@ RSpec.describe Backup::GitalyBackup do it 'passes parallel option through' do expect(Open3).to receive(:popen2).with(expected_env, anything, 'create', '-path', anything, '-parallel-storage', '3', '-layout', 'pointer', '-id', backup_id).and_call_original - subject.start(:create, destination) + subject.start(:create, destination, backup_id: backup_id) subject.finish! end end @@ -84,14 +84,14 @@ RSpec.describe Backup::GitalyBackup do it 'raises when the exit code not zero' do expect(subject).to receive(:bin_path).and_return(Gitlab::Utils.which('false')) - subject.start(:create, destination) + subject.start(:create, destination, backup_id: backup_id) expect { subject.finish! }.to raise_error(::Backup::Error, 'gitaly-backup exit status 1') end it 'raises when gitaly_backup_path is not set' do stub_backup_setting(gitaly_backup_path: nil) - expect { subject.start(:create, destination) }.to raise_error(::Backup::Error, 'gitaly-backup binary not found and gitaly_backup_path is not configured') + expect { subject.start(:create, destination, backup_id: backup_id) }.to raise_error(::Backup::Error, 'gitaly-backup binary not found and gitaly_backup_path is not configured') end context 'feature flag incremental_repository_backup disabled' do @@ -108,7 +108,7 @@ RSpec.describe Backup::GitalyBackup do expect(Open3).to receive(:popen2).with(expected_env, anything, 'create', '-path', anything).and_call_original - subject.start(:create, destination) + subject.start(:create, destination, backup_id: backup_id) subject.enqueue(project, Gitlab::GlRepository::PROJECT) subject.enqueue(project, Gitlab::GlRepository::WIKI) subject.enqueue(project, Gitlab::GlRepository::DESIGN) @@ -152,7 +152,7 @@ RSpec.describe Backup::GitalyBackup do it 'passes through SSL envs' do expect(Open3).to receive(:popen2).with(ssl_env, anything, 'create', '-path', anything, '-layout', 'pointer', '-id', backup_id).and_call_original - subject.start(:create, destination) + subject.start(:create, destination, backup_id: backup_id) subject.finish! end end @@ -177,7 +177,7 @@ RSpec.describe Backup::GitalyBackup do expect(Open3).to receive(:popen2).with(expected_env, anything, 'restore', '-path', anything, '-layout', 'pointer').and_call_original - subject.start(:restore, destination) + subject.start(:restore, destination, backup_id: backup_id) subject.enqueue(project, Gitlab::GlRepository::PROJECT) subject.enqueue(project, Gitlab::GlRepository::WIKI) subject.enqueue(project, Gitlab::GlRepository::DESIGN) @@ -200,7 +200,7 @@ RSpec.describe Backup::GitalyBackup do it 'passes parallel option through' do expect(Open3).to receive(:popen2).with(expected_env, anything, 'restore', '-path', anything, '-parallel', '3', '-layout', 'pointer').and_call_original - subject.start(:restore, destination) + subject.start(:restore, destination, backup_id: backup_id) subject.finish! end end @@ -211,7 +211,7 @@ RSpec.describe Backup::GitalyBackup do it 'passes parallel option through' do expect(Open3).to receive(:popen2).with(expected_env, anything, 'restore', '-path', anything, '-parallel-storage', '3', '-layout', 'pointer').and_call_original - subject.start(:restore, destination) + subject.start(:restore, destination, backup_id: backup_id) subject.finish! end end @@ -230,7 +230,7 @@ RSpec.describe Backup::GitalyBackup do expect(Open3).to receive(:popen2).with(expected_env, anything, 'restore', '-path', anything).and_call_original - subject.start(:restore, destination) + subject.start(:restore, destination, backup_id: backup_id) subject.enqueue(project, Gitlab::GlRepository::PROJECT) subject.enqueue(project, Gitlab::GlRepository::WIKI) subject.enqueue(project, Gitlab::GlRepository::DESIGN) @@ -251,14 +251,14 @@ RSpec.describe Backup::GitalyBackup do it 'raises when the exit code not zero' do expect(subject).to receive(:bin_path).and_return(Gitlab::Utils.which('false')) - subject.start(:restore, destination) + subject.start(:restore, destination, backup_id: backup_id) expect { subject.finish! }.to raise_error(::Backup::Error, 'gitaly-backup exit status 1') end it 'raises when gitaly_backup_path is not set' do stub_backup_setting(gitaly_backup_path: nil) - expect { subject.start(:restore, destination) }.to raise_error(::Backup::Error, 'gitaly-backup binary not found and gitaly_backup_path is not configured') + expect { subject.start(:restore, destination, backup_id: backup_id) }.to raise_error(::Backup::Error, 'gitaly-backup binary not found and gitaly_backup_path is not configured') end end end diff --git a/spec/lib/backup/lfs_spec.rb b/spec/lib/backup/lfs_spec.rb index a27f60f20d0..130012e4935 100644 --- a/spec/lib/backup/lfs_spec.rb +++ b/spec/lib/backup/lfs_spec.rb @@ -20,7 +20,7 @@ RSpec.describe Backup::Lfs do expect(backup).to receive(:run_pipeline!).with([%w(blabla-tar --exclude=lost+found -C /var/lfs-objects -cf - .), 'gzip -c -1'], any_args).and_return([[true, true], '']) expect(backup).to receive(:pipeline_succeeded?).and_return(true) - backup.dump('lfs.tar.gz') + backup.dump('lfs.tar.gz', 'backup_id') end end end diff --git a/spec/lib/backup/manager_spec.rb b/spec/lib/backup/manager_spec.rb index 04045c00981..f640a0dba9c 100644 --- a/spec/lib/backup/manager_spec.rb +++ b/spec/lib/backup/manager_spec.rb @@ -147,7 +147,8 @@ RSpec.describe Backup::Manager do describe '#create' do let(:incremental_env) { 'false' } let(:expected_backup_contents) { %w{backup_information.yml task1.tar.gz task2.tar.gz} } - let(:tar_file) { '1546300800_2019_01_01_12.3_gitlab_backup.tar' } + let(:backup_id) { '1546300800_2019_01_01_12.3' } + let(:tar_file) { "#{backup_id}_gitlab_backup.tar" } let(:tar_system_options) { { out: [tar_file, 'w', Gitlab.config.backup.archive_permissions] } } let(:tar_cmdline) { ['tar', '-cf', '-', *expected_backup_contents, tar_system_options] } let(:backup_information) do @@ -176,8 +177,8 @@ RSpec.describe Backup::Manager do .and_return(backup_information) allow(subject).to receive(:backup_information).and_return(backup_information) - allow(task1).to receive(:dump).with(File.join(Gitlab.config.backup.path, 'task1.tar.gz')) - allow(task2).to receive(:dump).with(File.join(Gitlab.config.backup.path, 'task2.tar.gz')) + allow(task1).to receive(:dump).with(File.join(Gitlab.config.backup.path, 'task1.tar.gz'), backup_id) + allow(task2).to receive(:dump).with(File.join(Gitlab.config.backup.path, 'task2.tar.gz'), backup_id) end it 'executes tar' do @@ -201,7 +202,7 @@ RSpec.describe Backup::Manager do end context 'when BACKUP is set' do - let(:tar_file) { 'custom_gitlab_backup.tar' } + let(:backup_id) { 'custom' } it 'uses the given value as tar file name' do stub_env('BACKUP', '/ignored/path/custom') @@ -581,7 +582,8 @@ RSpec.describe Backup::Manager do context 'incremental' do let(:incremental_env) { 'true' } let(:gitlab_version) { Gitlab::VERSION } - let(:tar_file) { "1546300800_2019_01_01_#{gitlab_version}_gitlab_backup.tar" } + let(:backup_id) { "1546300800_2019_01_01_#{gitlab_version}" } + let(:tar_file) { "#{backup_id}_gitlab_backup.tar" } let(:backup_information) do { backup_created_at: Time.zone.parse('2019-01-01'), @@ -645,6 +647,7 @@ RSpec.describe Backup::Manager do end context 'when BACKUP variable is set to a correct file' do + let(:backup_id) { '1451606400_2016_01_01_1.2.3' } let(:tar_cmdline) { %w{tar -xf 1451606400_2016_01_01_1.2.3_gitlab_backup.tar} } before do diff --git a/spec/lib/backup/object_backup_spec.rb b/spec/lib/backup/object_backup_spec.rb index 85658173b0e..c0284942001 100644 --- a/spec/lib/backup/object_backup_spec.rb +++ b/spec/lib/backup/object_backup_spec.rb @@ -21,7 +21,7 @@ RSpec.shared_examples 'backup object' do |setting| expect(backup).to receive(:run_pipeline!).with([%W(blabla-tar --exclude=lost+found --exclude=./tmp -C #{backup_path} -cf - .), 'gzip -c -1'], any_args).and_return([[true, true], '']) expect(backup).to receive(:pipeline_succeeded?).and_return(true) - backup.dump('backup_object.tar.gz') + backup.dump('backup_object.tar.gz', 'backup_id') end end end diff --git a/spec/lib/backup/pages_spec.rb b/spec/lib/backup/pages_spec.rb index 095dda61cf4..3af8de306ce 100644 --- a/spec/lib/backup/pages_spec.rb +++ b/spec/lib/backup/pages_spec.rb @@ -19,7 +19,7 @@ RSpec.describe Backup::Pages do expect(subject).to receive(:tar).and_return('blabla-tar') expect(subject).to receive(:run_pipeline!).with([%w(blabla-tar --exclude=lost+found --exclude=./@pages.tmp -C /var/gitlab-pages -cf - .), 'gzip -c -1'], any_args).and_return([[true, true], '']) expect(subject).to receive(:pipeline_succeeded?).and_return(true) - subject.dump('pages.tar.gz') + subject.dump('pages.tar.gz', 'backup_id') end end end diff --git a/spec/lib/backup/repositories_spec.rb b/spec/lib/backup/repositories_spec.rb index 911a8895be3..c6f611e727c 100644 --- a/spec/lib/backup/repositories_spec.rb +++ b/spec/lib/backup/repositories_spec.rb @@ -6,6 +6,7 @@ RSpec.describe Backup::Repositories do let(:progress) { spy(:stdout) } let(:strategy) { spy(:strategy) } let(:destination) { 'repositories' } + let(:backup_id) { 'backup_id' } subject do described_class.new( @@ -22,9 +23,9 @@ RSpec.describe Backup::Repositories do project_snippet = create(:project_snippet, :repository, project: project) personal_snippet = create(:personal_snippet, :repository, author: project.first_owner) - subject.dump(destination) + subject.dump(destination, backup_id) - expect(strategy).to have_received(:start).with(:create, destination) + expect(strategy).to have_received(:start).with(:create, destination, backup_id: backup_id) expect(strategy).to have_received(:enqueue).with(project, Gitlab::GlRepository::PROJECT) expect(strategy).to have_received(:enqueue).with(project, Gitlab::GlRepository::WIKI) expect(strategy).to have_received(:enqueue).with(project, Gitlab::GlRepository::DESIGN) @@ -50,25 +51,25 @@ RSpec.describe Backup::Repositories do it 'enqueue_project raises an error' do allow(strategy).to receive(:enqueue).with(anything, Gitlab::GlRepository::PROJECT).and_raise(IOError) - expect { subject.dump(destination) }.to raise_error(IOError) + expect { subject.dump(destination, backup_id) }.to raise_error(IOError) end it 'project query raises an error' do allow(Project).to receive_message_chain(:includes, :find_each).and_raise(ActiveRecord::StatementTimeout) - expect { subject.dump(destination) }.to raise_error(ActiveRecord::StatementTimeout) + expect { subject.dump(destination, backup_id) }.to raise_error(ActiveRecord::StatementTimeout) end end it 'avoids N+1 database queries' do control_count = ActiveRecord::QueryRecorder.new do - subject.dump(destination) + subject.dump(destination, backup_id) end.count create_list(:project, 2, :repository) expect do - subject.dump(destination) + subject.dump(destination, backup_id) end.not_to exceed_query_limit(control_count) end end diff --git a/spec/lib/backup/task_spec.rb b/spec/lib/backup/task_spec.rb index b0eb885d3f4..f6c6e44ce6b 100644 --- a/spec/lib/backup/task_spec.rb +++ b/spec/lib/backup/task_spec.rb @@ -15,7 +15,7 @@ RSpec.describe Backup::Task do describe '#dump' do it 'must be implemented by the subclass' do - expect { subject.dump('some/path') }.to raise_error(NotImplementedError) + expect { subject.dump('some/path', 'backup_id') }.to raise_error(NotImplementedError) end end diff --git a/spec/lib/backup/uploads_spec.rb b/spec/lib/backup/uploads_spec.rb index 0cfc80a9cb9..4a05f592208 100644 --- a/spec/lib/backup/uploads_spec.rb +++ b/spec/lib/backup/uploads_spec.rb @@ -19,7 +19,7 @@ RSpec.describe Backup::Uploads do expect(backup).to receive(:tar).and_return('blabla-tar') expect(backup).to receive(:run_pipeline!).with([%w(blabla-tar --exclude=lost+found --exclude=./tmp -C /var/uploads -cf - .), 'gzip -c -1'], any_args).and_return([[true, true], '']) expect(backup).to receive(:pipeline_succeeded?).and_return(true) - backup.dump('uploads.tar.gz') + backup.dump('uploads.tar.gz', 'backup_id') end end end diff --git a/spec/lib/gitlab/background_migration/backfill_group_features_spec.rb b/spec/lib/gitlab/background_migration/backfill_group_features_spec.rb new file mode 100644 index 00000000000..4705f0d0ab9 --- /dev/null +++ b/spec/lib/gitlab/background_migration/backfill_group_features_spec.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::BackgroundMigration::BackfillGroupFeatures, :migration, schema: 20220302114046 do + let(:group_features) { table(:group_features) } + let(:namespaces) { table(:namespaces) } + + subject { described_class.new(connection: ActiveRecord::Base.connection) } + + describe '#perform' do + it 'creates settings for all group namespaces in range' do + namespaces.create!(id: 1, name: 'group1', path: 'group1', type: 'Group') + namespaces.create!(id: 2, name: 'user', path: 'user') + namespaces.create!(id: 3, name: 'group2', path: 'group2', type: 'Group') + + # Checking that no error is raised if the group_feature for a group already exists + namespaces.create!(id: 4, name: 'group3', path: 'group3', type: 'Group') + group_features.create!(id: 1, group_id: 4) + expect(group_features.count).to eq 1 + + expect { subject.perform(1, 4, :namespaces, :id, 10, 0, 4) }.to change { group_features.count }.by(2) + + expect(group_features.count).to eq 3 + expect(group_features.all.pluck(:group_id)).to contain_exactly(1, 3, 4) + end + end +end diff --git a/spec/lib/gitlab/ci/config/external/file/artifact_spec.rb b/spec/lib/gitlab/ci/config/external/file/artifact_spec.rb index 8dd92c5b5fd..3678b46c8ff 100644 --- a/spec/lib/gitlab/ci/config/external/file/artifact_spec.rb +++ b/spec/lib/gitlab/ci/config/external/file/artifact_spec.rb @@ -29,14 +29,15 @@ RSpec.describe Gitlab::Ci::Config::External::File::Artifact do end describe '#valid?' do - shared_examples 'is invalid' do - it 'is not valid' do - expect(external_file).not_to be_valid - end + subject(:valid?) do + external_file.validate! + external_file.valid? + end + shared_examples 'is invalid' do it 'sets the expected error' do - expect(external_file.errors) - .to contain_exactly(expected_error) + expect(valid?).to be_falsy + expect(external_file.errors).to contain_exactly(expected_error) end end @@ -142,7 +143,7 @@ RSpec.describe Gitlab::Ci::Config::External::File::Artifact do context 'when file is not empty' do it 'is valid' do - expect(external_file).to be_valid + expect(valid?).to be_truthy expect(external_file.content).to be_present end @@ -154,6 +155,7 @@ RSpec.describe Gitlab::Ci::Config::External::File::Artifact do user: anything } expect(context).to receive(:mutate).with(expected_attrs).and_call_original + external_file.validate! external_file.content end end diff --git a/spec/lib/gitlab/ci/config/external/file/base_spec.rb b/spec/lib/gitlab/ci/config/external/file/base_spec.rb index 445edb253fd..a3a319313c4 100644 --- a/spec/lib/gitlab/ci/config/external/file/base_spec.rb +++ b/spec/lib/gitlab/ci/config/external/file/base_spec.rb @@ -16,7 +16,7 @@ RSpec.describe Gitlab::Ci::Config::External::File::Base do end end - subject { test_class.new(location, context) } + subject(:file) { test_class.new(location, context) } before do allow_any_instance_of(test_class) @@ -31,7 +31,7 @@ RSpec.describe Gitlab::Ci::Config::External::File::Base do let(:location) { 'some-location' } it 'returns true' do - expect(subject).to be_matching + expect(file).to be_matching end end @@ -39,40 +39,45 @@ RSpec.describe Gitlab::Ci::Config::External::File::Base do let(:location) { nil } it 'returns false' do - expect(subject).not_to be_matching + expect(file).not_to be_matching end end end describe '#valid?' do + subject(:valid?) do + file.validate! + file.valid? + end + context 'when location is not a string' do let(:location) { %w(some/file.txt other/file.txt) } - it { is_expected.not_to be_valid } + it { is_expected.to be_falsy } end context 'when location is not a YAML file' do let(:location) { 'some/file.txt' } - it { is_expected.not_to be_valid } + it { is_expected.to be_falsy } end context 'when location has not a valid naming scheme' do let(:location) { 'some/file/.yml' } - it { is_expected.not_to be_valid } + it { is_expected.to be_falsy } end context 'when location is a valid .yml extension' do let(:location) { 'some/file/config.yml' } - it { is_expected.to be_valid } + it { is_expected.to be_truthy } end context 'when location is a valid .yaml extension' do let(:location) { 'some/file/config.yaml' } - it { is_expected.to be_valid } + it { is_expected.to be_truthy } end context 'when there are YAML syntax errors' do @@ -84,8 +89,8 @@ RSpec.describe Gitlab::Ci::Config::External::File::Base do end it 'is not a valid file' do - expect(subject).not_to be_valid - expect(subject.error_message).to match /does not have valid YAML syntax/ + expect(valid?).to be_falsy + expect(file.error_message).to match /does not have valid YAML syntax/ end end end @@ -101,7 +106,7 @@ RSpec.describe Gitlab::Ci::Config::External::File::Base do end it 'does expand hash to include the template' do - expect(subject.to_hash).to include(:before_script) + expect(file.to_hash).to include(:before_script) end end end diff --git a/spec/lib/gitlab/ci/config/external/file/local_spec.rb b/spec/lib/gitlab/ci/config/external/file/local_spec.rb index dec3eebe7b1..a13e4410207 100644 --- a/spec/lib/gitlab/ci/config/external/file/local_spec.rb +++ b/spec/lib/gitlab/ci/config/external/file/local_spec.rb @@ -54,6 +54,11 @@ RSpec.describe Gitlab::Ci::Config::External::File::Local do end describe '#valid?' do + subject(:valid?) do + local_file.validate! + local_file.valid? + end + context 'when is a valid local path' do let(:location) { '/lib/gitlab/ci/templates/existent-file.yml' } @@ -61,25 +66,19 @@ RSpec.describe Gitlab::Ci::Config::External::File::Local do allow_any_instance_of(described_class).to receive(:fetch_local_content).and_return("image: 'ruby2:2'") end - it 'returns true' do - expect(local_file.valid?).to be_truthy - end + it { is_expected.to be_truthy } end context 'when is not a valid local path' do let(:location) { '/lib/gitlab/ci/templates/non-existent-file.yml' } - it 'returns false' do - expect(local_file.valid?).to be_falsy - end + it { is_expected.to be_falsy } end context 'when is not a yaml file' do let(:location) { '/config/application.rb' } - it 'returns false' do - expect(local_file.valid?).to be_falsy - end + it { is_expected.to be_falsy } end context 'when the given sha is not valid' do @@ -87,7 +86,7 @@ RSpec.describe Gitlab::Ci::Config::External::File::Local do let(:sha) { ':' } it 'returns false and adds an error message stating that included file does not exist' do - expect(local_file).not_to be_valid + expect(valid?).to be_falsy expect(local_file.errors).to include("Sha #{sha} is not valid!") end end @@ -128,6 +127,10 @@ RSpec.describe Gitlab::Ci::Config::External::File::Local do describe '#error_message' do let(:location) { '/lib/gitlab/ci/templates/non-existent-file.yml' } + before do + local_file.validate! + end + it 'returns an error message' do expect(local_file.error_message).to eq("Local file `#{location}` does not exist!") end @@ -162,6 +165,8 @@ RSpec.describe Gitlab::Ci::Config::External::File::Local do allow(project.repository).to receive(:blob_data_at).with(sha, another_location) .and_return(another_content) + + local_file.validate! end it 'does expand hash to include the template' do diff --git a/spec/lib/gitlab/ci/config/external/file/project_spec.rb b/spec/lib/gitlab/ci/config/external/file/project_spec.rb index c53914c5772..96d67b65abe 100644 --- a/spec/lib/gitlab/ci/config/external/file/project_spec.rb +++ b/spec/lib/gitlab/ci/config/external/file/project_spec.rb @@ -65,6 +65,11 @@ RSpec.describe Gitlab::Ci::Config::External::File::Project do end describe '#valid?' do + subject(:valid?) do + project_file.validate! + project_file.valid? + end + context 'when a valid path is used' do let(:params) do { project: project.full_path, file: '/file.yml' } @@ -76,15 +81,13 @@ RSpec.describe Gitlab::Ci::Config::External::File::Project do stub_project_blob(root_ref_sha, '/file.yml') { 'image: ruby:2.7' } end - it 'returns true' do - expect(project_file).to be_valid - end + it { is_expected.to be_truthy } context 'when user does not have permission to access file' do let(:context_user) { create(:user) } it 'returns false' do - expect(project_file).not_to be_valid + expect(valid?).to be_falsy expect(project_file.error_message).to include("Project `#{project.full_path}` not found or access denied!") end end @@ -101,9 +104,7 @@ RSpec.describe Gitlab::Ci::Config::External::File::Project do stub_project_blob(ref_sha, '/file.yml') { 'image: ruby:2.7' } end - it 'returns true' do - expect(project_file).to be_valid - end + it { is_expected.to be_truthy } end context 'when an empty file is used' do @@ -118,7 +119,7 @@ RSpec.describe Gitlab::Ci::Config::External::File::Project do end it 'returns false' do - expect(project_file).not_to be_valid + expect(valid?).to be_falsy expect(project_file.error_message).to include("Project `#{project.full_path}` file `/file.yml` is empty!") end end @@ -129,7 +130,7 @@ RSpec.describe Gitlab::Ci::Config::External::File::Project do end it 'returns false' do - expect(project_file).not_to be_valid + expect(valid?).to be_falsy expect(project_file.error_message).to include("Project `#{project.full_path}` reference `I-Do-Not-Exist` does not exist!") end end @@ -140,7 +141,7 @@ RSpec.describe Gitlab::Ci::Config::External::File::Project do end it 'returns false' do - expect(project_file).not_to be_valid + expect(valid?).to be_falsy expect(project_file.error_message).to include("Project `#{project.full_path}` file `/invalid-file.yml` does not exist!") end end @@ -151,7 +152,7 @@ RSpec.describe Gitlab::Ci::Config::External::File::Project do end it 'returns false' do - expect(project_file).not_to be_valid + expect(valid?).to be_falsy expect(project_file.error_message).to include('Included file `/invalid-file` does not have YAML extension!') end end diff --git a/spec/lib/gitlab/ci/config/external/file/remote_spec.rb b/spec/lib/gitlab/ci/config/external/file/remote_spec.rb index ab60ac215ba..56113532787 100644 --- a/spec/lib/gitlab/ci/config/external/file/remote_spec.rb +++ b/spec/lib/gitlab/ci/config/external/file/remote_spec.rb @@ -53,22 +53,23 @@ RSpec.describe Gitlab::Ci::Config::External::File::Remote do end describe "#valid?" do + subject(:valid?) do + remote_file.validate! + remote_file.valid? + end + context 'when is a valid remote url' do before do stub_full_request(location).to_return(body: remote_file_content) end - it 'returns true' do - expect(remote_file.valid?).to be_truthy - end + it { is_expected.to be_truthy } end context 'with an irregular url' do let(:location) { 'not-valid://gitlab.com/gitlab-org/gitlab-foss/blob/1234/.gitlab-ci-1.yml' } - it 'returns false' do - expect(remote_file.valid?).to be_falsy - end + it { is_expected.to be_falsy } end context 'with a timeout' do @@ -76,25 +77,19 @@ RSpec.describe Gitlab::Ci::Config::External::File::Remote do allow(Gitlab::HTTP).to receive(:get).and_raise(Timeout::Error) end - it 'is falsy' do - expect(remote_file.valid?).to be_falsy - end + it { is_expected.to be_falsy } end context 'when is not a yaml file' do let(:location) { 'https://asdasdasdaj48ggerexample.com' } - it 'is falsy' do - expect(remote_file.valid?).to be_falsy - end + it { is_expected.to be_falsy } end context 'with an internal url' do let(:location) { 'http://localhost:8080' } - it 'is falsy' do - expect(remote_file.valid?).to be_falsy - end + it { is_expected.to be_falsy } end end @@ -141,7 +136,10 @@ RSpec.describe Gitlab::Ci::Config::External::File::Remote do end describe "#error_message" do - subject { remote_file.error_message } + subject(:error_message) do + remote_file.validate! + remote_file.error_message + end context 'when remote file location is not valid' do let(:location) { 'not-valid://gitlab.com/gitlab-org/gitlab-foss/blob/1234/.gitlab-ci-1.yml' } diff --git a/spec/lib/gitlab/ci/config/external/file/template_spec.rb b/spec/lib/gitlab/ci/config/external/file/template_spec.rb index 75b22c1516c..2bbaa46a8c4 100644 --- a/spec/lib/gitlab/ci/config/external/file/template_spec.rb +++ b/spec/lib/gitlab/ci/config/external/file/template_spec.rb @@ -45,19 +45,22 @@ RSpec.describe Gitlab::Ci::Config::External::File::Template do end describe "#valid?" do + subject(:valid?) do + template_file.validate! + template_file.valid? + end + context 'when is a valid template name' do let(:template) { 'Auto-DevOps.gitlab-ci.yml' } - it 'returns true' do - expect(template_file).to be_valid - end + it { is_expected.to be_truthy } end context 'with invalid template name' do let(:template) { 'Template.yml' } it 'returns false' do - expect(template_file).not_to be_valid + expect(valid?).to be_falsy expect(template_file.error_message).to include('Template file `Template.yml` is not a valid location!') end end @@ -66,7 +69,7 @@ RSpec.describe Gitlab::Ci::Config::External::File::Template do let(:template) { 'I-Do-Not-Have-This-Template.gitlab-ci.yml' } it 'returns false' do - expect(template_file).not_to be_valid + expect(valid?).to be_falsy expect(template_file.error_message).to include('Included file `I-Do-Not-Have-This-Template.gitlab-ci.yml` is empty or does not exist!') end end diff --git a/spec/migrations/backfill_group_features_spec.rb b/spec/migrations/backfill_group_features_spec.rb new file mode 100644 index 00000000000..922d54f43be --- /dev/null +++ b/spec/migrations/backfill_group_features_spec.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe BackfillGroupFeatures, :migration do + let(:migration) { described_class::MIGRATION } + + describe '#up' do + it 'schedules background jobs for each batch of namespaces' do + migrate! + + expect(migration).to have_scheduled_batched_migration( + table_name: :namespaces, + column_name: :id, + job_arguments: [described_class::BATCH_SIZE], + interval: described_class::INTERVAL, + batch_size: described_class::BATCH_SIZE + ) + end + end + + describe '#down' do + it 'deletes all batched migration records' do + migrate! + schema_migrate_down! + + expect(migration).not_to have_scheduled_batched_migration + end + end +end diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb index d2a29228df3..9e4644e4054 100644 --- a/spec/models/group_spec.rb +++ b/spec/models/group_spec.rb @@ -41,6 +41,7 @@ RSpec.describe Group do it { is_expected.to have_many(:contacts).class_name('CustomerRelations::Contact') } it { is_expected.to have_many(:organizations).class_name('CustomerRelations::Organization') } it { is_expected.to have_one(:crm_settings) } + it { is_expected.to have_one(:group_feature) } describe '#members & #requesters' do let(:requester) { create(:user) } @@ -295,6 +296,21 @@ RSpec.describe Group do it_behaves_like 'a BulkUsersByEmailLoad model' + context 'after initialized' do + it 'has a group_feature' do + expect(described_class.new.group_feature).to be_present + end + end + + context 'when creating a new project' do + let_it_be(:group) { create(:group) } + + it 'automatically creates the groups feature for the group' do + expect(group.group_feature).to be_an_instance_of(Groups::FeatureSetting) + expect(group.group_feature).to be_persisted + end + end + context 'traversal_ids on create' do context 'default traversal_ids' do let(:group) { build(:group) } diff --git a/spec/tasks/dev_rake_spec.rb b/spec/tasks/dev_rake_spec.rb index 7c03b4f417c..0abed33ec87 100644 --- a/spec/tasks/dev_rake_spec.rb +++ b/spec/tasks/dev_rake_spec.rb @@ -40,33 +40,45 @@ RSpec.describe 'dev rake tasks' do end end - describe 'copy_db:ci' do + context 'multiple databases' do before do skip_if_multiple_databases_not_setup - - configurations = instance_double(ActiveRecord::DatabaseConfigurations) - allow(ActiveRecord::Base).to receive(:configurations).and_return(configurations) - allow(configurations).to receive(:configs_for).with(env_name: Rails.env, name: 'ci').and_return(ci_configuration) end - subject(:load_task) { run_rake_task('dev:setup_ci_db') } + context 'with a valid database' do + describe 'copy_db:ci' do + before do + configurations = instance_double(ActiveRecord::DatabaseConfigurations) + allow(ActiveRecord::Base).to receive(:configurations).and_return(configurations) + allow(configurations).to receive(:configs_for).with(env_name: Rails.env, name: 'ci').and_return(ci_configuration) + end - let(:ci_configuration) { instance_double(ActiveRecord::DatabaseConfigurations::HashConfig, name: 'ci', database: '__test_db_ci') } + subject(:load_task) { run_rake_task('dev:setup_ci_db') } - it 'creates the database from main' do - expect(ApplicationRecord.connection).to receive(:create_database).with( - ci_configuration.database, - template: ApplicationRecord.connection_db_config.database - ) + let(:ci_configuration) { instance_double(ActiveRecord::DatabaseConfigurations::HashConfig, name: 'ci', database: '__test_db_ci') } - run_rake_task('dev:copy_db:ci') - end + it 'creates the database from main' do + expect(ApplicationRecord.connection).to receive(:create_database).with( + ci_configuration.database, + template: ApplicationRecord.connection_db_config.database + ) + + run_rake_task('dev:copy_db:ci') + end - context 'when the database already exists' do - it 'prints out a warning' do - expect(ApplicationRecord.connection).to receive(:create_database).and_raise(ActiveRecord::DatabaseAlreadyExists) + context 'when the database already exists' do + it 'prints out a warning' do + expect(ApplicationRecord.connection).to receive(:create_database).and_raise(ActiveRecord::DatabaseAlreadyExists) + + expect { run_rake_task('dev:copy_db:ci') }.to output(/Database '#{ci_configuration.database}' already exists/).to_stderr + end + end + end + end - expect { run_rake_task('dev:copy_db:ci') }.to output(/Database '#{ci_configuration.database}' already exists/).to_stderr + context 'with an invalid database' do + it 'raises an error' do + expect { run_rake_task('dev:copy_db:foo') }.to raise_error(RuntimeError, /Don't know how to build task/) end end end diff --git a/spec/views/profiles/keys/_form.html.haml_spec.rb b/spec/views/profiles/keys/_form.html.haml_spec.rb index 624d7492aea..ba8394178d9 100644 --- a/spec/views/profiles/keys/_form.html.haml_spec.rb +++ b/spec/views/profiles/keys/_form.html.haml_spec.rb @@ -30,8 +30,8 @@ RSpec.describe 'profiles/keys/_form.html.haml' do end it 'has the title field', :aggregate_failures do - expect(rendered).to have_field('Title', type: 'text', placeholder: 'e.g. My MacBook key') - expect(rendered).to have_text('Give your individual key a title. This will be publicly visible.') + expect(rendered).to have_field('Title', type: 'text', placeholder: 'Example: MacBook key') + expect(rendered).to have_text('Key titles are publicly visible.') end it 'has the expires at field', :aggregate_failures do diff --git a/yarn.lock b/yarn.lock index 239cdab6692..a0ef7910326 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,13 @@ # yarn lockfile v1 +"@ampproject/remapping@^2.1.0": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.1.2.tgz#4edca94973ded9630d20101cd8559cedb8d8bd34" + integrity sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg== + dependencies: + "@jridgewell/trace-mapping" "^0.3.0" + "@apollo/client@^3.5.10": version "3.5.10" resolved "https://registry.yarnpkg.com/@apollo/client/-/client-3.5.10.tgz#43463108a6e07ae602cca0afc420805a19339a71" @@ -41,38 +48,54 @@ dependencies: "@babel/highlight" "^7.16.7" -"@babel/compat-data@^7.10.1", "@babel/compat-data@^7.16.4": - version "7.16.8" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.16.8.tgz#31560f9f29fdf1868de8cb55049538a1b9732a60" - integrity sha512-m7OkX0IdKLKPpBlJtF561YJal5y/jyI5fNfWbPxh2D/nbzzGI4qRyrD8xO2jB24u7l+5I2a43scCG2IrfjC50Q== +"@babel/compat-data@^7.10.1", "@babel/compat-data@^7.17.7": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.17.7.tgz#078d8b833fbbcc95286613be8c716cef2b519fa2" + integrity sha512-p8pdE6j0a29TNGebNm7NzYZWB3xVZJBZ7XGs42uAKzQo8VQ3F0By/cQCtUEABwIqw5zo6WA4NbmxsfzADzMKnQ== -"@babel/core@^7.1.0", "@babel/core@^7.10.1", "@babel/core@^7.7.5": - version "7.16.12" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.16.12.tgz#5edc53c1b71e54881315923ae2aedea2522bb784" - integrity sha512-dK5PtG1uiN2ikk++5OzSYsitZKny4wOCD0nrO4TqnW4BVBTQ2NGS3NgilvT/TEyxTST7LNyWV/T4tXDoD3fOgg== +"@babel/core@^7.1.0", "@babel/core@^7.10.1", "@babel/core@^7.17.0", "@babel/core@^7.7.5": + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.17.8.tgz#3dac27c190ebc3a4381110d46c80e77efe172e1a" + integrity sha512-OdQDV/7cRBtJHLSOBqqbYNkOcydOgnX59TZx4puf41fzcVtN3e/4yqY8lMQsK+5X2lJtAdmA+6OHqsj1hBJ4IQ== dependencies: + "@ampproject/remapping" "^2.1.0" "@babel/code-frame" "^7.16.7" - "@babel/generator" "^7.16.8" - "@babel/helper-compilation-targets" "^7.16.7" - "@babel/helper-module-transforms" "^7.16.7" - "@babel/helpers" "^7.16.7" - "@babel/parser" "^7.16.12" + "@babel/generator" "^7.17.7" + "@babel/helper-compilation-targets" "^7.17.7" + "@babel/helper-module-transforms" "^7.17.7" + "@babel/helpers" "^7.17.8" + "@babel/parser" "^7.17.8" "@babel/template" "^7.16.7" - "@babel/traverse" "^7.16.10" - "@babel/types" "^7.16.8" + "@babel/traverse" "^7.17.3" + "@babel/types" "^7.17.0" convert-source-map "^1.7.0" debug "^4.1.0" gensync "^1.0.0-beta.2" json5 "^2.1.2" semver "^6.3.0" - source-map "^0.5.0" -"@babel/generator@^7.15.4", "@babel/generator@^7.16.8": - version "7.16.8" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.16.8.tgz#359d44d966b8cd059d543250ce79596f792f2ebe" - integrity sha512-1ojZwE9+lOXzcWdWmO6TbUzDfqLD39CmEhN8+2cX9XkDo5yW1OpgfejfliysR2AWLpMamTiOiAp/mtroaymhpw== +"@babel/eslint-parser@^7.17.0": + version "7.17.0" + resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.17.0.tgz#eabb24ad9f0afa80e5849f8240d0e5facc2d90d6" + integrity sha512-PUEJ7ZBXbRkbq3qqM/jZ2nIuakUBqCYc7Qf52Lj7dlZ6zERnqisdHioL0l4wwQZnmskMeasqUNzLBFKs3nylXA== dependencies: - "@babel/types" "^7.16.8" + eslint-scope "^5.1.1" + eslint-visitor-keys "^2.1.0" + semver "^6.3.0" + +"@babel/eslint-plugin@^7.17.7": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/eslint-plugin/-/eslint-plugin-7.17.7.tgz#4ee1d5b29b79130f3bb5a933358376bcbee172b8" + integrity sha512-JATUoJJXSgwI0T8juxWYtK1JSgoLpIGUsCHIv+NMXcUDA2vIe6nvAHR9vnuJgs/P1hOFw7vPwibixzfqBBLIVw== + dependencies: + eslint-rule-composer "^0.3.0" + +"@babel/generator@^7.15.4", "@babel/generator@^7.17.3", "@babel/generator@^7.17.7": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.17.7.tgz#8da2599beb4a86194a3b24df6c085931d9ee45ad" + integrity sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w== + dependencies: + "@babel/types" "^7.17.0" jsesc "^2.5.1" source-map "^0.5.0" @@ -91,12 +114,12 @@ "@babel/helper-explode-assignable-expression" "^7.10.1" "@babel/types" "^7.10.1" -"@babel/helper-compilation-targets@^7.10.2", "@babel/helper-compilation-targets@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz#06e66c5f299601e6c7da350049315e83209d551b" - integrity sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA== +"@babel/helper-compilation-targets@^7.10.2", "@babel/helper-compilation-targets@^7.17.7": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.17.7.tgz#a3c2924f5e5f0379b356d4cfb313d1414dc30e46" + integrity sha512-UFzlz2jjd8kroj0hmCFV5zr+tQPi1dpC2cRsDV/3IEW8bJfCPrPpmcSN6ZS8RqIq4LXcmpipCQFPddyFA5Yc7w== dependencies: - "@babel/compat-data" "^7.16.4" + "@babel/compat-data" "^7.17.7" "@babel/helper-validator-option" "^7.16.7" browserslist "^4.17.5" semver "^6.3.0" @@ -183,19 +206,19 @@ dependencies: "@babel/types" "^7.16.7" -"@babel/helper-module-transforms@^7.10.1", "@babel/helper-module-transforms@^7.15.0", "@babel/helper-module-transforms@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.16.7.tgz#7665faeb721a01ca5327ddc6bba15a5cb34b6a41" - integrity sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng== +"@babel/helper-module-transforms@^7.10.1", "@babel/helper-module-transforms@^7.15.0", "@babel/helper-module-transforms@^7.17.7": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.17.7.tgz#3943c7f777139e7954a5355c815263741a9c1cbd" + integrity sha512-VmZD99F3gNTYB7fJRDTi+u6l/zxY0BE6OIxPSU7a50s6ZUQkHwSDmV92FfM+oCG0pZRVojGYhkR8I0OGeCVREw== dependencies: "@babel/helper-environment-visitor" "^7.16.7" "@babel/helper-module-imports" "^7.16.7" - "@babel/helper-simple-access" "^7.16.7" + "@babel/helper-simple-access" "^7.17.7" "@babel/helper-split-export-declaration" "^7.16.7" "@babel/helper-validator-identifier" "^7.16.7" "@babel/template" "^7.16.7" - "@babel/traverse" "^7.16.7" - "@babel/types" "^7.16.7" + "@babel/traverse" "^7.17.3" + "@babel/types" "^7.17.0" "@babel/helper-optimise-call-expression@^7.10.1", "@babel/helper-optimise-call-expression@^7.15.4": version "7.15.4" @@ -237,12 +260,12 @@ "@babel/traverse" "^7.15.4" "@babel/types" "^7.15.4" -"@babel/helper-simple-access@^7.14.8", "@babel/helper-simple-access@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz#d656654b9ea08dbb9659b69d61063ccd343ff0f7" - integrity sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g== +"@babel/helper-simple-access@^7.14.8", "@babel/helper-simple-access@^7.17.7": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.17.7.tgz#aaa473de92b7987c6dfa7ce9a7d9674724823367" + integrity sha512-txyMCGroZ96i+Pxr3Je3lzEJjqwaRC9buMUgtomcrLe5Nd0+fk1h0LLA+ixUF5OW7AhHuQ7Es1WcQJZmZsz2XA== dependencies: - "@babel/types" "^7.16.7" + "@babel/types" "^7.17.0" "@babel/helper-skip-transparent-expression-wrappers@^7.14.5": version "7.15.4" @@ -258,7 +281,7 @@ dependencies: "@babel/types" "^7.16.7" -"@babel/helper-validator-identifier@^7.14.9", "@babel/helper-validator-identifier@^7.16.7": +"@babel/helper-validator-identifier@^7.14.9", "@babel/helper-validator-identifier@^7.15.7", "@babel/helper-validator-identifier@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad" integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw== @@ -278,14 +301,14 @@ "@babel/traverse" "^7.10.1" "@babel/types" "^7.10.1" -"@babel/helpers@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.16.7.tgz#7e3504d708d50344112767c3542fc5e357fffefc" - integrity sha512-9ZDoqtfY7AuEOt3cxchfii6C7GDyyMBffktR5B2jvWv8u2+efwvpnVKXMWzNehqy68tKgAfSwfdw/lWpthS2bw== +"@babel/helpers@^7.17.8": + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.17.8.tgz#288450be8c6ac7e4e44df37bcc53d345e07bc106" + integrity sha512-QcL86FGxpfSJwGtAvv4iG93UL6bmqBdmoVY0CMCU2g+oD2ezQse3PT5Pa+jiD6LJndBQi0EDlpzOWNlLuhz5gw== dependencies: "@babel/template" "^7.16.7" - "@babel/traverse" "^7.16.7" - "@babel/types" "^7.16.7" + "@babel/traverse" "^7.17.3" + "@babel/types" "^7.17.0" "@babel/highlight@^7.10.4", "@babel/highlight@^7.16.0", "@babel/highlight@^7.16.7": version "7.16.10" @@ -301,10 +324,10 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.15.8.tgz#7bacdcbe71bdc3ff936d510c15dcea7cf0b99016" integrity sha512-BRYa3wcQnjS/nqI8Ac94pYYpJfojHVvVXJ97+IDCImX4Jc8W8Xv1+47enbruk+q1etOpsQNwnfFcNGw+gtPGxA== -"@babel/parser@^7.0.0", "@babel/parser@^7.1.0", "@babel/parser@^7.15.4", "@babel/parser@^7.16.10", "@babel/parser@^7.16.12", "@babel/parser@^7.16.7": - version "7.16.12" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.16.12.tgz#9474794f9a650cf5e2f892444227f98e28cdf8b6" - integrity sha512-VfaV15po8RiZssrkPweyvbGVSe4x2y+aciFCgn0n0/SJMR22cwofRV1mtnJQYcSB1wUTaA/X1LnA3es66MCO5A== +"@babel/parser@^7.1.0", "@babel/parser@^7.15.4", "@babel/parser@^7.16.7", "@babel/parser@^7.17.3", "@babel/parser@^7.17.8": + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.8.tgz#2817fb9d885dd8132ea0f8eb615a6388cca1c240" + integrity sha512-BoHhDJrJXqcg+ZL16Xv39H9n+AqJ4pcDrQBGZN+wHxIysrLZ3/ECwCBUch/1zUNhnsXULcONU3Ei5Hmkfk6kiQ== "@babel/plugin-proposal-async-generator-functions@^7.10.1": version "7.10.1" @@ -864,19 +887,19 @@ debug "^4.1.0" globals "^11.1.0" -"@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.10.1", "@babel/traverse@^7.15.4", "@babel/traverse@^7.16.10", "@babel/traverse@^7.16.7": - version "7.16.10" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.16.10.tgz#448f940defbe95b5a8029975b051f75993e8239f" - integrity sha512-yzuaYXoRJBGMlBhsMJoUW7G1UmSb/eXr/JHYM/MsOJgavJibLwASijW7oXBdw3NQ6T0bW7Ty5P/VarOs9cHmqw== +"@babel/traverse@^7.1.0", "@babel/traverse@^7.10.1", "@babel/traverse@^7.15.4", "@babel/traverse@^7.17.3": + version "7.17.3" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.17.3.tgz#0ae0f15b27d9a92ba1f2263358ea7c4e7db47b57" + integrity sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw== dependencies: "@babel/code-frame" "^7.16.7" - "@babel/generator" "^7.16.8" + "@babel/generator" "^7.17.3" "@babel/helper-environment-visitor" "^7.16.7" "@babel/helper-function-name" "^7.16.7" "@babel/helper-hoist-variables" "^7.16.7" "@babel/helper-split-export-declaration" "^7.16.7" - "@babel/parser" "^7.16.10" - "@babel/types" "^7.16.8" + "@babel/parser" "^7.17.3" + "@babel/types" "^7.17.0" debug "^4.1.0" globals "^11.1.0" @@ -888,10 +911,10 @@ "@babel/helper-validator-identifier" "^7.14.9" to-fast-properties "^2.0.0" -"@babel/types@^7.0.0", "@babel/types@^7.0.0-beta.49", "@babel/types@^7.10.1", "@babel/types@^7.10.2", "@babel/types@^7.15.4", "@babel/types@^7.16.7", "@babel/types@^7.16.8", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4": - version "7.16.8" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.16.8.tgz#0ba5da91dd71e0a4e7781a30f22770831062e3c1" - integrity sha512-smN2DQc5s4M7fntyjGtyIPbRJv6wW4rU/94fmYJ7PKQuZkC0qGMHXJbg6sNGt12JmVr4k5YaptI/XtiLJBnmIg== +"@babel/types@^7.0.0", "@babel/types@^7.0.0-beta.49", "@babel/types@^7.10.1", "@babel/types@^7.10.2", "@babel/types@^7.15.4", "@babel/types@^7.16.7", "@babel/types@^7.17.0", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4": + version "7.17.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.17.0.tgz#a826e368bccb6b3d84acd76acad5c0d87342390b" + integrity sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw== dependencies: "@babel/helper-validator-identifier" "^7.16.7" to-fast-properties "^2.0.0" @@ -949,19 +972,21 @@ resolved "https://registry.yarnpkg.com/@gitlab/at.js/-/at.js-1.5.7.tgz#1ee6f838cc4410a1d797770934df91d90df8179e" integrity sha512-c6ySRK/Ma7lxwpIVbSAF3P+xiTLrNTGTLRx4/pHK111AdFxwgUwrYF6aVZFXvmG65jHOJHoa0eQQ21RW6rm0Rg== -"@gitlab/eslint-plugin@11.0.0": - version "11.0.0" - resolved "https://registry.yarnpkg.com/@gitlab/eslint-plugin/-/eslint-plugin-11.0.0.tgz#90d71bc0c5f54ac066faba8c6f909b0df761d0bb" - integrity sha512-5t1eTu/+myitEP68ceKQRRE0S5R1QStlRVykivZFZDxGloCyAq1zE96ZwqsMzDtpfK5fmf1+7yxGw9CPdLUB/A== +"@gitlab/eslint-plugin@12.0.1": + version "12.0.1" + resolved "https://registry.yarnpkg.com/@gitlab/eslint-plugin/-/eslint-plugin-12.0.1.tgz#307486721e51cef223cf03dd2bae6d67d3286237" + integrity sha512-YVa6Pegiklu22V7jN/cj77E10L2M0aEN3A4UTzbCH57yQOVwyJC+bG33/eqzq175YFYWwnbkCOB22lBMLDizYQ== dependencies: - babel-eslint "^10.0.3" + "@babel/core" "^7.17.0" + "@babel/eslint-parser" "^7.17.0" + "@babel/eslint-plugin" "^7.17.7" eslint-config-airbnb-base "^14.2.1" eslint-config-prettier "^6.10.0" eslint-plugin-babel "^5.3.0" - eslint-plugin-filenames "^1.3.2" eslint-plugin-import "^2.22.1" eslint-plugin-jest "^23.8.2" eslint-plugin-promise "^4.2.1" + eslint-plugin-unicorn "^40.1.0" eslint-plugin-vue "^7.5.0" lodash "^4.17.21" vue-eslint-parser "^7.0.0" @@ -1378,6 +1403,24 @@ "@types/yargs" "^15.0.0" chalk "^4.0.0" +"@jridgewell/resolve-uri@^3.0.3": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz#68eb521368db76d040a6315cdb24bf2483037b9c" + integrity sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew== + +"@jridgewell/sourcemap-codec@^1.4.10": + version "1.4.11" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz#771a1d8d744eeb71b6adb35808e1a6c7b9b8c8ec" + integrity sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg== + +"@jridgewell/trace-mapping@^0.3.0": + version "0.3.4" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz#f6a0832dffd5b8a6aaa633b7d9f8e8e94c83a0c3" + integrity sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@miragejs/pretender-node-polyfill@^0.1.0": version "0.1.2" resolved "https://registry.yarnpkg.com/@miragejs/pretender-node-polyfill/-/pretender-node-polyfill-0.1.2.tgz#d26b6b7483fb70cd62189d05c95d2f67153e43f2" @@ -2801,18 +2844,6 @@ axios@^0.24.0: dependencies: follow-redirects "^1.14.4" -babel-eslint@^10.0.3: - version "10.0.3" - resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.0.3.tgz#81a2c669be0f205e19462fed2482d33e4687a88a" - integrity sha512-z3U7eMY6r/3f3/JB9mTsLjyxrv0Yb1zb8PCWCLpguxfCzBIZUwy23R1t/XKewP+8mEN2Ck8Dtr4q20z6ce6SoA== - dependencies: - "@babel/code-frame" "^7.0.0" - "@babel/parser" "^7.0.0" - "@babel/traverse" "^7.0.0" - "@babel/types" "^7.0.0" - eslint-visitor-keys "^1.0.0" - resolve "^1.12.0" - babel-jest@^26.5.2: version "26.5.2" resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-26.5.2.tgz#164f367a35946c6cf54eaccde8762dec50422250" @@ -3193,6 +3224,11 @@ buffer@^5.7.0: base64-js "^1.3.1" ieee754 "^1.1.13" +builtin-modules@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.2.0.tgz#45d5db99e7ee5e6bc4f362e008bf917ab5049887" + integrity sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA== + builtin-status-codes@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" @@ -3449,6 +3485,11 @@ ci-info@^2.0.0: resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== +ci-info@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.3.0.tgz#b4ed1fb6818dea4803a55c623041f9165d2066b2" + integrity sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw== + cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" @@ -3467,6 +3508,13 @@ class-utils@^0.3.5: isobject "^3.0.0" static-extend "^0.1.1" +clean-regexp@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/clean-regexp/-/clean-regexp-1.0.0.tgz#8df7c7aae51fd36874e8f8d05b9180bc11a3fed7" + integrity sha1-jffHquUf02h06PjQW5GAvBGj/tc= + dependencies: + escape-string-regexp "^1.0.5" + clean-stack@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" @@ -5303,16 +5351,6 @@ eslint-plugin-babel@^5.3.0: dependencies: eslint-rule-composer "^0.3.0" -eslint-plugin-filenames@^1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/eslint-plugin-filenames/-/eslint-plugin-filenames-1.3.2.tgz#7094f00d7aefdd6999e3ac19f72cea058e590cf7" - integrity sha512-tqxJTiEM5a0JmRCUYQmxw23vtTxrb2+a3Q2mMOPhFxvt7ZQQJmdiuMby9B/vUAuVMghyP7oET+nIf6EO6CBd/w== - dependencies: - lodash.camelcase "4.3.0" - lodash.kebabcase "4.1.1" - lodash.snakecase "4.1.1" - lodash.upperfirst "4.3.1" - eslint-plugin-import@^2.22.1: version "2.22.1" resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.22.1.tgz#0896c7e6a0cf44109a2d97b95903c2bb689d7702" @@ -5349,6 +5387,26 @@ eslint-plugin-promise@^4.2.1: resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-4.2.1.tgz#845fd8b2260ad8f82564c1222fce44ad71d9418a" integrity sha512-VoM09vT7bfA7D+upt+FjeBO5eHIJQBUWki1aPvB+vbNiHS3+oGIJGIeyBtKQTME6UPXXy3vV07OL1tHd3ANuDw== +eslint-plugin-unicorn@^40.1.0: + version "40.1.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-unicorn/-/eslint-plugin-unicorn-40.1.0.tgz#48975360e39d23df726e4b33e8dd5d650e184832" + integrity sha512-y5doK2DF9Sr5AqKEHbHxjFllJ167nKDRU01HDcWyv4Tnmaoe9iNxMrBnaybZvWZUaE3OC5Unu0lNIevYamloig== + dependencies: + "@babel/helper-validator-identifier" "^7.15.7" + ci-info "^3.3.0" + clean-regexp "^1.0.0" + eslint-utils "^3.0.0" + esquery "^1.4.0" + indent-string "^4.0.0" + is-builtin-module "^3.1.0" + lodash "^4.17.21" + pluralize "^8.0.0" + read-pkg-up "^7.0.1" + regexp-tree "^0.1.24" + safe-regex "^2.1.1" + semver "^7.3.5" + strip-indent "^3.0.0" + eslint-plugin-vue@^7.5.0: version "7.5.0" resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-7.5.0.tgz#cc6d983eb22781fa2440a7573cf39af439bb5725" @@ -5387,15 +5445,22 @@ eslint-utils@^2.0.0, eslint-utils@^2.1.0: dependencies: eslint-visitor-keys "^1.1.0" -eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: +eslint-utils@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" + integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== + dependencies: + eslint-visitor-keys "^2.0.0" + +eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== -eslint-visitor-keys@^2.0.0: - version "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-visitor-keys@^2.0.0, eslint-visitor-keys@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" + integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== eslint@7.32.0: version "7.32.0" @@ -6800,6 +6865,13 @@ is-buffer@^1.1.5, is-buffer@~1.1.1: resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== +is-builtin-module@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-3.1.0.tgz#6fdb24313b1c03b75f8b9711c0feb8c30b903b00" + integrity sha512-OV7JjAgOTfAFJmHZLvpSTb4qi0nIILDV1gWPYDnDJUTNFM5aGlRAhk4QcT8i7TuAleeEV5Fdkqn3t4mS+Q11fg== + dependencies: + builtin-modules "^3.0.0" + is-callable@^1.1.4, is-callable@^1.2.2: version "1.2.3" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.3.tgz#8b1e0500b73a1d76c70487636f368e519de8db8e" @@ -7943,7 +8015,7 @@ lodash.assign@^4.2.0: resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7" integrity sha1-DZnzzNem0mHRm9rrkkUAXShYCOc= -lodash.camelcase@4.3.0, lodash.camelcase@^4.3.0: +lodash.camelcase@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY= @@ -8013,11 +8085,6 @@ lodash.isplainobject@^4.0.6: resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs= -lodash.kebabcase@4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz#8489b1cb0d29ff88195cceca448ff6d6cc295c36" - integrity sha1-hImxyw0p/4gZXM7KRI/21swpXDY= - lodash.lowercase@4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/lodash.lowercase/-/lodash.lowercase-4.3.0.tgz#46515aced4acb0b7093133333af068e4c3b14e9d" @@ -8048,7 +8115,7 @@ lodash.pick@^4.4.0: resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3" integrity sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM= -lodash.snakecase@4.1.1, lodash.snakecase@^4.1.1: +lodash.snakecase@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz#39d714a35357147837aefd64b5dcbb16becd8f8d" integrity sha1-OdcUo1NXFHg3rv1ktdy7Fr7Nj40= @@ -8073,11 +8140,6 @@ lodash.uniqby@^4.7.0: resolved "https://registry.yarnpkg.com/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz#d99c07a669e9e6d24e1362dfe266c67616af1302" integrity sha1-2ZwHpmnp5tJOE2Lf4mbGdhavEwI= -lodash.upperfirst@4.3.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/lodash.upperfirst/-/lodash.upperfirst-4.3.1.tgz#1365edf431480481ef0d1c68957a5ed99d49f7ce" - integrity sha1-E2Xt9DFIBIHvDRxolXpe2Z1J984= - lodash.values@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/lodash.values/-/lodash.values-4.3.0.tgz#a3a6c2b0ebecc5c2cba1c17e6e620fe81b53d347" @@ -9366,6 +9428,11 @@ pkg-dir@^4.1.0, pkg-dir@^4.2.0: dependencies: find-up "^4.0.0" +pluralize@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-8.0.0.tgz#1a6fa16a38d12a1901e0320fa017051c539ce3b1" + integrity sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA== + pofile@1.0.x: version "1.0.11" resolved "https://registry.yarnpkg.com/pofile/-/pofile-1.0.11.tgz#35aff58c17491d127a07336d5522ebc9df57c954" @@ -10045,6 +10112,11 @@ regex-not@^1.0.0, regex-not@^1.0.2: extend-shallow "^3.0.2" safe-regex "^1.1.0" +regexp-tree@^0.1.24, regexp-tree@~0.1.1: + version "0.1.24" + resolved "https://registry.yarnpkg.com/regexp-tree/-/regexp-tree-0.1.24.tgz#3d6fa238450a4d66e5bc9c4c14bb720e2196829d" + integrity sha512-s2aEVuLhvnVJW6s/iPgEGK6R+/xngd2jNQ+xy4bXNDKxZKJH6jpPHY6kVeVv1IeLCHgswRj+Kl3ELaDjG6V1iw== + regexpp@^3.1.0: version "3.2.0" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" @@ -10322,6 +10394,13 @@ safe-regex@^1.1.0: dependencies: ret "~0.1.10" +safe-regex@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-2.1.1.tgz#f7128f00d056e2fe5c11e81a1324dd974aadced2" + integrity sha512-rx+x8AMzKb5Q5lQ95Zoi6ZbJqwCLkqi3XuJXp5P3rT8OEc6sZCJG5AE5dU3lsgRr/F4Bs31jSlVN+j5KrsGu9A== + dependencies: + regexp-tree "~0.1.1" + "safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" @@ -10455,7 +10534,7 @@ semver@^6.0.0, semver@^6.2.0, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -semver@^7.2.1, semver@^7.3.2, semver@^7.3.4: +semver@^7.2.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5: version "7.3.5" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== |
