From 94221585cabf666f38ac989978838393fc3bf56e Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Tue, 23 Jun 2020 00:08:58 +0000 Subject: [PATCH] Add latest changes from gitlab-org/gitlab@master --- .../boards/components/board_card.vue | 4 +- app/assets/javascripts/boards/index.js | 2 +- .../deploy_keys/components/action_btn.vue | 9 +- .../deploy_keys/components/app.vue | 4 +- .../javascripts/groups/components/app.vue | 4 +- .../javascripts/groups/components/groups.vue | 7 +- .../groups/components/item_actions.vue | 2 +- .../javascripts/helpers/event_hub_factory.js | 38 +++---- app/assets/javascripts/sidebar/event_hub.js | 4 +- app/models/merge_request.rb | 3 +- doc/.vale/gitlab/CurrentStatus.yml | 12 +++ doc/.vale/gitlab/spelling-exceptions.txt | 2 - doc/administration/gitaly/index.md | 11 +++ doc/user/application_security/sast/index.md | 2 +- .../secret_detection/index.md | 2 +- doc/user/project/index.md | 72 ++++++++++++-- locale/gitlab.pot | 15 ++- package.json | 1 - ...d_pipelines_dependent_relationship_spec.rb | 2 +- ...pipelines_independent_relationship_spec.rb | 2 +- spec/frontend/boards/board_card_spec.js | 2 +- .../deploy_keys/components/action_btn_spec.js | 2 +- .../deploy_keys/components/app_spec.js | 6 +- spec/frontend/groups/components/app_spec.js | 8 +- .../frontend/groups/components/groups_spec.js | 5 +- .../groups/components/item_actions_spec.js | 5 +- .../helpers/event_hub_factory_spec.js | 99 ++++++++++--------- ...ule_name_for_code_owners_rule_type_spec.rb | 21 ++-- spec/models/merge_request_spec.rb | 6 ++ yarn.lock | 12 +-- 30 files changed, 220 insertions(+), 144 deletions(-) create mode 100644 doc/.vale/gitlab/CurrentStatus.yml diff --git a/app/assets/javascripts/boards/components/board_card.vue b/app/assets/javascripts/boards/components/board_card.vue index e120e058ede..246d3b9dcd1 100644 --- a/app/assets/javascripts/boards/components/board_card.vue +++ b/app/assets/javascripts/boards/components/board_card.vue @@ -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); } } diff --git a/app/assets/javascripts/boards/index.js b/app/assets/javascripts/boards/index.js index 01e01ad6b8e..a882cd1cdfa 100644 --- a/app/assets/javascripts/boards/index.js +++ b/app/assets/javascripts/boards/index.js @@ -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); diff --git a/app/assets/javascripts/deploy_keys/components/action_btn.vue b/app/assets/javascripts/deploy_keys/components/action_btn.vue index c2c90bd472b..af7c391ab70 100644 --- a/app/assets/javascripts/deploy_keys/components/action_btn.vue +++ b/app/assets/javascripts/deploy_keys/components/action_btn.vue @@ -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; + }); }, }, }; diff --git a/app/assets/javascripts/deploy_keys/components/app.vue b/app/assets/javascripts/deploy_keys/components/app.vue index c747b63473a..83d2ffe2b3e 100644 --- a/app/assets/javascripts/deploy_keys/components/app.vue +++ b/app/assets/javascripts/deploy_keys/components/app.vue @@ -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?')) diff --git a/app/assets/javascripts/groups/components/app.vue b/app/assets/javascripts/groups/components/app.vue index 0f2ee4a5224..0b401f4d732 100644 --- a/app/assets/javascripts/groups/components/app.vue +++ b/app/assets/javascripts/groups/components/app.vue @@ -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; diff --git a/app/assets/javascripts/groups/components/groups.vue b/app/assets/javascripts/groups/components/groups.vue index daf145d4eca..c7acc21378b 100644 --- a/app/assets/javascripts/groups/components/groups.vue +++ b/app/assets/javascripts/groups/components/groups.vue @@ -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); }, }, }; diff --git a/app/assets/javascripts/groups/components/item_actions.vue b/app/assets/javascripts/groups/components/item_actions.vue index c91551da475..985ea5a9019 100644 --- a/app/assets/javascripts/groups/components/item_actions.vue +++ b/app/assets/javascripts/groups/components/item_actions.vue @@ -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); }, }, }; diff --git a/app/assets/javascripts/helpers/event_hub_factory.js b/app/assets/javascripts/helpers/event_hub_factory.js index 08cfe40b52d..863f490a63e 100644 --- a/app/assets/javascripts/helpers/event_hub_factory.js +++ b/app/assets/javascripts/helpers/event_hub_factory.js @@ -1,26 +1,18 @@ -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(); }; diff --git a/app/assets/javascripts/sidebar/event_hub.js b/app/assets/javascripts/sidebar/event_hub.js index dd4bd9a5ab7..f35506fd5de 100644 --- a/app/assets/javascripts/sidebar/event_hub.js +++ b/app/assets/javascripts/sidebar/event_hub.js @@ -1,6 +1,6 @@ -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); diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index adf4c0ffa15..68ff336a1bb 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -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) diff --git a/doc/.vale/gitlab/CurrentStatus.yml b/doc/.vale/gitlab/CurrentStatus.yml new file mode 100644 index 00000000000..52bcea23d5b --- /dev/null +++ b/doc/.vale/gitlab/CurrentStatus.yml @@ -0,0 +1,12 @@ +--- +# 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 diff --git a/doc/.vale/gitlab/spelling-exceptions.txt b/doc/.vale/gitlab/spelling-exceptions.txt index edc9059d1ac..7fe7fb2d6da 100644 --- a/doc/.vale/gitlab/spelling-exceptions.txt +++ b/doc/.vale/gitlab/spelling-exceptions.txt @@ -335,8 +335,6 @@ Puma Python Qualys Rackspace -Raketask -Raketasks reachability rebase rebased diff --git a/doc/administration/gitaly/index.md b/doc/administration/gitaly/index.md index 9522eaea88c..0439adccfe4 100644 --- a/doc/administration/gitaly/index.md +++ b/doc/administration/gitaly/index.md @@ -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`: diff --git a/doc/user/application_security/sast/index.md b/doc/user/application_security/sast/index.md index 90cb3594d23..b70272515a7 100644 --- a/doc/user/application_security/sast/index.md +++ b/doc/user/application_security/sast/index.md @@ -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` diff --git a/doc/user/application_security/secret_detection/index.md b/doc/user/application_security/secret_detection/index.md index e0cbaeda24c..c47d4ae9996 100644 --- a/doc/user/application_security/secret_detection/index.md +++ b/doc/user/application_security/secret_detection/index.md @@ -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` diff --git a/doc/user/project/index.md b/doc/user/project/index.md index 9f7fde4cf5d..a3d63c0e77d 100644 --- a/doc/user/project/index.md +++ b/doc/user/project/index.md @@ -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 password ``` +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. diff --git a/locale/gitlab.pot b/locale/gitlab.pot index ea1a38bb4e8..5d001f3c0e4 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -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 "" diff --git a/package.json b/package.json index aff2d285fb3..2abe1e69f84 100644 --- a/package.json +++ b/package.json @@ -105,7 +105,6 @@ "mermaid": "^8.5.2", "mersenne-twister": "1.1.0", "minimatch": "^3.0.4", - "mitt": "^1.2.0", "monaco-editor": "^0.18.1", "monaco-editor-webpack-plugin": "^1.7.0", "mousetrap": "^1.4.6", diff --git a/qa/qa/specs/features/browser_ui/6_release/pipeline/parent_child_pipelines_dependent_relationship_spec.rb b/qa/qa/specs/features/browser_ui/6_release/pipeline/parent_child_pipelines_dependent_relationship_spec.rb index 30163aacfaa..d2020ff6ec7 100644 --- a/qa/qa/specs/features/browser_ui/6_release/pipeline/parent_child_pipelines_dependent_relationship_spec.rb +++ b/qa/qa/specs/features/browser_ui/6_release/pipeline/parent_child_pipelines_dependent_relationship_spec.rb @@ -1,7 +1,7 @@ # 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| diff --git a/qa/qa/specs/features/browser_ui/6_release/pipeline/parent_child_pipelines_independent_relationship_spec.rb b/qa/qa/specs/features/browser_ui/6_release/pipeline/parent_child_pipelines_independent_relationship_spec.rb index 16272767f9f..9d9b187e77a 100644 --- a/qa/qa/specs/features/browser_ui/6_release/pipeline/parent_child_pipelines_independent_relationship_spec.rb +++ b/qa/qa/specs/features/browser_ui/6_release/pipeline/parent_child_pipelines_independent_relationship_spec.rb @@ -1,7 +1,7 @@ # 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| diff --git a/spec/frontend/boards/board_card_spec.js b/spec/frontend/boards/board_card_spec.js index 6bfbc7cb12f..959c71d05ca 100644 --- a/spec/frontend/boards/board_card_spec.js +++ b/spec/frontend/boards/board_card_spec.js @@ -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); }); diff --git a/spec/frontend/deploy_keys/components/action_btn_spec.js b/spec/frontend/deploy_keys/components/action_btn_spec.js index 78312751429..b8211b02464 100644 --- a/spec/frontend/deploy_keys/components/action_btn_spec.js +++ b/spec/frontend/deploy_keys/components/action_btn_spec.js @@ -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()); }); }); diff --git a/spec/frontend/deploy_keys/components/app_spec.js b/spec/frontend/deploy_keys/components/app_spec.js index cf54b7e60aa..291502c9ed7 100644 --- a/spec/frontend/deploy_keys/components/app_spec.js +++ b/spec/frontend/deploy_keys/components/app_spec.js @@ -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(); }) diff --git a/spec/frontend/groups/components/app_spec.js b/spec/frontend/groups/components/app_spec.js index 3c04cac7402..35eda21e047 100644 --- a/spec/frontend/groups/components/app_spec.js +++ b/spec/frontend/groups/components/app_spec.js @@ -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(); diff --git a/spec/frontend/groups/components/groups_spec.js b/spec/frontend/groups/components/groups_spec.js index 42c3c813941..6205400eb03 100644 --- a/spec/frontend/groups/components/groups_spec.js +++ b/spec/frontend/groups/components/groups_spec.js @@ -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), - ]); + ); }); }); }); diff --git a/spec/frontend/groups/components/item_actions_spec.js b/spec/frontend/groups/components/item_actions_spec.js index 1ca42f28c7f..c0dc1a816e6 100644 --- a/spec/frontend/groups/components/item_actions_spec.js +++ b/spec/frontend/groups/components/item_actions_spec.js @@ -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, - ]); + ); }); }); }); diff --git a/spec/frontend/helpers/event_hub_factory_spec.js b/spec/frontend/helpers/event_hub_factory_spec.js index dcfec6b836a..d29b9ddba34 100644 --- a/spec/frontend/helpers/event_hub_factory_spec.js +++ b/spec/frontend/helpers/event_hub_factory_spec.js @@ -1,77 +1,84 @@ 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); }); }); }); diff --git a/spec/migrations/20200526231421_update_index_approval_rule_name_for_code_owners_rule_type_spec.rb b/spec/migrations/20200526231421_update_index_approval_rule_name_for_code_owners_rule_type_spec.rb index 9842cfbc28d..387c477a58e 100644 --- a/spec/migrations/20200526231421_update_index_approval_rule_name_for_code_owners_rule_type_spec.rb +++ b/spec/migrations/20200526231421_update_index_approval_rule_name_for_code_owners_rule_type_spec.rb @@ -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) diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index c70ddac5da6..031b0688c7b 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -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') diff --git a/yarn.lock b/yarn.lock index a2d0656233f..6dc60a5a81f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -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" -- GitLab