Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2021-06-23 21:08:33 +00:00
parent d04f2be14d
commit 87e9d9675a
25 changed files with 312 additions and 140 deletions

View File

@ -1,12 +1,12 @@
<script>
import { GlDrawer } from '@gitlab/ui';
import { MountingPortal } from 'portal-vue';
import { mapState, mapActions, mapGetters } from 'vuex';
import SidebarDropdownWidget from 'ee_else_ce/sidebar/components/sidebar_dropdown_widget.vue';
import BoardSidebarLabelsSelect from '~/boards/components/sidebar/board_sidebar_labels_select.vue';
import BoardSidebarTimeTracker from '~/boards/components/sidebar/board_sidebar_time_tracker.vue';
import BoardSidebarTitle from '~/boards/components/sidebar/board_sidebar_title.vue';
import { ISSUABLE } from '~/boards/constants';
import { contentTop } from '~/lib/utils/common_utils';
import SidebarAssigneesWidget from '~/sidebar/components/assignees/sidebar_assignees_widget.vue';
import SidebarConfidentialityWidget from '~/sidebar/components/confidential/sidebar_confidentiality_widget.vue';
import SidebarDateWidget from '~/sidebar/components/date/sidebar_date_widget.vue';
@ -14,7 +14,6 @@ import SidebarSubscriptionsWidget from '~/sidebar/components/subscriptions/sideb
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
export default {
headerHeight: `${contentTop()}px`,
components: {
GlDrawer,
BoardSidebarTitle,
@ -25,6 +24,7 @@ export default {
BoardSidebarLabelsSelect,
SidebarSubscriptionsWidget,
SidebarDropdownWidget,
MountingPortal,
BoardSidebarWeightInput: () =>
import('ee_component/boards/components/sidebar/board_sidebar_weight_input.vue'),
IterationSidebarDropdownWidget: () =>
@ -45,6 +45,7 @@ export default {
default: false,
},
},
inheritAttrs: false,
computed: {
...mapGetters([
'isSidebarOpen',
@ -73,85 +74,88 @@ export default {
</script>
<template>
<gl-drawer
v-if="showSidebar"
:open="isSidebarOpen"
:header-height="$options.headerHeight"
@close="handleClose"
>
<template #header>{{ __('Issue details') }}</template>
<template #default>
<board-sidebar-title />
<sidebar-assignees-widget
:iid="activeBoardItem.iid"
:full-path="fullPath"
:initial-assignees="activeBoardItem.assignees"
:allow-multiple-assignees="multipleAssigneesFeatureAvailable"
@assignees-updated="setAssignees"
/>
<sidebar-dropdown-widget
v-if="epicFeatureAvailable"
:iid="activeBoardItem.iid"
issuable-attribute="epic"
:workspace-path="projectPathForActiveIssue"
:attr-workspace-path="groupPathForActiveIssue"
:issuable-type="issuableType"
data-testid="sidebar-epic"
/>
<div>
<sidebar-dropdown-widget
<mounting-portal mount-to="#js-right-sidebar-portal" name="board-content-sidebar" append>
<gl-drawer
v-if="showSidebar"
v-bind="$attrs"
:open="isSidebarOpen"
class="gl-absolute"
@close="handleClose"
>
<template #header>{{ __('Issue details') }}</template>
<template #default>
<board-sidebar-title />
<sidebar-assignees-widget
:iid="activeBoardItem.iid"
issuable-attribute="milestone"
:workspace-path="projectPathForActiveIssue"
:attr-workspace-path="projectPathForActiveIssue"
:issuable-type="issuableType"
data-testid="sidebar-milestones"
:full-path="fullPath"
:initial-assignees="activeBoardItem.assignees"
:allow-multiple-assignees="multipleAssigneesFeatureAvailable"
@assignees-updated="setAssignees"
/>
<template v-if="!glFeatures.iterationCadences">
<sidebar-dropdown-widget
v-if="epicFeatureAvailable"
:iid="activeBoardItem.iid"
issuable-attribute="epic"
:workspace-path="projectPathForActiveIssue"
:attr-workspace-path="groupPathForActiveIssue"
:issuable-type="issuableType"
data-testid="sidebar-epic"
/>
<div>
<sidebar-dropdown-widget
v-if="iterationFeatureAvailable"
:iid="activeBoardItem.iid"
issuable-attribute="iteration"
issuable-attribute="milestone"
:workspace-path="projectPathForActiveIssue"
:attr-workspace-path="groupPathForActiveIssue"
:attr-workspace-path="projectPathForActiveIssue"
:issuable-type="issuableType"
class="gl-mt-5"
data-testid="iteration-edit"
data-testid="sidebar-milestones"
/>
</template>
<template v-else>
<iteration-sidebar-dropdown-widget
v-if="iterationFeatureAvailable"
:iid="activeBoardItem.iid"
:workspace-path="projectPathForActiveIssue"
:attr-workspace-path="groupPathForActiveIssue"
:issuable-type="issuableType"
class="gl-mt-5"
data-testid="iteration-edit"
/>
</template>
</div>
<board-sidebar-time-tracker class="swimlanes-sidebar-time-tracker" />
<sidebar-date-widget
:iid="activeBoardItem.iid"
:full-path="fullPath"
:issuable-type="issuableType"
data-testid="sidebar-due-date"
/>
<board-sidebar-labels-select class="labels" />
<board-sidebar-weight-input v-if="weightFeatureAvailable" class="weight" />
<sidebar-confidentiality-widget
:iid="activeBoardItem.iid"
:full-path="fullPath"
:issuable-type="issuableType"
@confidentialityUpdated="setActiveItemConfidential($event)"
/>
<sidebar-subscriptions-widget
:iid="activeBoardItem.iid"
:full-path="fullPath"
:issuable-type="issuableType"
data-testid="sidebar-notifications"
/>
</template>
</gl-drawer>
<template v-if="!glFeatures.iterationCadences">
<sidebar-dropdown-widget
v-if="iterationFeatureAvailable"
:iid="activeBoardItem.iid"
issuable-attribute="iteration"
:workspace-path="projectPathForActiveIssue"
:attr-workspace-path="groupPathForActiveIssue"
:issuable-type="issuableType"
class="gl-mt-5"
data-testid="iteration-edit"
/>
</template>
<template v-else>
<iteration-sidebar-dropdown-widget
v-if="iterationFeatureAvailable"
:iid="activeBoardItem.iid"
:workspace-path="projectPathForActiveIssue"
:attr-workspace-path="groupPathForActiveIssue"
:issuable-type="issuableType"
class="gl-mt-5"
data-testid="iteration-edit"
/>
</template>
</div>
<board-sidebar-time-tracker class="swimlanes-sidebar-time-tracker" />
<sidebar-date-widget
:iid="activeBoardItem.iid"
:full-path="fullPath"
:issuable-type="issuableType"
data-testid="sidebar-due-date"
/>
<board-sidebar-labels-select class="labels" />
<board-sidebar-weight-input v-if="weightFeatureAvailable" class="weight" />
<sidebar-confidentiality-widget
:iid="activeBoardItem.iid"
:full-path="fullPath"
:issuable-type="issuableType"
@confidentialityUpdated="setActiveItemConfidential($event)"
/>
<sidebar-subscriptions-widget
:iid="activeBoardItem.iid"
:full-path="fullPath"
:issuable-type="issuableType"
data-testid="sidebar-notifications"
/>
</template>
</gl-drawer>
</mounting-portal>
</template>

View File

@ -1,5 +1,6 @@
<script>
import { GlButton, GlDrawer, GlLabel } from '@gitlab/ui';
import { MountingPortal } from 'portal-vue';
import { mapActions, mapState, mapGetters } from 'vuex';
import { LIST, ListType, ListTypeTitles } from '~/boards/constants';
import boardsStore from '~/boards/stores/boards_store';
@ -9,14 +10,13 @@ import eventHub from '~/sidebar/event_hub';
import Tracking from '~/tracking';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
// NOTE: need to revisit how we handle headerHeight, because we have so many different header and footer options.
export default {
headerHeight: process.env.NODE_ENV === 'development' ? '75px' : '40px',
listSettingsText: __('List settings'),
components: {
GlButton,
GlDrawer,
GlLabel,
MountingPortal,
BoardSettingsSidebarWipLimit: () =>
import('ee_component/boards/components/board_settings_wip_limit.vue'),
BoardSettingsListTypes: () =>
@ -24,6 +24,7 @@ export default {
},
mixins: [glFeatureFlagMixin(), Tracking.mixin()],
inject: ['canAdminList'],
inheritAttrs: false,
data() {
return {
ListType,
@ -86,43 +87,45 @@ export default {
</script>
<template>
<gl-drawer
v-if="showSidebar"
class="js-board-settings-sidebar"
:open="isSidebarOpen"
:header-height="$options.headerHeight"
@close="unsetActiveId"
>
<template #header>{{ $options.listSettingsText }}</template>
<template v-if="isSidebarOpen">
<div v-if="boardListType === ListType.label">
<label class="js-list-label gl-display-block">{{ listTypeTitle }}</label>
<gl-label
:title="activeListLabel.title"
:background-color="activeListLabel.color"
:scoped="showScopedLabels(activeListLabel)"
/>
</div>
<mounting-portal mount-to="#js-right-sidebar-portal" name="board-settings-sidebar" append>
<gl-drawer
v-if="showSidebar"
v-bind="$attrs"
class="js-board-settings-sidebar gl-absolute"
:open="isSidebarOpen"
@close="unsetActiveId"
>
<template #header>{{ $options.listSettingsText }}</template>
<template v-if="isSidebarOpen">
<div v-if="boardListType === ListType.label">
<label class="js-list-label gl-display-block">{{ listTypeTitle }}</label>
<gl-label
:title="activeListLabel.title"
:background-color="activeListLabel.color"
:scoped="showScopedLabels(activeListLabel)"
/>
</div>
<board-settings-list-types
v-else
:active-list="activeList"
:board-list-type="boardListType"
/>
<board-settings-sidebar-wip-limit
v-if="isWipLimitsOn"
:max-issue-count="activeList.maxIssueCount"
/>
<div v-if="canAdminList && !activeList.preset && activeList.id" class="gl-mt-4">
<gl-button
variant="danger"
category="secondary"
icon="remove"
data-testid="remove-list"
@click.stop="deleteBoard"
>{{ __('Remove list') }}
</gl-button>
</div>
</template>
</gl-drawer>
<board-settings-list-types
v-else
:active-list="activeList"
:board-list-type="boardListType"
/>
<board-settings-sidebar-wip-limit
v-if="isWipLimitsOn"
:max-issue-count="activeList.maxIssueCount"
/>
<div v-if="canAdminList && !activeList.preset && activeList.id" class="gl-mt-4">
<gl-button
variant="danger"
category="secondary"
icon="remove"
data-testid="remove-list"
@click.stop="deleteBoard"
>{{ __('Remove list') }}
</gl-button>
</div>
</template>
</gl-drawer>
</mounting-portal>
</template>

View File

@ -1,4 +1,5 @@
import { IntrospectionFragmentMatcher } from 'apollo-cache-inmemory';
import PortalVue from 'portal-vue';
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import { mapActions, mapGetters } from 'vuex';
@ -41,6 +42,7 @@ import boardConfigToggle from './config_toggle';
import mountMultipleBoardsSwitcher from './mount_multiple_boards_switcher';
Vue.use(VueApollo);
Vue.use(PortalVue);
const fragmentMatcher = new IntrospectionFragmentMatcher({
introspectionQueryResultData,

View File

@ -21,5 +21,5 @@
= file_field_tag :file, class: ''
.row
.form-actions.col-sm-12
= submit_tag _('Import project'), class: 'gl-button btn btn-confirm'
= submit_tag _('Import project'), class: 'gl-button btn btn-confirm', data: { qa_selector: 'import_project_button' }
= link_to _('Cancel'), new_project_path, class: 'gl-button btn btn-default btn-cancel'

View File

@ -1,7 +1,7 @@
.row
.form-group.project-name.col-sm-12
= label_tag :name, _('Project name'), class: 'label-bold'
= text_field_tag :name, @name, placeholder: "My awesome project", class: "js-project-name form-control gl-form-input input-lg", autofocus: true, required: true, aria: { required: true }
= text_field_tag :name, @name, placeholder: "My awesome project", class: "js-project-name form-control gl-form-input input-lg", autofocus: true, required: true, aria: { required: true }, data: { qa_selector: 'project_name_field' }
.form-group.col-12.col-sm-6
= label_tag :namespace_id, _('Project URL'), class: 'label-bold'
.form-group
@ -18,4 +18,4 @@
= hidden_field_tag :namespace_id, current_user.namespace_id
.form-group.col-12.col-sm-6.project-path
= label_tag :path, _('Project slug'), class: 'label-bold'
= text_field_tag :path, @path, placeholder: "my-awesome-project", class: "js-path-name form-control gl-form-input", required: true, aria: { required: true }
= text_field_tag :path, @path, placeholder: "my-awesome-project", class: "js-path-name form-control gl-form-input", required: true, aria: { required: true }, data: { qa_selector: 'project_slug_field' }

View File

@ -28,5 +28,6 @@
= render "layouts/flash", extra_flash_class: 'limit-container-width'
= yield :before_content
= yield
= yield :after_content
= render "layouts/nav/top_nav_responsive", class: 'layout-page content-wrapper-margin'

View File

@ -7,7 +7,7 @@
= _("Import project from")
.import-buttons
- if gitlab_project_import_enabled?
.import_gitlab_project.has-tooltip{ data: { container: 'body' } }
.import_gitlab_project.has-tooltip{ data: { container: 'body', qa_selector: 'gitlab_import_button' } }
= link_to new_import_gitlab_project_path, class: 'gl-button btn-default btn btn_import_gitlab_project', **tracking_attrs(track_label, 'click_button', 'gitlab_export') do
.gl-button-icon
= sprite_icon('tanuki')

View File

@ -2,6 +2,7 @@
- group = local_assigns.fetch(:group, false)
- @no_breadcrumb_container = true
- @no_container = true
- @content_wrapper_class = "#{@content_wrapper_class} gl-relative"
- @content_class = "issue-boards-content js-focus-mode-board"
- if board.to_type == "EpicBoard"
- breadcrumb_title _("Epic Boards")
@ -9,6 +10,9 @@
- breadcrumb_title _("Issue Boards")
= render 'shared/alerts/positioning_disabled'
= content_for :after_content do
#js-right-sidebar-portal
- page_title("#{board.name}", _("Boards"))
- add_page_specific_style 'page_bundles/boards'

View File

@ -0,0 +1,15 @@
# frozen_string_literal: true
class AddTimestampToSchemaMigration < ActiveRecord::Migration[6.1]
def up
# Add a nullable column with default null first
add_column :schema_migrations, :finished_at, :timestamptz
# Change default to NOW() for new records
change_column_default :schema_migrations, :finished_at, -> { 'NOW()' }
end
def down
remove_column :schema_migrations, :finished_at
end
end

View File

@ -0,0 +1 @@
52843d12ab18b92c71a334cf877682d9fae57632cf0ba14213dfc0543e39cf1b

View File

@ -17715,7 +17715,8 @@ CREATE SEQUENCE saml_providers_id_seq
ALTER SEQUENCE saml_providers_id_seq OWNED BY saml_providers.id;
CREATE TABLE schema_migrations (
version character varying NOT NULL
version character varying NOT NULL,
finished_at timestamp with time zone DEFAULT now()
);
CREATE TABLE scim_identities (

View File

@ -209,7 +209,7 @@
"commander": "^2.18.0",
"custom-jquery-matchers": "^2.1.0",
"docdash": "^1.0.2",
"eslint": "7.28.0",
"eslint": "7.29.0",
"eslint-import-resolver-jest": "3.0.0",
"eslint-import-resolver-webpack": "0.13.1",
"eslint-plugin-jasmine": "4.1.2",

View File

@ -107,6 +107,7 @@ module QA
autoload :RegistryRepository, 'qa/resource/registry_repository'
autoload :Package, 'qa/resource/package'
autoload :PipelineSchedules, 'qa/resource/pipeline_schedules'
autoload :ImportProject, 'qa/resource/import_project'
module KubernetesCluster
autoload :Base, 'qa/resource/kubernetes_cluster/base'
@ -530,6 +531,11 @@ module QA
autoload :CommitModal, 'qa/page/component/commit_modal'
autoload :VisibilitySetting, 'qa/page/component/visibility_setting'
module Import
autoload :Gitlab, 'qa/page/component/import/gitlab'
autoload :Selection, 'qa/page/component/import/selection'
end
module Issuable
autoload :Common, 'qa/page/component/issuable/common'
autoload :Sidebar, 'qa/page/component/issuable/sidebar'

Binary file not shown.

View File

@ -0,0 +1,40 @@
# frozen_string_literal: true
module QA
module Page
module Component
module Import
module Gitlab
def self.included(base)
super
base.view 'app/views/import/gitlab_projects/new.html.haml' do
element :import_project_button
end
base.view 'app/views/import/shared/_new_project_form.html.haml' do
element :project_name_field
element :project_slug_field
end
end
def set_imported_project_name(name)
fill_element(:project_name_field, name)
end
def attach_exported_file(path)
page.attach_file("file", path, make_visible: { display: 'block' })
end
def click_import_gitlab_project
click_element(:import_project_button)
wait_until(reload: false) do
has_notice?("The project was successfully imported.")
end
end
end
end
end
end
end

View File

@ -0,0 +1,23 @@
# frozen_string_literal: true
module QA
module Page
module Component
module Import
module Selection
def self.included(base)
super
base.view 'app/views/projects/_import_project_pane.html.haml' do
element :gitlab_import_button
end
end
def click_gitlab
click_element(:gitlab_import_button)
end
end
end
end
end
end

View File

@ -8,6 +8,10 @@ module QA
include Page::Component::Select2
include Page::Component::VisibilitySetting
include Layout::Flash
include Page::Component::Import::Selection
include Page::Component::Import::Gitlab
view 'app/views/projects/_new_project_fields.html.haml' do
element :initialize_with_readme_checkbox
element :project_namespace_select

View File

@ -0,0 +1,35 @@
# frozen_string_literal: true
module QA
module Resource
class ImportProject < Resource::Project
attr_writer :file_path
def initialize
@name = "ImportedProject-#{SecureRandom.hex(8)}"
@file_path = ::File.join('qa', 'fixtures', 'export.tar.gz')
end
def fabricate!
self.import = true
super
group.visit!
Page::Group::Show.perform(&:go_to_new_project)
Page::Project::New.perform do |new_project|
new_project.click_import_project
new_project.click_gitlab
new_project.set_imported_project_name(@name)
new_project.attach_exported_file(@file_path)
new_project.click_import_gitlab_project
end
end
def fabricate_via_api!
raise NotImplementedError
end
end
end
end

View File

@ -70,6 +70,8 @@ module QA
end
def fabricate!
return fabricate_large_merge_request if Runtime::Scenario.large_setup?
populate_target_and_source_if_required
project.visit!
@ -90,6 +92,8 @@ module QA
end
def fabricate_via_api!
return fabricate_large_merge_request if Runtime::Scenario.large_setup?
resource_web_url(api_get)
rescue ResourceNotFoundError, NoValueError # rescue if iid not populated
populate_target_and_source_if_required
@ -144,6 +148,15 @@ module QA
end
end
def fabricate_large_merge_request
@project = Resource::ImportProject.fabricate_via_browser_ui!
# Setting the name here, since otherwise some tests will look for an existing file in
# the proejct without ever knowing what is in it.
@file_name = "LICENSE"
visit("#{project.web_url}/-/merge_requests/1")
current_url
end
# Get MR comments
#
# @return [Array]

View File

@ -61,19 +61,17 @@ module QA
def verify_labels_import
labels = imported_project.labels.map { |label| label.slice(:name, :color) }
expect(labels).to eq(
[
{ name: 'bug', color: '#d73a4a' },
{ name: 'custom new label', color: '#fc8f91' },
{ name: 'documentation', color: '#0075ca' },
{ name: 'duplicate', color: '#cfd3d7' },
{ name: 'enhancement', color: '#a2eeef' },
{ name: 'good first issue', color: '#7057ff' },
{ name: 'help wanted', color: '#008672' },
{ name: 'invalid', color: '#e4e669' },
{ name: 'question', color: '#d876e3' },
{ name: 'wontfix', color: '#ffffff' }
]
expect(labels).to include(
{ name: 'bug', color: '#d73a4a' },
{ name: 'custom new label', color: '#fc8f91' },
{ name: 'documentation', color: '#0075ca' },
{ name: 'duplicate', color: '#cfd3d7' },
{ name: 'enhancement', color: '#a2eeef' },
{ name: 'good first issue', color: '#7057ff' },
{ name: 'help wanted', color: '#008672' },
{ name: 'invalid', color: '#e4e669' },
{ name: 'question', color: '#d876e3' },
{ name: 'wontfix', color: '#ffffff' }
)
end

View File

@ -19,7 +19,7 @@ module QA
Flow::Login.sign_in
end
it 'can be reverted', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1745' do
it 'can be reverted', :can_use_large_setup, testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1745' do
revertable_merge_request.visit!
Page::MergeRequest::Show.perform do |merge_request|

View File

@ -65,6 +65,8 @@ module QA
args.push(DEFAULT_TEST_PATH_ARGS) unless options.any? { |opt| opt =~ %r{/features/} }
end
Runtime::Scenario.define(:large_setup?, args.flatten.include?('can_use_large_setup'))
if Runtime::Scenario.attributes[:parallel]
ParallelRunner.run(args.flatten)
elsif Runtime::Scenario.attributes[:loop]

View File

@ -1,5 +1,6 @@
import { GlDrawer } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import { MountingPortal } from 'portal-vue';
import Vuex from 'vuex';
import SidebarDropdownWidget from 'ee_else_ce/sidebar/components/sidebar_dropdown_widget.vue';
import { stubComponent } from 'helpers/stub_component';
@ -90,6 +91,14 @@ describe('BoardContentSidebar', () => {
expect(wrapper.findComponent(GlDrawer).exists()).toBe(true);
});
it('confirms we render MountingPortal', () => {
expect(wrapper.find(MountingPortal).props()).toMatchObject({
mountTo: '#js-right-sidebar-portal',
append: true,
name: 'board-content-sidebar',
});
});
it('does not render GlDrawer when isSidebarOpen is false', () => {
createStore({ mockGetters: { isSidebarOpen: () => false } });
createComponent();

View File

@ -3,6 +3,7 @@ import { GlDrawer, GlLabel } from '@gitlab/ui';
import { shallowMount, createLocalVue } from '@vue/test-utils';
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import { MountingPortal } from 'portal-vue';
import Vuex from 'vuex';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import BoardSettingsSidebar from '~/boards/components/board_settings_sidebar.vue';
@ -51,6 +52,16 @@ describe('BoardSettingsSidebar', () => {
wrapper.destroy();
});
it('finds a MountingPortal component', () => {
createComponent();
expect(wrapper.find(MountingPortal).props()).toMatchObject({
mountTo: '#js-right-sidebar-portal',
append: true,
name: 'board-settings-sidebar',
});
});
describe('when sidebarType is "list"', () => {
it('finds a GlDrawer component', () => {
createComponent();

View File

@ -5017,10 +5017,10 @@ eslint-visitor-keys@^2.0.0:
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz#21fdc8fbcd9c795cc0321f0563702095751511a8"
integrity sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==
eslint@7.28.0:
version "7.28.0"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.28.0.tgz#435aa17a0b82c13bb2be9d51408b617e49c1e820"
integrity sha512-UMfH0VSjP0G4p3EWirscJEQ/cHqnT/iuH6oNZOB94nBjWbMnhGEPxsZm1eyIW0C/9jLI0Fow4W5DXLjEI7mn1g==
eslint@7.29.0:
version "7.29.0"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.29.0.tgz#ee2a7648f2e729485e4d0bd6383ec1deabc8b3c0"
integrity sha512-82G/JToB9qIy/ArBzIWG9xvvwL3R86AlCjtGw+A29OMZDqhTybz/MByORSukGxeI+YPCR4coYyITKk8BFH9nDA==
dependencies:
"@babel/code-frame" "7.12.11"
"@eslint/eslintrc" "^0.4.2"