Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
36e4abb3dd
commit
a020b8c048
|
|
@ -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();
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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()) {
|
||||
|
|
|
|||
|
|
@ -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()) {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
});
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Replace bootstrap event strings with constants
|
||||
merge_request: 52777
|
||||
author: Kev @KevSlashNull
|
||||
type: other
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: 'BulkImports: avoid infinity recursion on group migration'
|
||||
merge_request: 52931
|
||||
author:
|
||||
type: fixed
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add index to incident management oncall shifts table
|
||||
merge_request: 52961
|
||||
author:
|
||||
type: performance
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1 @@
|
|||
047dd77352eda8134e55047e2d3fab07bbcd6eb41600cefb9b581d32e441fb68
|
||||
|
|
@ -0,0 +1 @@
|
|||
339d828635107f77116ffd856abcb8f8f64985cabb82c0c34ab76056f5756d2e
|
||||
|
|
@ -0,0 +1 @@
|
|||
30f3cbc0f96848f72a188616503eb80d38c33769c8bebf86a5922b374750d066
|
||||
|
|
@ -0,0 +1 @@
|
|||
6cb54c71a9835ec1b3cf801a19c2cd385d224e0438c7924b6a29d298ecebe8a7
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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). |
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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', () => {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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', () => {
|
||||
|
|
|
|||
|
|
@ -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", () => {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue