Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2021-02-03 00:09:41 +00:00
parent 36e4abb3dd
commit a020b8c048
46 changed files with 425 additions and 42 deletions

View File

@ -3,6 +3,7 @@ import { Sortable, MultiDrag } from 'sortablejs';
import { GlLoadingIcon } from '@gitlab/ui';
import { sprintf, __ } from '~/locale';
import { deprecatedCreateFlash as createFlash } from '~/flash';
import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants';
import eventHub from '../eventhub';
import boardsStore from '../stores/boards_store';
import {
@ -167,7 +168,7 @@ export default {
boardsStore.startMoving(list, issue);
this.$root.$emit('bv::hide::tooltip');
this.$root.$emit(BV_HIDE_TOOLTIP);
sortableStart();
},

View File

@ -13,6 +13,7 @@ import { n__, s__, __ } from '~/locale';
import sidebarEventHub from '~/sidebar/event_hub';
import { isScopedLabel } from '~/lib/utils/common_utils';
import { isListDraggable } from '~/boards/boards_util';
import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants';
import { inactiveId, LIST, ListType } from '../constants';
import eventHub from '../eventhub';
import AccessorUtilities from '../../lib/utils/accessor';
@ -158,7 +159,7 @@ export default {
// When expanding/collapsing, the tooltip on the caret button sometimes stays open.
// Close all tooltips manually to prevent dangling tooltips.
this.$root.$emit('bv::hide::tooltip');
this.$root.$emit(BV_HIDE_TOOLTIP);
},
addToLocalStorage() {
if (AccessorUtilities.isLocalStorageAccessSafe()) {

View File

@ -17,6 +17,7 @@ import boardsStore from '../stores/boards_store';
import eventHub from '../eventhub';
import { inactiveId, LIST, ListType } from '../constants';
import IssueCount from './issue_count.vue';
import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants';
// This component is being replaced in favor of './board_list_header.vue' for GraphQL boards
@ -142,7 +143,7 @@ export default {
// When expanding/collapsing, the tooltip on the caret button sometimes stays open.
// Close all tooltips manually to prevent dangling tooltips.
this.$root.$emit('bv::hide::tooltip');
this.$root.$emit(BV_HIDE_TOOLTIP);
},
addToLocalStorage() {
if (AccessorUtilities.isLocalStorageAccessSafe()) {

View File

@ -10,6 +10,7 @@ import {
} from '@gitlab/ui';
import BoardEditableItem from '~/boards/components/sidebar/board_editable_item.vue';
import createFlash from '~/flash';
import { BV_DROPDOWN_HIDE } from '~/lib/utils/constants';
import { __, s__ } from '~/locale';
import projectMilestones from '../../graphql/project_milestones.query.graphql';
@ -73,7 +74,7 @@ export default {
},
},
mounted() {
this.$root.$on('bv::dropdown::hide', () => {
this.$root.$on(BV_DROPDOWN_HIDE, () => {
this.$refs.sidebarItem.collapse();
});
},

View File

@ -11,6 +11,7 @@ import {
CONFLICT_THEIR,
CONFLICT_MARKER,
} from '../constants';
import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants';
import DiffGutterAvatars from './diff_gutter_avatars.vue';
import * as utils from './diff_row_utils';
@ -162,7 +163,7 @@ export default {
this.$emit('enterdragging', { ...line, index });
},
onDragStart(line) {
this.$root.$emit('bv::hide::tooltip');
this.$root.$emit(BV_HIDE_TOOLTIP);
this.dragging = true;
this.$emit('startdragging', line);
},

View File

@ -6,6 +6,7 @@
import { GlTooltipDirective, GlButton, GlModalDirective } from '@gitlab/ui';
import { s__ } from '~/locale';
import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants';
import eventHub from '../event_hub';
export default {
@ -40,7 +41,7 @@ export default {
},
methods: {
onClick() {
this.$root.$emit('bv::hide::tooltip', this.$options.deleteEnvironmentTooltipId);
this.$root.$emit(BV_HIDE_TOOLTIP, this.$options.deleteEnvironmentTooltipId);
eventHub.$emit('requestDeleteEnvironment', this.environment);
},
onDeleteEnvironment(environment) {

View File

@ -6,6 +6,7 @@
import { GlTooltipDirective, GlButton, GlModalDirective } from '@gitlab/ui';
import { s__ } from '~/locale';
import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants';
import eventHub from '../event_hub';
export default {
@ -40,7 +41,7 @@ export default {
},
methods: {
onClick() {
this.$root.$emit('bv::hide::tooltip', this.$options.stopEnvironmentTooltipId);
this.$root.$emit(BV_HIDE_TOOLTIP, this.$options.stopEnvironmentTooltipId);
eventHub.$emit('requestStopEnvironment', this.environment);
},
onStopEnvironment(environment) {

View File

@ -1,6 +1,7 @@
<script>
import { mapActions, mapState } from 'vuex';
import { GlIcon, GlTooltipDirective } from '@gitlab/ui';
import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants';
import { leftSidebarViews } from '../constants';
export default {
@ -20,7 +21,7 @@ export default {
this.updateActivityBarView(view);
this.$root.$emit('bv::hide::tooltip');
this.$root.$emit(BV_HIDE_TOOLTIP);
},
},
leftSidebarViews,

View File

@ -1,5 +1,6 @@
<script>
import { GlTooltipDirective, GlIcon } from '@gitlab/ui';
import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants';
import { otherSide } from '../utils';
import { SIDE_RIGHT } from '../constants';
@ -50,7 +51,7 @@ export default {
},
clickTab(e, tab) {
e.currentTarget.blur();
this.$root.$emit('bv::hide::tooltip');
this.$root.$emit(BV_HIDE_TOOLTIP);
if (this.isActiveTab(tab)) {
this.$emit('close');

View File

@ -13,3 +13,6 @@ export const DATETIME_RANGE_TYPES = {
export const BV_SHOW_MODAL = 'bv::show::modal';
export const BV_HIDE_MODAL = 'bv::hide::modal';
export const BV_HIDE_TOOLTIP = 'bv::hide::tooltip';
export const BV_DROPDOWN_SHOW = 'bv::dropdown::show';
export const BV_DROPDOWN_HIDE = 'bv::dropdown::hide';

View File

@ -6,6 +6,7 @@ import resolvedStatusMixin from '~/batch_comments/mixins/resolved_status';
import eventHub from '~/sidebar/event_hub';
import Api from '~/api';
import { deprecatedCreateFlash as flash } from '~/flash';
import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants';
import { splitCamelCase } from '../../lib/utils/text_utility';
import ReplyButton from './note_actions/reply_button.vue';
@ -193,7 +194,7 @@ export default {
},
closeTooltip() {
this.$nextTick(() => {
this.$root.$emit('bv::hide::tooltip');
this.$root.$emit(BV_HIDE_TOOLTIP);
});
},
handleAssigneeUpdate(assignees) {

View File

@ -3,6 +3,7 @@ import { GlTooltipDirective, GlButton, GlLoadingIcon, GlIcon } from '@gitlab/ui'
import axios from '~/lib/utils/axios_utils';
import { dasherize } from '~/lib/utils/text_utility';
import { __ } from '~/locale';
import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants';
import { deprecatedCreateFlash as createFlash } from '~/flash';
import { reportToSentry } from './utils';
@ -62,7 +63,7 @@ export default {
*
*/
onClickAction() {
this.$root.$emit('bv::hide::tooltip', `js-ci-action-${this.link}`);
this.$root.$emit(BV_HIDE_TOOLTIP, `js-ci-action-${this.link}`);
this.isDisabled = true;
this.isLoading = true;

View File

@ -4,6 +4,7 @@ import { sprintf } from '~/locale';
import delayedJobMixin from '~/jobs/mixins/delayed_job_mixin';
import ActionComponent from './action_component.vue';
import JobNameComponent from './job_name_component.vue';
import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants';
import { accessValue } from './accessors';
import { REST } from './constants';
import { reportToSentry } from './utils';
@ -144,7 +145,7 @@ export default {
},
methods: {
hideTooltips() {
this.$root.$emit('bv::hide::tooltip');
this.$root.$emit(BV_HIDE_TOOLTIP);
},
pipelineActionRequestComplete() {
this.$emit('pipelineActionRequestComplete');

View File

@ -2,6 +2,7 @@
import { GlTooltipDirective, GlButton, GlLink, GlLoadingIcon, GlBadge } from '@gitlab/ui';
import CiStatus from '~/vue_shared/components/ci_icon.vue';
import { __, sprintf } from '~/locale';
import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants';
import { accessValue } from './accessors';
import { DOWNSTREAM, REST, UPSTREAM } from './constants';
import { reportToSentry } from './utils';
@ -126,7 +127,7 @@ export default {
this.$emit('pipelineExpandToggle', this.sourceJobName, !this.expanded);
},
hideTooltips() {
this.$root.$emit('bv::hide::tooltip');
this.$root.$emit(BV_HIDE_TOOLTIP);
},
onDownstreamHovered() {
this.$emit('downstreamHovered', this.sourceJobName);

View File

@ -2,6 +2,7 @@
import { GlButton, GlTooltipDirective } from '@gitlab/ui';
import Clipboard from 'clipboard';
import { uniqueId } from 'lodash';
import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants';
export default {
components: {
@ -76,7 +77,7 @@ export default {
});
this.clipboard
.on('success', (e) => {
this.$root.$emit('bv::hide::tooltip', this.id);
this.$root.$emit(BV_HIDE_TOOLTIP, this.id);
this.$emit('success', e);
// Clear the selection and blur the trigger so it loses its border
e.clearSelection();

View File

@ -43,6 +43,8 @@ class BulkImports::Entity < ApplicationRecord
validate :validate_parent_is_a_group, if: :parent
validate :validate_imported_entity_type
validate :validate_destination_namespace_ascendency, if: :group_entity?
enum source_type: { group_entity: 0, project_entity: 1 }
state_machine :status, initial: :created do
@ -107,4 +109,17 @@ class BulkImports::Entity < ApplicationRecord
)
end
end
def validate_destination_namespace_ascendency
source = Group.find_by_full_path(source_full_path)
return unless source
if source.self_and_descendants.any? { |namespace| namespace.full_path == destination_namespace }
errors.add(
:destination_namespace,
s_('BulkImport|destination group cannot be part of the source group tree')
)
end
end
end

View File

@ -0,0 +1,6 @@
---
title: Change projects.has_external_wiki column to be not null and default to false,
and cleanup all null and incorrect data
merge_request: 50916
author:
type: changed

View File

@ -0,0 +1,5 @@
---
title: Replace bootstrap event strings with constants
merge_request: 52777
author: Kev @KevSlashNull
type: other

View File

@ -0,0 +1,5 @@
---
title: 'BulkImports: avoid infinity recursion on group migration'
merge_request: 52931
author:
type: fixed

View File

@ -0,0 +1,5 @@
---
title: Add index to incident management oncall shifts table
merge_request: 52961
author:
type: performance

View File

@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40583
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/241711
milestone: '13.4'
type: development
group: group::analytics
group: group::optimize
default_enabled: true

View File

@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/34503
rollout_issue_url:
milestone: '13.4'
type: development
group: group::analytics
group: group::optimize
default_enabled: true

View File

@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/37300/
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38675
milestone: '13.3'
type: development
group: group::analytics
group: group::optimize
default_enabled: true

View File

@ -4,5 +4,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/33146
rollout_issue_url:
milestone: '13.2'
type: development
group: group::analytics
group: group::optimize
default_enabled: true

View File

@ -0,0 +1,19 @@
# frozen_string_literal: true
class AddDefaultProjectsHasExternalWiki < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def up
with_lock_retries do
change_column_default(:projects, :has_external_wiki, from: nil, to: false)
end
end
def down
with_lock_retries do
change_column_default(:projects, :has_external_wiki, from: false, to: nil)
end
end
end

View File

@ -0,0 +1,24 @@
# frozen_string_literal: true
class AddIndexToOncallShftsOnStartsAtAndEndsAt < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
NEW_NAME = 'index_oncall_shifts_on_rotation_id_and_starts_at_and_ends_at'
OLD_NAME = 'index_incident_management_oncall_shifts_on_rotation_id'
def up
add_concurrent_index :incident_management_oncall_shifts, %i[rotation_id starts_at ends_at], name: NEW_NAME
remove_concurrent_index_by_name :incident_management_oncall_shifts, OLD_NAME
end
def down
add_concurrent_index :incident_management_oncall_shifts, :rotation_id, name: OLD_NAME
remove_concurrent_index_by_name :incident_management_oncall_shifts, NEW_NAME
end
end

View File

@ -0,0 +1,16 @@
# frozen_string_literal: true
class AddNotNullConstraintToProjectsHasExternalWiki < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_not_null_constraint :projects, :has_external_wiki, validate: false
end
def down
remove_not_null_constraint :projects, :has_external_wiki
end
end

View File

@ -0,0 +1,89 @@
# frozen_string_literal: true
class CleanupProjectsWithNullHasExternalWiki < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
TMP_INDEX_NAME = 'tmp_index_projects_on_id_where_has_external_wiki_is_true_null'.freeze
BATCH_SIZE = 100
disable_ddl_transaction!
class Service < ActiveRecord::Base
include EachBatch
belongs_to :project
self.table_name = 'services'
self.inheritance_column = :_type_disabled
end
class Project < ActiveRecord::Base
include EachBatch
self.table_name = 'projects'
end
def up
update_projects_with_active_external_wikis
update_projects_without_active_external_wikis
end
def down
# no-op : can't go back to `NULL` without first dropping the `NOT NULL` constraint
end
private
def update_projects_with_active_external_wikis
# 11 projects are scoped in this query on GitLab.com.
scope = Service.where(active: true, type: 'ExternalWikiService').where.not(project_id: nil)
scope.each_batch(of: BATCH_SIZE) do |relation|
scope_with_projects = relation
.joins(:project)
.select('project_id')
.merge(Project.where(has_external_wiki: [false, nil]).where(pending_delete: false).where(archived: false))
execute(<<~SQL)
WITH project_ids_to_update (id) AS (
#{scope_with_projects.to_sql}
)
UPDATE projects SET has_external_wiki = true WHERE id IN (SELECT id FROM project_ids_to_update)
SQL
end
end
def update_projects_without_active_external_wikis
# Add a temporary index to speed up the scoping of projects.
index_where = <<~SQL
(
"projects"."has_external_wiki" = TRUE
OR "projects"."has_external_wiki" IS NULL
)
AND "projects"."pending_delete" = FALSE
AND "projects"."archived" = FALSE
SQL
add_concurrent_index(:projects, :id, where: index_where, name: TMP_INDEX_NAME)
services_sub_query = Service
.select('1')
.where('services.project_id = projects.id')
.where(type: 'ExternalWikiService')
.where(active: true)
# 322 projects are scoped in this query on GitLab.com.
Project.where(index_where).each_batch(of: BATCH_SIZE) do |relation|
relation_with_exists_query = relation.where('NOT EXISTS (?)', services_sub_query)
execute(<<~SQL)
WITH project_ids_to_update (id) AS (
#{relation_with_exists_query.select(:id).to_sql}
)
UPDATE projects SET has_external_wiki = false WHERE id IN (SELECT id FROM project_ids_to_update)
SQL
end
# Drop the temporary index.
remove_concurrent_index_by_name(:projects, TMP_INDEX_NAME)
end
end

View File

@ -0,0 +1 @@
047dd77352eda8134e55047e2d3fab07bbcd6eb41600cefb9b581d32e441fb68

View File

@ -0,0 +1 @@
339d828635107f77116ffd856abcb8f8f64985cabb82c0c34ab76056f5756d2e

View File

@ -0,0 +1 @@
30f3cbc0f96848f72a188616503eb80d38c33769c8bebf86a5922b374750d066

View File

@ -0,0 +1 @@
6cb54c71a9835ec1b3cf801a19c2cd385d224e0438c7924b6a29d298ecebe8a7

View File

@ -16129,7 +16129,7 @@ CREATE TABLE projects (
repository_storage character varying DEFAULT 'default'::character varying NOT NULL,
repository_read_only boolean,
request_access_enabled boolean DEFAULT true NOT NULL,
has_external_wiki boolean,
has_external_wiki boolean DEFAULT false,
ci_config_path character varying,
lfs_enabled boolean,
description_html text,
@ -19662,6 +19662,9 @@ ALTER TABLE ONLY chat_teams
ALTER TABLE vulnerability_scanners
ADD CONSTRAINT check_37608c9db5 CHECK ((char_length(vendor) <= 255)) NOT VALID;
ALTER TABLE projects
ADD CONSTRAINT check_421d399b70 CHECK ((has_external_wiki IS NOT NULL)) NOT VALID;
ALTER TABLE group_import_states
ADD CONSTRAINT check_cda75c7c3f CHECK ((user_id IS NOT NULL)) NOT VALID;
@ -22127,8 +22130,6 @@ CREATE INDEX index_incident_management_oncall_schedules_on_project_id ON inciden
CREATE INDEX index_incident_management_oncall_shifts_on_participant_id ON incident_management_oncall_shifts USING btree (participant_id);
CREATE INDEX index_incident_management_oncall_shifts_on_rotation_id ON incident_management_oncall_shifts USING btree (rotation_id);
CREATE UNIQUE INDEX index_index_statuses_on_project_id ON index_statuses USING btree (project_id);
CREATE INDEX index_insights_on_namespace_id ON insights USING btree (namespace_id);
@ -22575,6 +22576,8 @@ CREATE INDEX index_onboarding_progresses_for_verify_track ON onboarding_progress
CREATE UNIQUE INDEX index_onboarding_progresses_on_namespace_id ON onboarding_progresses USING btree (namespace_id);
CREATE INDEX index_oncall_shifts_on_rotation_id_and_starts_at_and_ends_at ON incident_management_oncall_shifts USING btree (rotation_id, starts_at, ends_at);
CREATE INDEX index_open_project_tracker_data_on_service_id ON open_project_tracker_data USING btree (service_id);
CREATE INDEX index_operations_feature_flags_issues_on_issue_id ON operations_feature_flags_issues USING btree (issue_id);

View File

@ -168,6 +168,16 @@ These groups are checked on each SAML login and user attributes updated as neces
This feature **does not** allow you to
automatically add users to GitLab [Groups](../user/group/index.md).
Support for these groups depends on your [subscription](https://about.gitlab.com/pricing/)
and whether you've installed [GitLab Enterprise Edition (EE)](https://about.gitlab.com/install/).
| Group | Tier | GitLab Enterprise Edition (EE) Only? |
|------------------------------|--------------------|--------------------------------------|
| [Required](#required-groups) | **(FREE SELF)** | Yes |
| [External](#external-groups) | **(FREE SELF)** | No |
| [Admin](#admin-groups) | **(FREE SELF)** | Yes |
| [Auditor](#auditor-groups) | **(PREMIUM SELF)** | Yes |
### Requirements
First you need to tell GitLab where to look for group information. For this you
@ -189,7 +199,7 @@ The name of the attribute can be anything you like, but it must contain the grou
to which a user belongs. In order to tell GitLab where to find these groups, you need
to add a `groups_attribute:` element to your SAML settings.
### Required groups **(PREMIUM SELF)**
### Required groups **(FREE SELF)**
Your IdP passes Group Information to the SP (GitLab) in the SAML Response. You need to configure GitLab to identify:
@ -215,7 +225,7 @@ Example:
} }
```
### External groups **(PREMIUM SELF)**
### External groups **(FREE SELF)**
SAML login supports automatic identification on whether a user should be considered an [external user](../user/permissions.md#external-users). This is based on the user's group membership in the SAML identity provider.
@ -233,7 +243,7 @@ SAML login supports automatic identification on whether a user should be conside
} }
```
### Admin groups **(PREMIUM SELF)**
### Admin groups **(FREE SELF)**
The requirements are the same as the previous settings, your IdP needs to pass Group information to GitLab, you need to tell
GitLab where to look for the groups in the SAML response, and which group(s) should be

View File

@ -89,12 +89,12 @@ The following options are available:
| Push rule | Description |
|---------------------------------|-------------|
| Removal of tags with `git push` | Forbid users to remove Git tags with `git push`. Tags can be deleted through the web UI. |
| Check whether author is a GitLab user | Restrict commits by author (email) to existing GitLab users. |
| Committer restriction **(PREMIUM)** | GitLab rejects any commit that was not committed by the current authenticated user. |
| Check whether the commit author is a GitLab user | Restrict commits to existing GitLab users (checked against their emails). |
| Reject unverified users **(PREMIUM)** | GitLab rejects any commit that was not committed by an authenticated user. |
| Check whether commit is signed through GPG **(PREMIUM)** | Reject commit when it is not signed through GPG. Read [signing commits with GPG](../user/project/repository/gpg_signed_commits/index.md). |
| Prevent committing secrets to Git | GitLab rejects any files that are likely to contain secrets. Read [what files are forbidden](#prevent-pushing-secrets-to-the-repository). |
| Restrict by commit message | Only commit messages that match this regular expression are allowed to be pushed. Leave empty to allow any commit message. Uses multiline mode, which can be disabled using `(?-m)`. |
| Restrict by commit message (negative match) | Only commit messages that do not match this regular expression are allowed to be pushed. Leave empty to allow any commit message. Uses multiline mode, which can be disabled using `(?-m)`. |
| Prevent pushing secret files | GitLab rejects any files that are likely to contain secrets. See the [forbiden file names](#prevent-pushing-secrets-to-the-repository). |
| Require expression in commit messages | Only commit messages that match this regular expression are allowed to be pushed. Leave empty to allow any commit message. Uses multiline mode, which can be disabled using `(?-m)`. |
| Reject expression in commit messages | Only commit messages that do not match this regular expression are allowed to be pushed. Leave empty to allow any commit message. Uses multiline mode, which can be disabled using `(?-m)`. |
| Restrict by branch name | Only branch names that match this regular expression are allowed to be pushed. Leave empty to allow any branch name. |
| Restrict by commit author's email | Only commit author's email that match this regular expression are allowed to be pushed. Leave empty to allow any email. |
| Prohibited file names | Any committed filenames that match this regular expression and do not already exist in the repository are not allowed to be pushed. Leave empty to allow any filenames. See [common examples](#prohibited-file-names). |

View File

@ -35,6 +35,7 @@ These shortcuts are available in most areas of GitLab
| <kbd>Shift</kbd> + <kbd>m</kbd> | Go to your Merge requests page.|
| <kbd>Shift</kbd> + <kbd>t</kbd> | Go to your To-Do List page. |
| <kbd>p</kbd> + <kbd>b</kbd> | Show/hide the Performance Bar. |
| <kbd>g</kbd> + <kbd>x</kbd> | Toggle between [GitLab](https://gitlab.com/) and [GitLab Next](https://next.gitlab.com/). |
Additionally, the following shortcuts are available when editing text in text fields,
for example comments, replies, issue descriptions, and merge request descriptions:

View File

@ -138,8 +138,8 @@ wait_for_pids(){
i=$((i+1))
if [ $((i%10)) = 0 ]; then
echo -n "."
elif [ $((i)) = 301 ]; then
echo "Waited 30s for the processes to write their pids, something probably went wrong."
elif [ $((i)) = 601 ]; then
echo "Waited 60s for the processes to write their pids, something probably went wrong."
exit 1;
fi
done

View File

@ -4926,6 +4926,9 @@ msgstr ""
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
msgid "BulkImport|destination group cannot be part of the source group tree"
msgstr ""
msgid "BulkImport|expected an associated Group but has an associated Project"
msgstr ""
@ -23774,7 +23777,7 @@ msgstr ""
msgid "Push to create a project"
msgstr ""
msgid "PushRule|Committer restriction"
msgid "PushRule|Reject unverified users"
msgstr ""
msgid "Pushed"

View File

@ -3,6 +3,7 @@ import { GlIcon } from '@gitlab/ui';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import IdeSidebarNav from '~/ide/components/ide_sidebar_nav.vue';
import { SIDE_RIGHT, SIDE_LEFT } from '~/ide/constants';
import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants';
const TEST_TABS = [
{
@ -74,7 +75,7 @@ describe('ide/components/ide_sidebar_nav', () => {
createComponent({ isOpen, side });
bsTooltipHide = jest.fn();
wrapper.vm.$root.$on('bv::hide::tooltip', bsTooltipHide);
wrapper.vm.$root.$on(BV_HIDE_TOOLTIP, bsTooltipHide);
});
it('renders buttons', () => {

View File

@ -6,6 +6,7 @@ import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
import { GlBreakpointInstance as bp } from '@gitlab/ui/dist/utils';
import waitForPromises from 'helpers/wait_for_promises';
import RoleDropdown from '~/members/components/table/role_dropdown.vue';
import { BV_DROPDOWN_SHOW } from '~/lib/utils/constants';
import { member } from '../../mock_data';
const localVue = createLocalVue();
@ -67,7 +68,7 @@ describe('RoleDropdown', () => {
createComponent();
findDropdownToggle().trigger('click');
wrapper.vm.$root.$on('bv::dropdown::shown', () => {
wrapper.vm.$root.$on(BV_DROPDOWN_SHOW, () => {
done();
});
});

View File

@ -6,6 +6,7 @@ import createStore from '~/notes/stores';
import noteActions from '~/notes/components/note_actions.vue';
import axios from '~/lib/utils/axios_utils';
import { userDataMock } from '../mock_data';
import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants';
describe('noteActions', () => {
let wrapper;
@ -135,7 +136,7 @@ describe('noteActions', () => {
.then(() => {
const emitted = Object.keys(rootWrapper.emitted());
expect(emitted).toEqual(['bv::hide::tooltip']);
expect(emitted).toEqual([BV_HIDE_TOOLTIP]);
done();
})
.catch(done.fail);

View File

@ -4,6 +4,7 @@ import LinkedPipelineComponent from '~/pipelines/components/graph/linked_pipelin
import CiStatus from '~/vue_shared/components/ci_icon.vue';
import { UPSTREAM, DOWNSTREAM } from '~/pipelines/components/graph/constants';
import mockData from './linked_pipelines_mock_data';
import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants';
const mockPipeline = mockData.triggered[0];
const validTriggeredPipelineId = mockPipeline.project.id;
@ -212,11 +213,11 @@ describe('Linked pipeline', () => {
expect(wrapper.emitted().pipelineClicked).toBeTruthy();
});
it('should emit `bv::hide::tooltip` to close the tooltip', () => {
it(`should emit ${BV_HIDE_TOOLTIP} to close the tooltip`, () => {
jest.spyOn(wrapper.vm.$root, '$emit');
findButton().trigger('click');
expect(wrapper.vm.$root.$emit.mock.calls[0]).toEqual(['bv::hide::tooltip']);
expect(wrapper.vm.$root.$emit.mock.calls[0]).toEqual([BV_HIDE_TOOLTIP]);
});
it('should emit downstreamHovered with job name on mouseover', () => {

View File

@ -1,5 +1,6 @@
import { shallowMount, createWrapper } from '@vue/test-utils';
import ModalCopyButton from '~/vue_shared/components/modal_copy_button.vue';
import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants';
describe('modal copy button', () => {
let wrapper;
@ -31,7 +32,7 @@ describe('modal copy button', () => {
return wrapper.vm.$nextTick().then(() => {
expect(wrapper.emitted().success).not.toBeEmpty();
expect(document.execCommand).toHaveBeenCalledWith('copy');
expect(root.emitted('bv::hide::tooltip')).toEqual([['test-id']]);
expect(root.emitted(BV_HIDE_TOOLTIP)).toEqual([['test-id']]);
});
});
it("should propagate the clipboard error event if execCommand doesn't work", () => {

View File

@ -0,0 +1,104 @@
# frozen_string_literal: true
require 'spec_helper'
require_migration!
RSpec.describe CleanupProjectsWithNullHasExternalWiki, :migration, schema: 20210105025900 do
let(:namespace) { table(:namespaces).create!(name: 'foo', path: 'bar') }
let(:projects) { table(:projects) }
let(:services) { table(:services) }
let(:constraint_name) { 'check_421d399b70' }
def create_projects!(num)
Array.new(num) do
projects.create!(namespace_id: namespace.id)
end
end
def create_active_external_wiki_integrations!(*projects)
projects.each do |project|
services.create!(type: 'ExternalWikiService', project_id: project.id, active: true)
end
end
def create_disabled_external_wiki_integrations!(*projects)
projects.each do |project|
services.create!(type: 'ExternalWikiService', project_id: project.id, active: false)
end
end
def create_active_other_integrations!(*projects)
projects.each do |project|
services.create!(type: 'NotAnExternalWikiService', project_id: project.id, active: true)
end
end
it 'sets `projects.has_external_wiki` correctly' do
allow(ActiveRecord::Base.connection).to receive(:transaction_open?).and_return(false)
project_with_external_wiki_1,
project_with_external_wiki_2,
project_with_external_wiki_3,
project_with_disabled_external_wiki_1,
project_with_disabled_external_wiki_2,
project_with_disabled_external_wiki_3,
project_without_external_wiki_1,
project_without_external_wiki_2,
project_without_external_wiki_3 = create_projects!(9)
create_active_external_wiki_integrations!(
project_with_external_wiki_1,
project_with_external_wiki_2,
project_with_external_wiki_3
)
create_disabled_external_wiki_integrations!(
project_with_disabled_external_wiki_1,
project_with_disabled_external_wiki_2,
project_with_disabled_external_wiki_3
)
create_active_other_integrations!(
project_without_external_wiki_1,
project_without_external_wiki_2,
project_without_external_wiki_3
)
# PG triggers on the services table added in a previous migration
# will have set the `has_external_wiki` columns to correct data when
# the services records were created above.
#
# We set the `has_external_wiki` columns for projects to NULL or incorrect
# data manually below to emulate projects in a state before the PG
# triggers were added.
project_with_external_wiki_1.update!(has_external_wiki: nil)
project_with_external_wiki_2.update!(has_external_wiki: false)
project_with_disabled_external_wiki_1.update!(has_external_wiki: nil)
project_with_disabled_external_wiki_2.update!(has_external_wiki: true)
project_without_external_wiki_1.update!(has_external_wiki: nil)
project_without_external_wiki_2.update!(has_external_wiki: true)
migrate!
expected_true = [
project_with_external_wiki_1,
project_with_external_wiki_2,
project_with_external_wiki_3
].each(&:reload).map(&:has_external_wiki)
expected_false = [
project_without_external_wiki_1,
project_without_external_wiki_2,
project_without_external_wiki_3,
project_with_disabled_external_wiki_1,
project_with_disabled_external_wiki_2,
project_with_disabled_external_wiki_3
].each(&:reload).map(&:has_external_wiki)
expect(expected_true).to all(eq(true))
expect(expected_false).to all(eq(false))
end
end

View File

@ -81,6 +81,37 @@ RSpec.describe BulkImports::Entity, type: :model do
expect(entity.errors).to include(:parent)
end
end
context 'validate destination namespace of a group_entity' do
it 'is invalid if destination namespace is the source namespace' do
group_a = create(:group, path: 'group_a')
entity = build(
:bulk_import_entity,
:group_entity,
source_full_path: group_a.full_path,
destination_namespace: group_a.full_path
)
expect(entity).not_to be_valid
expect(entity.errors).to include(:destination_namespace)
end
it 'is invalid if destination namespace is a descendant of the source' do
group_a = create(:group, path: 'group_a')
group_b = create(:group, parent: group_a, path: 'group_b')
entity = build(
:bulk_import_entity,
:group_entity,
source_full_path: group_a.full_path,
destination_namespace: group_b.full_path
)
expect(entity).not_to be_valid
expect(entity.errors).to include(:destination_namespace)
end
end
end
describe "#update_tracker_for" do

View File

@ -1145,11 +1145,32 @@ RSpec.describe Project, factory_default: :keep do
is_expected.to eq(nil)
end
it 'sets Project#has_external_wiki when it is nil' do
create(:service, project: project, type: 'ExternalWikiService', active: true)
project.update_column(:has_external_wiki, nil)
it 'calls Project#cache_has_external_wiki when `has_external_wiki` is nil' do
project = build(:project, has_external_wiki: nil)
expect { subject }.to change { project.has_external_wiki }.from(nil).to(true)
expect(project).to receive(:cache_has_external_wiki)
project.external_wiki
end
it 'does not call Project#cache_has_external_wiki when `has_external_wiki` is not nil' do
project = build(:project)
expect(project).not_to receive(:cache_has_external_wiki)
project.external_wiki
end
end
describe '#cache_has_external_wiki (private method)' do
it 'sets Project#has_external_wiki correctly, affecting Project#external_wiki' do
project = create(:project)
create(:service, project: project, type: 'ExternalWikiService', active: true)
project.update_column(:has_external_wiki, false)
expect { project.send(:cache_has_external_wiki) }
.to change { project.has_external_wiki }.from(false).to(true)
.and(change { project.external_wiki }.from(nil).to(kind_of(ExternalWikiService)))
end
end