提交 94221585 编写于 作者: G GitLab Bot

Add latest changes from gitlab-org/gitlab@master

上级 2319d04d
......@@ -89,10 +89,10 @@ export default {
eventHub.$emit('clearDetailIssue', isMultiSelect);
if (isMultiSelect) {
eventHub.$emit('newDetailIssue', [this.issue, isMultiSelect]);
eventHub.$emit('newDetailIssue', this.issue, isMultiSelect);
}
} else {
eventHub.$emit('newDetailIssue', [this.issue, isMultiSelect]);
eventHub.$emit('newDetailIssue', this.issue, isMultiSelect);
boardsStore.setListDetail(this.list);
}
}
......
......@@ -202,7 +202,7 @@ export default () => {
updateTokens() {
this.filterManager.updateTokens();
},
updateDetailIssue([newIssue, multiSelect = false]) {
updateDetailIssue(newIssue, multiSelect = false) {
const { sidebarInfoEndpoint } = newIssue;
if (sidebarInfoEndpoint && newIssue.subscribed === undefined) {
newIssue.setFetchingState('subscriptions', true);
......
......@@ -30,12 +30,9 @@ export default {
doAction() {
this.isLoading = true;
eventHub.$emit(`${this.type}.key`, [
this.deployKey,
() => {
this.isLoading = false;
},
]);
eventHub.$emit(`${this.type}.key`, this.deployKey, () => {
this.isLoading = false;
});
},
},
};
......
......@@ -90,13 +90,13 @@ export default {
return new Flash(s__('DeployKeys|Error getting deploy keys'));
});
},
enableKey([deployKey]) {
enableKey(deployKey) {
this.service
.enableKey(deployKey.id)
.then(this.fetchKeys)
.catch(() => new Flash(s__('DeployKeys|Error enabling deploy key')));
},
disableKey([deployKey, callback]) {
disableKey(deployKey, callback) {
if (
// eslint-disable-next-line no-alert
window.confirm(s__('DeployKeys|You are going to remove this deploy key. Are you sure?'))
......
......@@ -123,7 +123,7 @@ export default {
this.updateGroups(res, Boolean(filterGroupsBy));
});
},
fetchPage([page, filterGroupsBy, sortBy, archived]) {
fetchPage(page, filterGroupsBy, sortBy, archived) {
this.isLoading = true;
return this.fetchGroups({
......@@ -169,7 +169,7 @@ export default {
parentGroup.isOpen = false;
}
},
showLeaveGroupModal([group, parentGroup]) {
showLeaveGroupModal(group, parentGroup) {
const { fullName } = group;
this.targetGroup = group;
this.targetParentGroup = parentGroup;
......
......@@ -35,12 +35,7 @@ export default {
const filterGroupsParam = getParameterByName('filter');
const sortParam = getParameterByName('sort');
const archivedParam = getParameterByName('archived');
eventHub.$emit(`${this.action}fetchPage`, [
page,
filterGroupsParam,
sortParam,
archivedParam,
]);
eventHub.$emit(`${this.action}fetchPage`, page, filterGroupsParam, sortParam, archivedParam);
},
},
};
......
......@@ -37,7 +37,7 @@ export default {
},
methods: {
onLeaveGroup() {
eventHub.$emit(`${this.action}showLeaveGroupModal`, [this.group, this.parentGroup]);
eventHub.$emit(`${this.action}showLeaveGroupModal`, this.group, this.parentGroup);
},
},
};
......
import mitt from 'mitt';
import Vue from 'vue';
/**
* Return a Vue like event hub
*
* - $on
* - $off
* - $once
* - $emit
*
* Please note, this was once implemented with `mitt`, but since then has been reverted
* because of some API issues. https://gitlab.com/gitlab-org/gitlab/-/merge_requests/35074
*
* We'd like to shy away from using a full fledged Vue instance from this in the future.
*/
export default () => {
const emitter = mitt();
const originalEmit = emitter.emit;
emitter.once = (event, handler) => {
const wrappedHandler = evt => {
handler(evt);
emitter.off(event, wrappedHandler);
};
emitter.on(event, wrappedHandler);
};
emitter.emit = (event, args = []) => {
originalEmit(event, args);
};
emitter.$on = emitter.on;
emitter.$once = emitter.once;
emitter.$off = emitter.off;
emitter.$emit = emitter.emit;
return emitter;
return new Vue();
};
import createEventHub from '~/helpers/event_hub_factory';
import Vue from 'vue';
const eventHub = createEventHub();
const eventHub = new Vue();
// TODO: remove eventHub hack after code splitting refactor
window.emitSidebarEvent = (...args) => eventHub.$emit(...args);
......
......@@ -946,7 +946,8 @@ class MergeRequest < ApplicationRecord
end
def can_remove_source_branch?(current_user)
!ProtectedBranch.protected?(source_project, source_branch) &&
source_project &&
!ProtectedBranch.protected?(source_project, source_branch) &&
!source_project.root_ref?(source_branch) &&
Ability.allowed?(current_user, :push_code, source_project) &&
diff_head_sha == source_branch_head.try(:sha)
......
---
# Suggestion: gitlab.CurrentStatus
# Checks for words that indicate a product or feature may change in the future.
#
# For a list of all options, see https://errata-ai.github.io/vale/styles/
extends: existence
message: 'Avoid words like "%s" that promise future changes.'
level: suggestion
ignorecase: true
link: https://docs.gitlab.com/ee/development/documentation/styleguide.html#language-to-avoid
tokens:
- currently
......@@ -335,8 +335,6 @@ Puma
Python
Qualys
Rackspace
Raketask
Raketasks
reachability
rebase
rebased
......
......@@ -402,6 +402,17 @@ git_data_dirs({
})
```
You should use configuration similar to the following:
```ruby
git_data_dirs({
'default' => { 'gitaly_address' => 'tcp://gitaly1.internal:8075' },
# this should be the IP address of the GitLab server that has Gitaly running on it
'storage1' => { 'gitaly_address' => 'tcp://gitlab.internal:8075' },
'storage2' => { 'gitaly_address' => 'tcp://gitaly2.internal:8075' },
})
```
**For Omnibus GitLab**
1. Edit `/etc/gitlab/gitlab.rb`:
......
......@@ -287,7 +287,7 @@ SAST can be [configured](#customizing-the-sast-settings) using environment varia
#### Logging Level
You can control the verbosity of logs by setting the `SECURE_LOG_LEVEL` env var. It's default is set to `info`, you can set it to any of the following levels:
You can control the verbosity of logs by setting the `SECURE_LOG_LEVEL` env var. The default is set to `info`, you can set it to any of the following levels:
- `panic`
- `fatal`
......
......@@ -148,7 +148,7 @@ Secret Detection can be customized by defining available variables:
### Logging Level
You can control the verbosity of logs by setting the `SECURE_LOG_LEVEL` env var. It's default is set to `info`, you can set it to any of the following levels:
You can control the verbosity of logs by setting the `SECURE_LOG_LEVEL` env var. The default is set to `info`, you can set it to any of the following levels:
- `panic`
- `fatal`
......
......@@ -261,14 +261,52 @@ When [renaming a user](../profile/index.md#changing-your-username),
## Use your project as a Go package
Any project can be used as a Go package including private projects in subgroups.
GitLab responds correctly to `go get` and `godoc.org` discovery requests,
including the [`go-import`](https://golang.org/cmd/go/#hdr-Remote_import_paths)
and [`go-source`](https://github.com/golang/gddo/wiki/Source-Code-Links) meta
tags, respectively. To use packages hosted in private projects with the `go get`
command, use a [`.netrc` file](https://ec.haxx.se/usingcurl-netrc.html) and a
[personal access token](../profile/personal_access_tokens.md) in the password
field.
Any project can be used as a Go package. GitLab responds correctly to `go get`
and `godoc.org` discovery requests, including the
[`go-import`](https://golang.org/cmd/go/#hdr-Remote_import_paths) and
[`go-source`](https://github.com/golang/gddo/wiki/Source-Code-Links) meta tags.
Private projects, including projects in subgroups, can be used as a Go package,
but may require configuration to work correctly. GitLab will respond correctly
to `go get` discovery requests for projects that *are not* in subgroups,
regardless of authentication or authorization.
[Authentication](#authenticate-go-requests) is required to use a private project
in a subgroup as a Go package. Otherwise, GitLab will truncate the path for
private projects in subgroups to the first two segments, causing `go get` to
fail.
GitLab implements its own Go proxy. This feature must be enabled by an
administrator and requires additional configuration. See [GitLab Go
Proxy](../packages/go_proxy/index.md).
### Disable Go module features for private projects
In Go 1.12 and later, Go queries module proxies and checksum databases in the
process of [fetching a
module](../../development/go_guide/dependencies.md#fetching). This can be
selectively disabled with `GOPRIVATE` (disable both),
[`GONOPROXY`](../../development/go_guide/dependencies.md#proxies) (disable proxy
queries), and [`GONOSUMDB`](../../development/go_guide/dependencies.md#fetching)
(disable checksum queries).
`GOPRIVATE`, `GONOPROXY`, and `GONOSUMDB` are comma-separated lists of Go
modules and Go module prefixes. For example,
`GOPRIVATE=gitlab.example.com/my/private/project` will disable queries for that
one project, but `GOPRIVATE=gitlab.example.com` will disable queries for *all*
projects on GitLab.com. Go will not query module proxies if the module name or a
prefix of it appears in `GOPRIVATE` or `GONOPROXY`. Go will not query checksum
databases if the module name or a prefix of it appears in `GONOPRIVATE` or
`GONOSUMDB`.
### Authenticate Go requests
To authenticate requests to private projects made by Go, use a [`.netrc`
file](https://ec.haxx.se/usingcurl-netrc.html) and a [personal access
token](../profile/personal_access_tokens.md) in the password field. **This only
works if your GitLab instance can be accessed with HTTPS.** The `go` command
will not transmit credentials over insecure connections. This will authenticate
all HTTPS requests made directly by Go but will not authenticate requests made
through Git.
For example:
......@@ -278,6 +316,24 @@ login <gitlab_user_name>
password <personal_access_token>
```
NOTE: **Note:**
On Windows, Go reads `~/_netrc` instead of `~/.netrc`.
### Authenticate Git fetches
If a module cannot be fetched from a proxy, Go will fall back to using Git (for
GitLab projects). Git will use `.netrc` to authenticate requests. Alternatively,
Git can be configured to embed specific credentials in the request URL, or to
use SSH instead of HTTPS (as Go always uses HTTPS to fetch Git repositories):
```shell
# embed credentials in any request to GitLab.com:
git config --global url."https://${user}:${personal_access_token}@gitlab.example.com".insteadOf "https://gitlab.example.com"
# use SSH instead of HTTPS:
git config --global url."git@gitlab.example.com".insteadOf "https://gitlab.example.com"
```
## Access project page with project ID
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/53671) in GitLab 11.8.
......
......@@ -7310,6 +7310,9 @@ msgstr ""
msgid "Delete this attachment"
msgstr ""
msgid "Delete user list"
msgstr ""
msgid "Delete variable"
msgstr ""
......@@ -24761,6 +24764,9 @@ msgstr ""
msgid "User key was successfully removed."
msgstr ""
msgid "User list %{name} will be removed. Are you sure?"
msgstr ""
msgid "User map"
msgstr ""
......@@ -24782,6 +24788,12 @@ msgstr ""
msgid "User was successfully updated."
msgstr ""
msgid "UserList|Delete %{name}?"
msgstr ""
msgid "UserList|created %{timeago}"
msgstr ""
msgid "UserOnboardingTour|%{activeTour}/%{totalTours}"
msgstr ""
......@@ -26944,9 +26956,6 @@ msgstr ""
msgid "created %{timeAgo}"
msgstr ""
msgid "created %{timeago}"
msgstr ""
msgid "customize"
msgstr ""
......
# frozen_string_literal: true
module QA
context 'Release', :docker, quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/217250', type: :investigating } do
context 'Release', :docker do
describe 'Parent-child pipelines dependent relationship' do
let!(:project) do
Resource::Project.fabricate_via_api! do |project|
......
# frozen_string_literal: true
module QA
context 'Release', :docker, quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/217250', type: :investigating } do
context 'Release', :docker do
describe 'Parent-child pipelines independent relationship' do
let!(:project) do
Resource::Project.fabricate_via_api! do |project|
......
......@@ -196,7 +196,7 @@ describe('Board card', () => {
wrapper.trigger('mousedown');
wrapper.trigger('mouseup');
expect(eventHub.$emit).toHaveBeenCalledWith('newDetailIssue', [wrapper.vm.issue, undefined]);
expect(eventHub.$emit).toHaveBeenCalledWith('newDetailIssue', wrapper.vm.issue, undefined);
expect(boardsStore.detail.list).toEqual(wrapper.vm.list);
});
......
......@@ -32,7 +32,7 @@ describe('Deploy keys action btn', () => {
wrapper.trigger('click');
return wrapper.vm.$nextTick().then(() => {
expect(eventHub.$emit).toHaveBeenCalledWith('enable.key', [deployKey, expect.any(Function)]);
expect(eventHub.$emit).toHaveBeenCalledWith('enable.key', deployKey, expect.anything());
});
});
......
......@@ -88,7 +88,7 @@ describe('Deploy keys app component', () => {
jest.spyOn(wrapper.vm.service, 'getKeys').mockImplementation(() => {});
jest.spyOn(wrapper.vm.service, 'enableKey').mockImplementation(() => Promise.resolve());
eventHub.$emit('enable.key', [key]);
eventHub.$emit('enable.key', key);
return wrapper.vm.$nextTick();
})
......@@ -106,7 +106,7 @@ describe('Deploy keys app component', () => {
jest.spyOn(wrapper.vm.service, 'getKeys').mockImplementation(() => {});
jest.spyOn(wrapper.vm.service, 'disableKey').mockImplementation(() => Promise.resolve());
eventHub.$emit('disable.key', [key]);
eventHub.$emit('disable.key', key);
return wrapper.vm.$nextTick();
})
......@@ -124,7 +124,7 @@ describe('Deploy keys app component', () => {
jest.spyOn(wrapper.vm.service, 'getKeys').mockImplementation(() => {});
jest.spyOn(wrapper.vm.service, 'disableKey').mockImplementation(() => Promise.resolve());
eventHub.$emit('remove.key', [key]);
eventHub.$emit('remove.key', key);
return wrapper.vm.$nextTick();
})
......
......@@ -184,7 +184,7 @@ describe('AppComponent', () => {
jest.spyOn(window.history, 'replaceState').mockImplementation(() => {});
jest.spyOn($, 'scrollTo').mockImplementation(() => {});
const fetchPagePromise = vm.fetchPage([2, null, null, true]);
const fetchPagePromise = vm.fetchPage(2, null, null, true);
expect(vm.isLoading).toBe(true);
expect(vm.fetchGroups).toHaveBeenCalledWith({
......@@ -275,7 +275,7 @@ describe('AppComponent', () => {
expect(vm.targetGroup).toBe(null);
expect(vm.targetParentGroup).toBe(null);
vm.showLeaveGroupModal([group, mockParentGroupItem]);
vm.showLeaveGroupModal(group, mockParentGroupItem);
expect(vm.targetGroup).not.toBe(null);
expect(vm.targetParentGroup).not.toBe(null);
......@@ -286,7 +286,7 @@ describe('AppComponent', () => {
expect(vm.showModal).toBe(false);
expect(vm.groupLeaveConfirmationMessage).toBe('');
vm.showLeaveGroupModal([group, mockParentGroupItem]);
vm.showLeaveGroupModal(group, mockParentGroupItem);
expect(vm.showModal).toBe(true);
expect(vm.groupLeaveConfirmationMessage).toBe(
......@@ -298,7 +298,7 @@ describe('AppComponent', () => {
describe('hideLeaveGroupModal', () => {
it('hides modal confirmation which is shown before leaving the group', () => {
const group = { ...mockParentGroupItem };
vm.showLeaveGroupModal([group, mockParentGroupItem]);
vm.showLeaveGroupModal(group, mockParentGroupItem);
expect(vm.showModal).toBe(true);
vm.hideLeaveGroupModal();
......
......@@ -41,12 +41,13 @@ describe('GroupsComponent', () => {
vm.change(2);
expect(eventHub.$emit).toHaveBeenCalledWith('fetchPage', [
expect(eventHub.$emit).toHaveBeenCalledWith(
'fetchPage',
2,
expect.any(Object),
expect.any(Object),
expect.any(Object),
]);
);
});
});
});
......
......@@ -31,10 +31,11 @@ describe('ItemActionsComponent', () => {
jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
vm.onLeaveGroup();
expect(eventHub.$emit).toHaveBeenCalledWith('showLeaveGroupModal', [
expect(eventHub.$emit).toHaveBeenCalledWith(
'showLeaveGroupModal',
vm.group,
vm.parentGroup,
]);
);
});
});
});
......
import createEventHub from '~/helpers/event_hub_factory';
const TEST_EVENT = 'foobar';
describe('event bus factory', () => {
let eventBus;
let handler;
beforeEach(() => {
eventBus = createEventHub();
handler = jest.fn();
});
afterEach(() => {
eventBus = null;
});
describe('underlying module', () => {
let mitt;
describe('instance', () => {
it.each`
method
${'$on'}
${'$once'}
${'$off'}
${'$emit'}
`('has $method method', ({ method }) => {
expect(eventBus[method]).toEqual(expect.any(Function));
});
});
describe('$on', () => {
beforeEach(() => {
jest.resetModules();
jest.mock('mitt');
eventBus.$on(TEST_EVENT, handler);
});
// eslint-disable-next-line global-require
mitt = require('mitt');
mitt.mockReturnValue(() => ({}));
it('calls handler when event is emitted', () => {
eventBus.$emit(TEST_EVENT);
expect(handler).toHaveBeenCalledWith();
});
const createEventHubActual = jest.requireActual('~/helpers/event_hub_factory').default;
eventBus = createEventHubActual();
it('calls handler with multiple args', () => {
eventBus.$emit(TEST_EVENT, 'arg1', 'arg2', 'arg3');
expect(handler).toHaveBeenCalledWith('arg1', 'arg2', 'arg3');
});
it('creates an emitter', () => {
expect(mitt).toHaveBeenCalled();
it('calls handler multiple times', () => {
eventBus.$emit(TEST_EVENT, 'arg1', 'arg2', 'arg3');
eventBus.$emit(TEST_EVENT, 'arg1', 'arg2', 'arg3');
expect(handler).toHaveBeenCalledTimes(2);
});
});
describe('instance', () => {
it.each`
method
${'on'}
${'once'}
${'off'}
${'emit'}
`('binds $$method to $method ', ({ method }) => {
expect(typeof eventBus[method]).toBe('function');
expect(eventBus[method]).toBe(eventBus[`$${method}`]);
it('does not call handler after $off with handler', () => {
eventBus.$off(TEST_EVENT, handler);
eventBus.$emit(TEST_EVENT);
expect(handler).not.toHaveBeenCalled();
});
});
describe('once', () => {
const event = 'foobar';
let handler;
it('does not call handler after $off', () => {
eventBus.$off(TEST_EVENT);
beforeEach(() => {
jest.spyOn(eventBus, 'on');
jest.spyOn(eventBus, 'off');
handler = jest.fn();
eventBus.once(event, handler);
eventBus.$emit(TEST_EVENT);
expect(handler).not.toHaveBeenCalled();
});
});
it('calls on internally', () => {
expect(eventBus.on).toHaveBeenCalled();
describe('$once', () => {
beforeEach(() => {
eventBus.$once(TEST_EVENT, handler);
});
it('calls handler when event is emitted', () => {
eventBus.emit(event);
eventBus.$emit(TEST_EVENT);
expect(handler).toHaveBeenCalled();
});
it('calls off when event is emitted', () => {
eventBus.emit(event);
expect(eventBus.off).toHaveBeenCalled();
});
it('calls the handler only once when event is emitted multiple times', () => {
eventBus.emit(event);
eventBus.emit(event);
eventBus.$emit(TEST_EVENT);
eventBus.$emit(TEST_EVENT);
expect(handler).toHaveBeenCalledTimes(1);
});
......@@ -80,14 +87,18 @@ describe('event bus factory', () => {
handler = jest.fn().mockImplementation(() => {
throw new Error();
});
eventBus.once(event, handler);
eventBus.$once(TEST_EVENT, handler);
});
it('calls off when event is emitted', () => {
expect(() => {
eventBus.emit(event);
eventBus.$emit(TEST_EVENT);
}).toThrow();
expect(eventBus.off).toHaveBeenCalled();
expect(() => {
eventBus.$emit(TEST_EVENT);
}).not.toThrow();
expect(handler).toHaveBeenCalledTimes(1);
});
});
});
......
......@@ -78,8 +78,8 @@ describe UpdateIndexApprovalRuleNameForCodeOwnersRuleType do
disable_migrations_output { migrate! }
# After running the migration, expect `section == nil` rules to still
# be blocked by the legacy indices, but sectional rules are allowed.
# After running the migration, expect `section == nil` rules to still be
# blocked by the legacy indices, but sectional rules are allowed.
#
expect { create_sectional_approval_rules }
.to change { approval_rules.count }.by(2)
......@@ -115,8 +115,8 @@ describe UpdateIndexApprovalRuleNameForCodeOwnersRuleType do
described_class::LEGACY_INDEX_NAME_CODE_OWNERS
)
# Since ApprovalMergeRequestRules are EE-specific, we expect none to
# be deleted during the migration.
# Since ApprovalMergeRequestRules are EE-specific, we expect none to be
# deleted during the migration.
#
expect { disable_migrations_output { migration.down } }
.not_to change { approval_rules.count }
......@@ -144,17 +144,14 @@ describe UpdateIndexApprovalRuleNameForCodeOwnersRuleType do
expect { create_two_matching_nil_section_approval_rules }
.to raise_exception(ActiveRecord::RecordNotUnique)
# Run the down migration. This will remove the 2 approval rules we create
# above, and call MergeRequests::SyncCodeOwnerApprovalRules to recreate
# new ones.
#
expect(MergeRequests::SyncCodeOwnerApprovalRules)
.to receive(:new).with(MergeRequest.find(merge_request.id)).once.and_call_original
# We expect approval_rules.count to be changed by -3 as we're deleting the
# 3 rules created above, and MergeRequests::SyncCodeOwnerApprovalRules
# will not be able to create new one with an empty (or missing)
# CODEOWNERS file.
# Run the down migration. This will remove the 3 approval rules we create
# above, and call MergeRequests::SyncCodeOwnerApprovalRules to recreate
# new ones. However, as there is no CODEOWNERS file in this test
# context, no approval rules will be created, so we can expect
# approval_rules.count to be changed by -3.
#
expect { disable_migrations_output { migration.down } }
.to change { approval_rules.count }.by(-3)
......
......@@ -1170,6 +1170,12 @@ describe MergeRequest do
expect(subject.can_remove_source_branch?(user)).to be_falsey
end
it "can't be removed because source project has been deleted" do
subject.source_project = nil
expect(subject.can_remove_source_branch?(user)).to be_falsey
end
it "can't remove a root ref" do
subject.update(source_branch: 'master', target_branch: 'feature')
......
......@@ -8232,11 +8232,6 @@ mississippi@^3.0.0:
stream-each "^1.1.0"
through2 "^2.0.0"
mitt@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/mitt/-/mitt-1.2.0.tgz#cb24e6569c806e31bd4e3995787fe38a04fdf90d"
integrity sha512-r6lj77KlwqLhIUku9UWYes7KJtsczvolZkzp8hbaDPPaE24OmWl5s539Mytlj22siEQKosZ26qCBgda2PKwoJw==
mixin-deep@^1.2.0:
version "1.3.2"
resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566"
......@@ -9763,16 +9758,11 @@ rc@^1.2.8, rc@~1.2.7:
minimist "^1.2.0"
strip-json-comments "~2.0.1"
react-is@^16.12.0:
react-is@^16.12.0, react-is@^16.8.4:
version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
react-is@^16.8.4:
version "16.8.6"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.6.tgz#5bbc1e2d29141c9fbdfed456343fe2bc430a6a16"
integrity sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA==
read-pkg-up@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02"
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册