Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
e3042fc5ce
commit
f020d5dc9b
|
|
@ -1 +1 @@
|
|||
30ae36f781ee979330b1f170d81c97c319c2fff1
|
||||
4a1b0d4018ee35cfe786ba3dd975b20013a39e39
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import { s__ } from '~/locale';
|
||||
|
||||
export const MSG_CANNOT_PUSH_CODE_SHOULD_FORK = s__(
|
||||
'WebIDE|You need permission to edit files directly in this project. Fork this project to make your changes and submit a merge request.',
|
||||
'WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes.',
|
||||
);
|
||||
|
||||
export const MSG_CANNOT_PUSH_CODE_GO_TO_FORK = s__(
|
||||
'WebIDE|You need permission to edit files directly in this project. Go to your fork to make changes and submit a merge request.',
|
||||
'WebIDE|You can’t edit files directly in this project. Go to your fork and submit a merge request with your changes.',
|
||||
);
|
||||
|
||||
export const MSG_CANNOT_PUSH_CODE = s__(
|
||||
|
|
@ -13,7 +13,7 @@ export const MSG_CANNOT_PUSH_CODE = s__(
|
|||
);
|
||||
|
||||
export const MSG_CANNOT_PUSH_UNSIGNED = s__(
|
||||
'WebIDE|This project does not accept unsigned commits. You will not be able to commit your changes through the Web IDE.',
|
||||
'WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE.',
|
||||
);
|
||||
|
||||
export const MSG_CANNOT_PUSH_UNSIGNED_SHORT = s__(
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ import { __ } from '~/locale';
|
|||
import { DEFAULT_NONE_ANY } from '~/vue_shared/components/filtered_search_bar/constants';
|
||||
import AuthorToken from '~/vue_shared/components/filtered_search_bar/tokens/author_token.vue';
|
||||
import EmojiToken from '~/vue_shared/components/filtered_search_bar/tokens/emoji_token.vue';
|
||||
import EpicToken from '~/vue_shared/components/filtered_search_bar/tokens/epic_token.vue';
|
||||
import IterationToken from '~/vue_shared/components/filtered_search_bar/tokens/iteration_token.vue';
|
||||
import LabelToken from '~/vue_shared/components/filtered_search_bar/tokens/label_token.vue';
|
||||
import MilestoneToken from '~/vue_shared/components/filtered_search_bar/tokens/milestone_token.vue';
|
||||
|
|
@ -87,6 +88,9 @@ export default {
|
|||
exportCsvPath: {
|
||||
default: '',
|
||||
},
|
||||
groupEpicsPath: {
|
||||
default: '',
|
||||
},
|
||||
hasBlockedIssuesFeature: {
|
||||
default: false,
|
||||
},
|
||||
|
|
@ -241,6 +245,17 @@ export default {
|
|||
});
|
||||
}
|
||||
|
||||
if (this.groupEpicsPath) {
|
||||
tokens.push({
|
||||
type: 'epic_id',
|
||||
title: __('Epic'),
|
||||
icon: 'epic',
|
||||
token: EpicToken,
|
||||
unique: true,
|
||||
fetchEpics: this.fetchEpics,
|
||||
});
|
||||
}
|
||||
|
||||
if (this.hasIssueWeightsFeature) {
|
||||
tokens.push({
|
||||
type: 'weight',
|
||||
|
|
@ -306,6 +321,16 @@ export default {
|
|||
fetchEmojis(search) {
|
||||
return this.fetchWithCache(this.autocompleteAwardEmojisPath, 'emojis', 'name', search);
|
||||
},
|
||||
async fetchEpics(search) {
|
||||
const epics = await this.fetchWithCache(this.groupEpicsPath, 'epics');
|
||||
if (!search) {
|
||||
return epics.slice(0, MAX_LIST_SIZE);
|
||||
}
|
||||
const number = Number(search);
|
||||
return Number.isNaN(number)
|
||||
? fuzzaldrinPlus.filter(epics, search, { key: 'title' })
|
||||
: epics.filter((epic) => epic.id === number);
|
||||
},
|
||||
fetchLabels(search) {
|
||||
return this.fetchWithCache(this.projectLabelsPath, 'labels', 'title', search);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -324,6 +324,26 @@ export const filters = {
|
|||
},
|
||||
},
|
||||
},
|
||||
epic_id: {
|
||||
apiParam: {
|
||||
[OPERATOR_IS]: {
|
||||
[NORMAL_FILTER]: 'epic_id',
|
||||
[SPECIAL_FILTER]: 'epic_id',
|
||||
},
|
||||
[OPERATOR_IS_NOT]: {
|
||||
[NORMAL_FILTER]: 'not[epic_id]',
|
||||
},
|
||||
},
|
||||
urlParam: {
|
||||
[OPERATOR_IS]: {
|
||||
[NORMAL_FILTER]: 'epic_id',
|
||||
[SPECIAL_FILTER]: 'epic_id',
|
||||
},
|
||||
[OPERATOR_IS_NOT]: {
|
||||
[NORMAL_FILTER]: 'not[epic_id]',
|
||||
},
|
||||
},
|
||||
},
|
||||
weight: {
|
||||
apiParam: {
|
||||
[OPERATOR_IS]: {
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@ export function mountIssuesListApp() {
|
|||
emptyStateSvgPath,
|
||||
endpoint,
|
||||
exportCsvPath,
|
||||
groupEpicsPath,
|
||||
hasBlockedIssuesFeature,
|
||||
hasIssuableHealthStatusFeature,
|
||||
hasIssues,
|
||||
|
|
@ -121,6 +122,7 @@ export function mountIssuesListApp() {
|
|||
canBulkUpdate: parseBoolean(canBulkUpdate),
|
||||
emptyStateSvgPath,
|
||||
endpoint,
|
||||
groupEpicsPath,
|
||||
hasBlockedIssuesFeature: parseBoolean(hasBlockedIssuesFeature),
|
||||
hasIssuableHealthStatusFeature: parseBoolean(hasIssuableHealthStatusFeature),
|
||||
hasIssues: parseBoolean(hasIssues),
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { GlToast } from '@gitlab/ui';
|
||||
import Vue from 'vue';
|
||||
import Vuex from 'vuex';
|
||||
import { parseDataAttributes } from 'ee_else_ce/members/utils';
|
||||
import { parseDataAttributes } from '~/members/utils';
|
||||
import App from './components/app.vue';
|
||||
import membersStore from './store';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,5 @@
|
|||
import { isUndefined } from 'lodash';
|
||||
import {
|
||||
getParameterByName,
|
||||
convertObjectPropsToCamelCase,
|
||||
parseBoolean,
|
||||
} from '~/lib/utils/common_utils';
|
||||
import { getParameterByName, convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
|
||||
import { setUrlParams } from '~/lib/utils/url_utility';
|
||||
import { __ } from '~/locale';
|
||||
import {
|
||||
|
|
@ -105,18 +101,12 @@ export const buildSortHref = ({
|
|||
export const canOverride = () => false;
|
||||
|
||||
export const parseDataAttributes = (el) => {
|
||||
const { members, pagination, sourceId, memberPath, canManageMembers } = el.dataset;
|
||||
const { membersData } = el.dataset;
|
||||
|
||||
return {
|
||||
members: convertObjectPropsToCamelCase(JSON.parse(members), { deep: true }),
|
||||
pagination: convertObjectPropsToCamelCase(JSON.parse(pagination || '{}'), {
|
||||
deep: true,
|
||||
ignoreKeyNames: ['params'],
|
||||
}),
|
||||
sourceId: parseInt(sourceId, 10),
|
||||
memberPath,
|
||||
canManageMembers: parseBoolean(canManageMembers),
|
||||
};
|
||||
return convertObjectPropsToCamelCase(JSON.parse(membersData), {
|
||||
deep: true,
|
||||
ignoreKeyNames: ['params'],
|
||||
});
|
||||
};
|
||||
|
||||
export const baseRequestFormatter = (basePropertyName, accessLevelPropertyName) => ({
|
||||
|
|
|
|||
|
|
@ -28,10 +28,15 @@ export default {
|
|||
'mavenSetupXml',
|
||||
'gradleGroovyInstalCommand',
|
||||
'gradleGroovyAddSourceCommand',
|
||||
'gradleKotlinInstalCommand',
|
||||
'gradleKotlinAddSourceCommand',
|
||||
]),
|
||||
showMaven() {
|
||||
return this.instructionType === 'maven';
|
||||
},
|
||||
showGroovy() {
|
||||
return this.instructionType === 'groovy';
|
||||
},
|
||||
},
|
||||
i18n: {
|
||||
xmlText: s__(
|
||||
|
|
@ -47,8 +52,9 @@ export default {
|
|||
trackingActions: { ...TrackingActions },
|
||||
TrackingLabels,
|
||||
installOptions: [
|
||||
{ value: 'maven', label: s__('PackageRegistry|Show Maven commands') },
|
||||
{ value: 'groovy', label: s__('PackageRegistry|Show Gradle Groovy DSL commands') },
|
||||
{ value: 'maven', label: s__('PackageRegistry|Maven XML') },
|
||||
{ value: 'groovy', label: s__('PackageRegistry|Gradle Groovy DSL') },
|
||||
{ value: 'kotlin', label: s__('PackageRegistry|Gradle Kotlin DSL') },
|
||||
],
|
||||
};
|
||||
</script>
|
||||
|
|
@ -107,7 +113,7 @@ export default {
|
|||
</template>
|
||||
</gl-sprintf>
|
||||
</template>
|
||||
<template v-else>
|
||||
<template v-else-if="showGroovy">
|
||||
<code-instruction
|
||||
class="gl-mb-5"
|
||||
:label="s__('PackageRegistry|Gradle Groovy DSL install command')"
|
||||
|
|
@ -125,5 +131,23 @@ export default {
|
|||
multiline
|
||||
/>
|
||||
</template>
|
||||
<template v-else>
|
||||
<code-instruction
|
||||
class="gl-mb-5"
|
||||
:label="s__('PackageRegistry|Gradle Kotlin DSL install command')"
|
||||
:instruction="gradleKotlinInstalCommand"
|
||||
:copy-text="s__('PackageRegistry|Copy Gradle Kotlin DSL install command')"
|
||||
:tracking-action="$options.trackingActions.COPY_KOTLIN_INSTALL_COMMAND"
|
||||
:tracking-label="$options.TrackingLabels.CODE_INSTRUCTION"
|
||||
/>
|
||||
<code-instruction
|
||||
:label="s__('PackageRegistry|Add Gradle Kotlin DSL repository command')"
|
||||
:instruction="gradleKotlinAddSourceCommand"
|
||||
:copy-text="s__('PackageRegistry|Copy add Gradle Kotlin DSL repository command')"
|
||||
:tracking-action="$options.trackingActions.COPY_KOTLIN_ADD_TO_SOURCE_COMMAND"
|
||||
:tracking-label="$options.TrackingLabels.CODE_INSTRUCTION"
|
||||
multiline
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -38,6 +38,9 @@ export const TrackingActions = {
|
|||
|
||||
COPY_GRADLE_INSTALL_COMMAND: 'copy_gradle_install_command',
|
||||
COPY_GRADLE_ADD_TO_SOURCE_COMMAND: 'copy_gradle_add_to_source_command',
|
||||
|
||||
COPY_KOTLIN_INSTALL_COMMAND: 'copy_kotlin_install_command',
|
||||
COPY_KOTLIN_ADD_TO_SOURCE_COMMAND: 'copy_kotlin_add_to_source_command',
|
||||
};
|
||||
|
||||
export const NpmManager = {
|
||||
|
|
|
|||
|
|
@ -126,4 +126,15 @@ export const gradleGroovyAddSourceCommand = ({ mavenPath }) =>
|
|||
url '${mavenPath}'
|
||||
}`;
|
||||
|
||||
export const gradleKotlinInstalCommand = ({ packageEntity }) => {
|
||||
const {
|
||||
app_group: group = '',
|
||||
app_name: name = '',
|
||||
app_version: version = '',
|
||||
} = packageEntity.maven_metadatum;
|
||||
return `implementation("${group}:${name}:${version}")`;
|
||||
};
|
||||
|
||||
export const gradleKotlinAddSourceCommand = ({ mavenPath }) => `maven("${mavenPath}")`;
|
||||
|
||||
export const groupExists = ({ groupListUrl }) => groupListUrl.length > 0;
|
||||
|
|
|
|||
|
|
@ -1,15 +1,18 @@
|
|||
<script>
|
||||
import { GlFilteredSearchToken, GlFilteredSearchSuggestion, GlLoadingIcon } from '@gitlab/ui';
|
||||
import {
|
||||
GlDropdownDivider,
|
||||
GlFilteredSearchSuggestion,
|
||||
GlFilteredSearchToken,
|
||||
GlLoadingIcon,
|
||||
} from '@gitlab/ui';
|
||||
import { debounce } from 'lodash';
|
||||
|
||||
import createFlash from '~/flash';
|
||||
import { isNumeric } from '~/lib/utils/number_utils';
|
||||
import { __ } from '~/locale';
|
||||
import { DEBOUNCE_DELAY } from '../constants';
|
||||
import { stripQuotes } from '../filtered_search_utils';
|
||||
import { DEBOUNCE_DELAY, DEFAULT_NONE_ANY } from '../constants';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GlDropdownDivider,
|
||||
GlFilteredSearchToken,
|
||||
GlFilteredSearchSuggestion,
|
||||
GlLoadingIcon,
|
||||
|
|
@ -32,29 +35,16 @@ export default {
|
|||
},
|
||||
computed: {
|
||||
currentValue() {
|
||||
/*
|
||||
* When the URL contains the epic_iid, we'd get: '123'
|
||||
*/
|
||||
if (isNumeric(this.value.data)) {
|
||||
return parseInt(this.value.data, 10);
|
||||
}
|
||||
|
||||
/*
|
||||
* When the token is added in current session it'd be: 'Foo::&123'
|
||||
*/
|
||||
const id = this.value.data.split('::&')[1];
|
||||
|
||||
if (id) {
|
||||
return parseInt(id, 10);
|
||||
}
|
||||
|
||||
return this.value.data;
|
||||
return Number(this.value.data);
|
||||
},
|
||||
defaultEpics() {
|
||||
return this.config.defaultEpics || DEFAULT_NONE_ANY;
|
||||
},
|
||||
idProperty() {
|
||||
return this.config.idProperty || 'id';
|
||||
},
|
||||
activeEpic() {
|
||||
const currentValueIsString = typeof this.currentValue === 'string';
|
||||
return this.epics.find(
|
||||
(epic) => epic[currentValueIsString ? 'title' : 'iid'] === this.currentValue,
|
||||
);
|
||||
return this.epics.find((epic) => epic[this.idProperty] === this.currentValue);
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
|
|
@ -72,20 +62,8 @@ export default {
|
|||
this.loading = true;
|
||||
this.config
|
||||
.fetchEpics(searchTerm)
|
||||
.then(({ data }) => {
|
||||
this.epics = data;
|
||||
})
|
||||
.catch(() => createFlash({ message: __('There was a problem fetching epics.') }))
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
fetchSingleEpic(iid) {
|
||||
this.loading = true;
|
||||
this.config
|
||||
.fetchSingleEpic(iid)
|
||||
.then(({ data }) => {
|
||||
this.epics = [data];
|
||||
.then((response) => {
|
||||
this.epics = Array.isArray(response) ? response : response.data;
|
||||
})
|
||||
.catch(() => createFlash({ message: __('There was a problem fetching epics.') }))
|
||||
.finally(() => {
|
||||
|
|
@ -93,17 +71,13 @@ export default {
|
|||
});
|
||||
},
|
||||
searchEpics: debounce(function debouncedSearch({ data }) {
|
||||
if (isNumeric(data)) {
|
||||
return this.fetchSingleEpic(data);
|
||||
}
|
||||
return this.fetchEpicsBySearchTerm(data);
|
||||
this.fetchEpicsBySearchTerm(data);
|
||||
}, DEBOUNCE_DELAY),
|
||||
|
||||
getEpicValue(epic) {
|
||||
return `${epic.title}::&${epic.iid}`;
|
||||
getEpicDisplayText(epic) {
|
||||
return `${epic.title}::&${epic[this.idProperty]}`;
|
||||
},
|
||||
},
|
||||
stripQuotes,
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
@ -115,17 +89,25 @@ export default {
|
|||
@input="searchEpics"
|
||||
>
|
||||
<template #view="{ inputValue }">
|
||||
<span>{{ activeEpic ? getEpicValue(activeEpic) : $options.stripQuotes(inputValue) }}</span>
|
||||
{{ activeEpic ? getEpicDisplayText(activeEpic) : inputValue }}
|
||||
</template>
|
||||
<template #suggestions>
|
||||
<gl-filtered-search-suggestion
|
||||
v-for="epic in defaultEpics"
|
||||
:key="epic.value"
|
||||
:value="epic.value"
|
||||
>
|
||||
{{ epic.text }}
|
||||
</gl-filtered-search-suggestion>
|
||||
<gl-dropdown-divider v-if="defaultEpics.length" />
|
||||
<gl-loading-icon v-if="loading" />
|
||||
<template v-else>
|
||||
<gl-filtered-search-suggestion
|
||||
v-for="epic in epics"
|
||||
:key="epic.id"
|
||||
:value="getEpicValue(epic)"
|
||||
:key="epic[idProperty]"
|
||||
:value="String(epic[idProperty])"
|
||||
>
|
||||
<div>{{ epic.title }}</div>
|
||||
{{ epic.title }}
|
||||
</gl-filtered-search-suggestion>
|
||||
</template>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@ module AcceptsPendingInvitations
|
|||
def accept_pending_invitations
|
||||
return unless resource.active_for_authentication?
|
||||
|
||||
if resource.accept_pending_invitations!.any?
|
||||
if resource.pending_invitations.load.any?
|
||||
resource.accept_pending_invitations!
|
||||
clear_stored_location_for_resource
|
||||
after_pending_invitations_hook
|
||||
end
|
||||
|
|
|
|||
|
|
@ -17,7 +17,10 @@ class Projects::RunnerProjectsController < Projects::ApplicationController
|
|||
if @runner.assign_to(project, current_user)
|
||||
redirect_to path
|
||||
else
|
||||
redirect_to path, alert: 'Failed adding runner to project'
|
||||
assign_to_messages = @runner.errors.messages[:assign_to]
|
||||
alert = assign_to_messages&.join(',') || 'Failed adding runner to project'
|
||||
|
||||
redirect_to path, alert: alert
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -32,6 +32,15 @@ module Types
|
|||
field :web_path, GraphQL::STRING_TYPE, null: true,
|
||||
description: 'Web path of the blob.'
|
||||
|
||||
field :ide_edit_path, GraphQL::STRING_TYPE, null: true,
|
||||
description: 'Web path to edit this blob in the Web IDE.'
|
||||
|
||||
field :fork_and_edit_path, GraphQL::STRING_TYPE, null: true,
|
||||
description: 'Web path to edit this blob using a forked project.'
|
||||
|
||||
field :ide_fork_and_edit_path, GraphQL::STRING_TYPE, null: true,
|
||||
description: 'Web path to edit this blob in the Web IDE using a forked project.'
|
||||
|
||||
field :size, GraphQL::INT_TYPE, null: true,
|
||||
description: 'Size (in bytes) of the blob.'
|
||||
|
||||
|
|
@ -53,6 +62,9 @@ module Types
|
|||
field :raw_path, GraphQL::STRING_TYPE, null: true,
|
||||
description: 'Web path to download the raw blob.'
|
||||
|
||||
field :external_storage_url, GraphQL::STRING_TYPE, null: true,
|
||||
description: 'Web path to download the raw blob via external storage, if enabled.'
|
||||
|
||||
field :replace_path, GraphQL::STRING_TYPE, null: true,
|
||||
description: 'Web path to replace the blob content.'
|
||||
|
||||
|
|
@ -72,6 +84,10 @@ module Types
|
|||
null: true,
|
||||
calls_gitaly: true
|
||||
|
||||
field :can_modify_blob, GraphQL::BOOLEAN_TYPE, null: true, method: :can_modify_blob?,
|
||||
calls_gitaly: true,
|
||||
description: 'Whether the current user can modify the blob.'
|
||||
|
||||
def raw_text_blob
|
||||
object.data unless object.binary?
|
||||
end
|
||||
|
|
|
|||
|
|
@ -13,31 +13,41 @@ module Groups::GroupMembersHelper
|
|||
render 'shared/members/invite_member', submit_url: group_group_members_path(group), access_levels: group.access_level_roles, default_access_level: default_access_level
|
||||
end
|
||||
|
||||
def group_group_links_data_json(group_links)
|
||||
GroupLink::GroupGroupLinkSerializer.new.represent(group_links, { current_user: current_user }).to_json
|
||||
def group_members_list_data_json(group, members, pagination = {})
|
||||
group_members_list_data(group, members, pagination).to_json
|
||||
end
|
||||
|
||||
def members_data_json(group, members)
|
||||
MemberSerializer.new.represent(members, { current_user: current_user, group: group, source: group }).to_json
|
||||
def group_group_links_list_data_json(group)
|
||||
group_group_links_list_data(group).to_json
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def group_members_serialized(group, members)
|
||||
MemberSerializer.new.represent(members, { current_user: current_user, group: group, source: group })
|
||||
end
|
||||
|
||||
def group_group_links_serialized(group_links)
|
||||
GroupLink::GroupGroupLinkSerializer.new.represent(group_links, { current_user: current_user })
|
||||
end
|
||||
|
||||
# Overridden in `ee/app/helpers/ee/groups/group_members_helper.rb`
|
||||
def group_members_list_data_attributes(group, members, pagination = {})
|
||||
def group_members_list_data(group, members, pagination)
|
||||
{
|
||||
members: members_data_json(group, members),
|
||||
pagination: members_pagination_data_json(members, pagination),
|
||||
members: group_members_serialized(group, members),
|
||||
pagination: members_pagination_data(members, pagination),
|
||||
member_path: group_group_member_path(group, ':id'),
|
||||
source_id: group.id,
|
||||
can_manage_members: can?(current_user, :admin_group_member, group).to_s
|
||||
can_manage_members: can?(current_user, :admin_group_member, group)
|
||||
}
|
||||
end
|
||||
|
||||
def group_group_links_list_data_attributes(group)
|
||||
def group_group_links_list_data(group)
|
||||
group_links = group.shared_with_group_links
|
||||
|
||||
{
|
||||
members: group_group_links_data_json(group_links),
|
||||
pagination: members_pagination_data_json(group_links),
|
||||
members: group_group_links_serialized(group_links),
|
||||
pagination: members_pagination_data(group_links),
|
||||
member_path: group_group_link_path(group, ':id'),
|
||||
source_id: group.id
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,13 +66,13 @@ module MembersHelper
|
|||
'group and any subresources'
|
||||
end
|
||||
|
||||
def members_pagination_data_json(members, pagination = {})
|
||||
def members_pagination_data(members, pagination = {})
|
||||
{
|
||||
current_page: members.respond_to?(:current_page) ? members.current_page : nil,
|
||||
per_page: members.respond_to?(:limit_value) ? members.limit_value : nil,
|
||||
total_items: members.respond_to?(:total_count) ? members.total_count : members.count,
|
||||
param_name: pagination[:param_name] || nil,
|
||||
params: pagination[:params] || {}
|
||||
}.to_json
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -27,31 +27,41 @@ module Projects::ProjectMembersHelper
|
|||
project.group.has_owner?(current_user)
|
||||
end
|
||||
|
||||
def project_group_links_data_json(group_links)
|
||||
GroupLink::ProjectGroupLinkSerializer.new.represent(group_links, { current_user: current_user }).to_json
|
||||
def project_members_list_data_json(project, members, pagination = {})
|
||||
project_members_list_data(project, members, pagination).to_json
|
||||
end
|
||||
|
||||
def project_members_data_json(project, members)
|
||||
MemberSerializer.new.represent(members, { current_user: current_user, group: project.group, source: project }).to_json
|
||||
def project_group_links_list_data_json(project, group_links)
|
||||
project_group_links_list_data(project, group_links).to_json
|
||||
end
|
||||
|
||||
def project_members_list_data_attributes(project, members, pagination = {})
|
||||
private
|
||||
|
||||
def project_members_serialized(project, members)
|
||||
MemberSerializer.new.represent(members, { current_user: current_user, group: project.group, source: project })
|
||||
end
|
||||
|
||||
def project_group_links_serialized(group_links)
|
||||
GroupLink::ProjectGroupLinkSerializer.new.represent(group_links, { current_user: current_user })
|
||||
end
|
||||
|
||||
def project_members_list_data(project, members, pagination)
|
||||
{
|
||||
members: project_members_data_json(project, members),
|
||||
pagination: members_pagination_data_json(members, pagination),
|
||||
members: project_members_serialized(project, members),
|
||||
pagination: members_pagination_data(members, pagination),
|
||||
member_path: project_project_member_path(project, ':id'),
|
||||
source_id: project.id,
|
||||
can_manage_members: can_manage_project_members?(project).to_s
|
||||
can_manage_members: can_manage_project_members?(project)
|
||||
}
|
||||
end
|
||||
|
||||
def project_group_links_list_data_attributes(project, group_links)
|
||||
def project_group_links_list_data(project, group_links)
|
||||
{
|
||||
members: project_group_links_data_json(group_links),
|
||||
pagination: members_pagination_data_json(group_links),
|
||||
members: project_group_links_serialized(group_links),
|
||||
pagination: members_pagination_data(group_links),
|
||||
member_path: project_group_link_path(project, ':id'),
|
||||
source_id: project.id,
|
||||
can_manage_members: can_manage_project_members?(project).to_s
|
||||
can_manage_members: can_manage_project_members?(project)
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -46,9 +46,9 @@ module Ci
|
|||
MINUTES_COST_FACTOR_FIELDS = %i[public_projects_minutes_cost_factor private_projects_minutes_cost_factor].freeze
|
||||
|
||||
has_many :builds
|
||||
has_many :runner_projects, inverse_of: :runner, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
|
||||
has_many :runner_projects, inverse_of: :runner, autosave: true, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
|
||||
has_many :projects, through: :runner_projects
|
||||
has_many :runner_namespaces, inverse_of: :runner
|
||||
has_many :runner_namespaces, inverse_of: :runner, autosave: true
|
||||
has_many :groups, through: :runner_namespaces
|
||||
|
||||
has_one :last_build, -> { order('id DESC') }, class_name: 'Ci::Build'
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ module Packages
|
|||
uniqueness: { scope: %i[distribution_id] },
|
||||
format: { with: Gitlab::Regex.debian_architecture_regex }
|
||||
|
||||
scope :ordered_by_name, -> { order(:name) }
|
||||
scope :with_distribution, ->(distribution) { where(distribution: distribution) }
|
||||
scope :with_name, ->(name) { where(name: name) }
|
||||
end
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ module Packages
|
|||
uniqueness: { scope: %i[distribution_id] },
|
||||
format: { with: Gitlab::Regex.debian_component_regex }
|
||||
|
||||
scope :ordered_by_name, -> { order(:name) }
|
||||
scope :with_distribution, ->(distribution) { where(distribution: distribution) }
|
||||
scope :with_name, ->(name) { where(name: name) }
|
||||
end
|
||||
|
|
|
|||
|
|
@ -60,6 +60,8 @@ module Packages
|
|||
|
||||
scope :preload_distribution, -> { includes(component: :distribution) }
|
||||
|
||||
scope :created_before, ->(reference) { where("#{table_name}.created_at < ?", reference) }
|
||||
|
||||
mount_file_store_uploader Packages::Debian::ComponentFileUploader
|
||||
|
||||
before_validation :update_size_from_file
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ class Email < ApplicationRecord
|
|||
|
||||
self.reconfirmable = false # currently email can't be changed, no need to reconfirm
|
||||
|
||||
delegate :username, :can?, to: :user
|
||||
delegate :username, :can?, :pending_invitations, :accept_pending_invitations!, to: :user
|
||||
|
||||
def email=(value)
|
||||
write_attribute(:email, value.downcase.strip)
|
||||
|
|
@ -32,10 +32,6 @@ class Email < ApplicationRecord
|
|||
self.errors.add(:email, 'has already been taken') if User.exists?(email: self.email)
|
||||
end
|
||||
|
||||
def accept_pending_invitations!
|
||||
user.accept_pending_invitations!
|
||||
end
|
||||
|
||||
def validate_email_format
|
||||
self.errors.add(:email, I18n.t(:invalid, scope: 'valid_email.validations.email')) unless ValidateEmail.valid?(self.email)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -6,4 +6,14 @@ class Packages::Debian::GroupDistribution < ApplicationRecord
|
|||
end
|
||||
|
||||
include Packages::Debian::Distribution
|
||||
|
||||
def packages
|
||||
Packages::Package
|
||||
.for_projects(group.all_projects.public_only)
|
||||
.with_debian_codename(codename)
|
||||
end
|
||||
|
||||
def package_files
|
||||
::Packages::PackageFile.for_package_ids(packages.select(:id))
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -5,8 +5,9 @@ class Packages::Debian::ProjectDistribution < ApplicationRecord
|
|||
:project
|
||||
end
|
||||
|
||||
include Packages::Debian::Distribution
|
||||
|
||||
has_many :publications, class_name: 'Packages::Debian::Publication', inverse_of: :distribution, foreign_key: :distribution_id
|
||||
has_many :packages, class_name: 'Packages::Package', through: :publications
|
||||
|
||||
include Packages::Debian::Distribution
|
||||
has_many :package_files, class_name: 'Packages::PackageFile', through: :packages
|
||||
end
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ class Packages::PackageFile < ApplicationRecord
|
|||
|
||||
delegate :project, :project_id, to: :package
|
||||
delegate :conan_file_type, to: :conan_file_metadatum
|
||||
delegate :file_type, :architecture, :fields, to: :debian_file_metadatum, prefix: :debian
|
||||
delegate :file_type, :component, :architecture, :fields, to: :debian_file_metadatum, prefix: :debian
|
||||
delegate :channel, :metadata, to: :helm_file_metadatum, prefix: :helm
|
||||
|
||||
belongs_to :package
|
||||
|
|
@ -27,6 +27,7 @@ class Packages::PackageFile < ApplicationRecord
|
|||
validates :file_name, uniqueness: { scope: :package }, if: -> { package&.pypi? }
|
||||
|
||||
scope :recent, -> { order(id: :desc) }
|
||||
scope :for_package_ids, ->(ids) { where(package_id: ids) }
|
||||
scope :with_file_name, ->(file_name) { where(file_name: file_name) }
|
||||
scope :with_file_name_like, ->(file_name) { where(arel_table[:file_name].matches(file_name)) }
|
||||
scope :with_files_stored_locally, -> { where(file_store: ::Packages::PackageFileUploader::Store::LOCAL) }
|
||||
|
|
@ -44,7 +45,17 @@ class Packages::PackageFile < ApplicationRecord
|
|||
|
||||
scope :with_debian_file_type, ->(file_type) do
|
||||
joins(:debian_file_metadatum)
|
||||
.where(packages_debian_file_metadata: { debian_file_type: ::Packages::Debian::FileMetadatum.debian_file_types[file_type] })
|
||||
.where(packages_debian_file_metadata: { file_type: ::Packages::Debian::FileMetadatum.file_types[file_type] })
|
||||
end
|
||||
|
||||
scope :with_debian_component_name, ->(component_name) do
|
||||
joins(:debian_file_metadatum)
|
||||
.where(packages_debian_file_metadata: { component: component_name })
|
||||
end
|
||||
|
||||
scope :with_debian_architecture_name, ->(architecture_name) do
|
||||
joins(:debian_file_metadatum)
|
||||
.where(packages_debian_file_metadata: { architecture: architecture_name })
|
||||
end
|
||||
|
||||
scope :with_conan_package_reference, ->(conan_package_reference) do
|
||||
|
|
|
|||
|
|
@ -1,6 +1,12 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class BlobPresenter < Gitlab::View::Presenter::Delegated
|
||||
include ApplicationHelper
|
||||
include BlobHelper
|
||||
include DiffHelper
|
||||
include TreeHelper
|
||||
include ChecksCollaboration
|
||||
|
||||
presents :blob
|
||||
|
||||
def highlight(to: nil, plain: nil)
|
||||
|
|
@ -40,6 +46,28 @@ class BlobPresenter < Gitlab::View::Presenter::Delegated
|
|||
url_helpers.project_create_blob_path(project, ref_qualified_path)
|
||||
end
|
||||
|
||||
def fork_and_edit_path
|
||||
fork_path_for_current_user(project, edit_blob_path)
|
||||
end
|
||||
|
||||
def ide_fork_and_edit_path
|
||||
fork_path_for_current_user(project, ide_edit_path)
|
||||
end
|
||||
|
||||
def can_modify_blob?
|
||||
super(blob, project, blob.commit_id)
|
||||
end
|
||||
|
||||
def ide_edit_path
|
||||
super(project, blob.commit_id, blob.path)
|
||||
end
|
||||
|
||||
def external_storage_url
|
||||
return unless static_objects_external_storage_enabled?
|
||||
|
||||
external_storage_url_or_path(url_helpers.project_raw_url(project, ref_qualified_path))
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def url_helpers
|
||||
|
|
|
|||
|
|
@ -0,0 +1,207 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Packages
|
||||
module Debian
|
||||
class GenerateDistributionService
|
||||
include Gitlab::Utils::StrongMemoize
|
||||
include ExclusiveLeaseGuard
|
||||
|
||||
# used by ExclusiveLeaseGuard
|
||||
DEFAULT_LEASE_TIMEOUT = 1.hour.to_i.freeze
|
||||
|
||||
# From https://salsa.debian.org/ftp-team/dak/-/blob/991aaa27a7f7aa773bb9c0cf2d516e383d9cffa0/setup/core-init.d/080_metadatakeys#L9
|
||||
BINARIES_METADATA = %w(
|
||||
Package
|
||||
Source
|
||||
Binary
|
||||
Version
|
||||
Essential
|
||||
Installed-Size
|
||||
Maintainer
|
||||
Uploaders
|
||||
Original-Maintainer
|
||||
Build-Depends
|
||||
Build-Depends-Indep
|
||||
Build-Conflicts
|
||||
Build-Conflicts-Indep
|
||||
Architecture
|
||||
Standards-Version
|
||||
Format
|
||||
Files
|
||||
Dm-Upload-Allowed
|
||||
Vcs-Browse
|
||||
Vcs-Hg
|
||||
Vcs-Darcs
|
||||
Vcs-Svn
|
||||
Vcs-Git
|
||||
Vcs-Browser
|
||||
Vcs-Arch
|
||||
Vcs-Bzr
|
||||
Vcs-Mtn
|
||||
Vcs-Cvs
|
||||
Checksums-Sha256
|
||||
Checksums-Sha1
|
||||
Replaces
|
||||
Provides
|
||||
Depends
|
||||
Pre-Depends
|
||||
Recommends
|
||||
Suggests
|
||||
Enhances
|
||||
Conflicts
|
||||
Breaks
|
||||
Description
|
||||
Origin
|
||||
Bugs
|
||||
Multi-Arch
|
||||
Homepage
|
||||
Tag
|
||||
Package-Type
|
||||
Installer-Menu-Item
|
||||
).freeze
|
||||
|
||||
def initialize(distribution)
|
||||
@distribution = distribution
|
||||
@last_generated_at = nil
|
||||
@md5sum = []
|
||||
@sha256 = []
|
||||
end
|
||||
|
||||
def execute
|
||||
try_obtain_lease do
|
||||
@distribution.transaction do
|
||||
@last_generated_at = @distribution.component_files.maximum(:created_at)
|
||||
generate_component_files
|
||||
generate_release
|
||||
destroy_old_component_files
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def generate_component_files
|
||||
@distribution.components.ordered_by_name.each do |component|
|
||||
@distribution.architectures.ordered_by_name.each do |architecture|
|
||||
generate_component_file(component, :packages, architecture, :deb)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def generate_component_file(component, component_file_type, architecture, package_file_type)
|
||||
paragraphs = @distribution.package_files
|
||||
.preload_debian_file_metadata
|
||||
.with_debian_component_name(component.name)
|
||||
.with_debian_architecture_name(architecture.name)
|
||||
.with_debian_file_type(package_file_type)
|
||||
.find_each
|
||||
.map(&method(:package_stanza_from_fields))
|
||||
create_component_file(component, component_file_type, architecture, package_file_type, paragraphs.join("\n"))
|
||||
end
|
||||
|
||||
def package_stanza_from_fields(package_file)
|
||||
[
|
||||
BINARIES_METADATA.map do |metadata_key|
|
||||
rfc822_field(metadata_key, package_file.debian_fields[metadata_key])
|
||||
end,
|
||||
rfc822_field('Section', package_file.debian_fields['Section'] || 'misc'),
|
||||
rfc822_field('Priority', package_file.debian_fields['Priority'] || 'extra'),
|
||||
rfc822_field('Filename', package_filename(package_file)),
|
||||
rfc822_field('Size', package_file.size),
|
||||
rfc822_field('MD5sum', package_file.file_md5),
|
||||
rfc822_field('SHA256', package_file.file_sha256)
|
||||
].flatten.compact.join('')
|
||||
end
|
||||
|
||||
def package_filename(package_file)
|
||||
letter = package_file.package.name.start_with?('lib') ? package_file.package.name[0..3] : package_file.package.name[0]
|
||||
"#{pool_prefix(package_file)}/#{letter}/#{package_file.package.name}/#{package_file.file_name}"
|
||||
end
|
||||
|
||||
def pool_prefix(package_file)
|
||||
case @distribution
|
||||
when ::Packages::Debian::GroupDistribution
|
||||
"pool/#{@distribution.codename}/#{package_file.package.project_id}"
|
||||
else
|
||||
"pool/#{@distribution.codename}/#{@distribution.container_id}"
|
||||
end
|
||||
end
|
||||
|
||||
def create_component_file(component, component_file_type, architecture, package_file_type, content)
|
||||
component_file = component.files.create!(
|
||||
file_type: component_file_type,
|
||||
architecture: architecture,
|
||||
compression_type: nil,
|
||||
file: CarrierWaveStringFile.new(content),
|
||||
file_md5: Digest::MD5.hexdigest(content),
|
||||
file_sha256: Digest::SHA256.hexdigest(content)
|
||||
)
|
||||
@md5sum.append(" #{component_file.file_md5} #{component_file.size.to_s.rjust(8)} #{component_file.relative_path}")
|
||||
@sha256.append(" #{component_file.file_sha256} #{component_file.size.to_s.rjust(8)} #{component_file.relative_path}")
|
||||
end
|
||||
|
||||
def generate_release
|
||||
@distribution.file = CarrierWaveStringFile.new(release_header + release_sums)
|
||||
@distribution.updated_at = release_date
|
||||
@distribution.save!
|
||||
end
|
||||
|
||||
def release_header
|
||||
strong_memoize(:release_header) do
|
||||
[
|
||||
%w[origin label suite version codename].map do |attribute|
|
||||
rfc822_field(attribute.capitalize, @distribution.attributes[attribute])
|
||||
end,
|
||||
rfc822_field('Date', release_date.to_formatted_s(:rfc822)),
|
||||
valid_until_field,
|
||||
rfc822_field('NotAutomatic', !@distribution.automatic, !@distribution.automatic),
|
||||
rfc822_field('ButAutomaticUpgrades', @distribution.automatic_upgrades, !@distribution.automatic && @distribution.automatic_upgrades),
|
||||
rfc822_field('Architectures', @distribution.architectures.map { |architecture| architecture.name }.sort.join(' ')),
|
||||
rfc822_field('Components', @distribution.components.map { |component| component.name }.sort.join(' ')),
|
||||
rfc822_field('Description', @distribution.description)
|
||||
].flatten.compact.join('')
|
||||
end
|
||||
end
|
||||
|
||||
def release_date
|
||||
strong_memoize(:release_date) do
|
||||
Time.now.utc
|
||||
end
|
||||
end
|
||||
|
||||
def release_sums
|
||||
["MD5Sum:", @md5sum, "SHA256:", @sha256].flatten.compact.join("\n") + "\n"
|
||||
end
|
||||
|
||||
def rfc822_field(name, value, condition = true)
|
||||
return unless condition
|
||||
return if value.blank?
|
||||
|
||||
"#{name}: #{value.to_s.gsub("\n\n", "\n.\n").gsub("\n", "\n ")}\n"
|
||||
end
|
||||
|
||||
def valid_until_field
|
||||
return unless @distribution.valid_time_duration_seconds
|
||||
|
||||
rfc822_field('Valid-Until', release_date.since(@distribution.valid_time_duration_seconds).to_formatted_s(:rfc822))
|
||||
end
|
||||
|
||||
def destroy_old_component_files
|
||||
# Only keep the last generation and one hour before
|
||||
return if @last_generated_at.nil?
|
||||
|
||||
@distribution.component_files.created_before(@last_generated_at - 1.hour).destroy_all # rubocop:disable Cop/DestroyAll
|
||||
end
|
||||
|
||||
# used by ExclusiveLeaseGuard
|
||||
def lease_key
|
||||
"packages:debian:generate_distribution_service:distribution:#{@distribution.id}"
|
||||
end
|
||||
|
||||
# used by ExclusiveLeaseGuard
|
||||
def lease_timeout
|
||||
DEFAULT_LEASE_TIMEOUT
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -61,21 +61,21 @@
|
|||
%span.badge.gl-tab-counter-badge.badge-muted.badge-pill.gl-badge.sm= @requesters.count
|
||||
.tab-content
|
||||
#tab-members.tab-pane{ class: ('active' unless invited_active) }
|
||||
.js-group-members-list{ data: group_members_list_data_attributes(@group, @members, { param_name: :page, params: { invited_members_page: nil, search_invited: nil } }) }
|
||||
.js-group-members-list{ data: { members_data: group_members_list_data_json(@group, @members, { param_name: :page, params: { invited_members_page: nil, search_invited: nil } }) } }
|
||||
.loading
|
||||
.gl-spinner.gl-spinner-md
|
||||
- if @group.shared_with_group_links.present?
|
||||
#tab-groups.tab-pane
|
||||
.js-group-group-links-list{ data: group_group_links_list_data_attributes(@group) }
|
||||
.js-group-group-links-list{ data: { members_data: group_group_links_list_data_json(@group) } }
|
||||
.loading
|
||||
.gl-spinner.gl-spinner-md
|
||||
- if show_invited_members
|
||||
#tab-invited-members.tab-pane{ class: ('active' if invited_active) }
|
||||
.js-group-invited-members-list{ data: group_members_list_data_attributes(@group, @invited_members, { param_name: :invited_members_page, params: { page: nil } }) }
|
||||
.js-group-invited-members-list{ data: { members_data: group_members_list_data_json(@group, @invited_members, { param_name: :invited_members_page, params: { page: nil } }) } }
|
||||
.loading
|
||||
.gl-spinner.gl-spinner-md
|
||||
- if show_access_requests
|
||||
#tab-access-requests.tab-pane
|
||||
.js-group-access-requests-list{ data: group_members_list_data_attributes(@group, @requesters) }
|
||||
.js-group-access-requests-list{ data: { members_data: group_members_list_data_json(@group, @requesters) } }
|
||||
.loading
|
||||
.gl-spinner.gl-spinner-md
|
||||
|
|
|
|||
|
|
@ -1,10 +1,7 @@
|
|||
- message_base = s_("ForkSuggestion|You can’t %{edit_start}edit%{edit_end} files directly in this project. Fork this project and submit a merge request with your changes.").html_safe
|
||||
- message = message_base.html_safe % { edit_start: '<span class="js-file-fork-suggestion-section-action">'.html_safe, edit_end: '</span>'.html_safe }
|
||||
.js-file-fork-suggestion-section.file-fork-suggestion.hidden
|
||||
%span.file-fork-suggestion-note
|
||||
You're not allowed to
|
||||
%span.js-file-fork-suggestion-section-action
|
||||
edit
|
||||
files in this project directly. Please fork this project,
|
||||
make your changes there, and submit a merge request.
|
||||
= link_to 'Fork', nil, method: :post, class: 'js-fork-suggestion-button gl-button btn btn-grouped btn-confirm-secondary'
|
||||
%span.file-fork-suggestion-note= message
|
||||
= link_to s_('ForkSuggestion|Fork'), nil, method: :post, class: 'js-fork-suggestion-button gl-button btn btn-grouped btn-confirm-secondary'
|
||||
%button.js-cancel-fork-suggestion-button.gl-button.btn.btn-grouped{ type: 'button' }
|
||||
Cancel
|
||||
= s_('ForkSuggestion|Cancel')
|
||||
|
|
|
|||
|
|
@ -82,21 +82,21 @@
|
|||
%span.badge.gl-tab-counter-badge.badge-muted.badge-pill.gl-badge.sm= @requesters.count
|
||||
.tab-content
|
||||
#tab-members.tab-pane{ class: ('active' unless groups_tab_active?) }
|
||||
.js-project-members-list{ data: project_members_list_data_attributes(@project, @project_members, { param_name: :page, params: { search_groups: nil } }) }
|
||||
.js-project-members-list{ data: { members_data: project_members_list_data_json(@project, @project_members, { param_name: :page, params: { search_groups: nil } }) } }
|
||||
.loading
|
||||
.gl-spinner.gl-spinner-md
|
||||
- if show_groups?(@group_links)
|
||||
#tab-groups.tab-pane{ class: ('active' if groups_tab_active?) }
|
||||
.js-project-group-links-list{ data: project_group_links_list_data_attributes(@project, @group_links) }
|
||||
.js-project-group-links-list{ data: { members_data: project_group_links_list_data_json(@project, @group_links) } }
|
||||
.loading
|
||||
.gl-spinner.gl-spinner-md
|
||||
- if show_invited_members?(@project, @invited_members)
|
||||
#tab-invited-members.tab-pane
|
||||
.js-project-invited-members-list{ data: project_members_list_data_attributes(@project, @invited_members) }
|
||||
.js-project-invited-members-list{ data: { members_data: project_members_list_data_json(@project, @invited_members) } }
|
||||
.loading
|
||||
.gl-spinner.gl-spinner-md
|
||||
- if show_access_requests?(@project, @requesters)
|
||||
#tab-access-requests.tab-pane
|
||||
.js-project-access-requests-list{ data: project_members_list_data_attributes(@project, @requesters) }
|
||||
.js-project-access-requests-list{ data: { members_data: project_members_list_data_json(@project, @requesters) } }
|
||||
.loading
|
||||
.gl-spinner.gl-spinner-md
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
%button.close{ type: "button", "data-dismiss": "modal", "aria-label" => _('Close') }
|
||||
%span{ "aria-hidden": true } ×
|
||||
.modal-body.p-3
|
||||
%p= _("You're not allowed to %{tag_start}edit%{tag_end} files in this project directly. Please fork this project, make your changes there, and submit a merge request.") % { tag_start: '', tag_end: ''}
|
||||
%p= _("You can’t %{tag_start}edit%{tag_end} files directly in this project. Fork this project and submit a merge request with your changes.") % { tag_start: '', tag_end: ''}
|
||||
.modal-footer
|
||||
= link_to _('Cancel'), '#', class: "btn gl-button btn-default", "data-dismiss" => "modal"
|
||||
= link_to _('Fork project'), fork_path, class: 'btn gl-button btn-confirm', data: { qa_selector: 'fork_project_button' }, method: :post
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ class UpdateHighestRoleWorker
|
|||
|
||||
return unless user.present?
|
||||
|
||||
if user.active? && user.user_type.nil? && !user.internal?
|
||||
if user.active? && user.human? && !user.internal?
|
||||
Users::UpdateHighestMemberRoleService.new(user).execute
|
||||
else
|
||||
UserHighestRole.where(user_id: user_id).delete_all
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add more attributes to the blob GraphQL API
|
||||
merge_request: 61155
|
||||
author:
|
||||
type: added
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add Gradle Kotlin installations commands
|
||||
merge_request: 60097
|
||||
author: Cromefire_ (@cromefire_)
|
||||
type: changed
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Update messages when user cannot directly push code to project
|
||||
merge_request: 61071
|
||||
author:
|
||||
type: other
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: 'GithubImport: Fix Review importer when the author does not exist anymore'
|
||||
merge_request: 61257
|
||||
author:
|
||||
type: fixed
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
# This file is created only to be able to run `derailed exec perf:mem` task
|
||||
# This task loads the whole Rails application using its own initializers
|
||||
|
|
@ -5,31 +5,28 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
type: reference, howto
|
||||
---
|
||||
|
||||
# External Pipeline Validation
|
||||
# External pipeline validation
|
||||
|
||||
You can use an external service to validate a pipeline before it's created.
|
||||
|
||||
WARNING:
|
||||
This is an experimental feature and subject to change without notice.
|
||||
|
||||
## Usage
|
||||
|
||||
GitLab sends a POST request to the external service URL with the pipeline
|
||||
data as payload. GitLab then invalidates the pipeline based on the response
|
||||
code. If there's an error or the request times out, the pipeline is not
|
||||
invalidated.
|
||||
data as payload. The response code from the external service determines if GitLab
|
||||
should accept or reject the pipeline. If the response is:
|
||||
|
||||
Response codes:
|
||||
- `200`, the pipeline is accepted.
|
||||
- `4XX`, the pipeline is rejected.
|
||||
- Other codes, the pipeline is accepted and logged.
|
||||
|
||||
- `200`: Accepted
|
||||
- `4XX`: Rejected
|
||||
- All other codes: accepted and logged
|
||||
If there's an error or the request times out, the pipeline is accepted.
|
||||
|
||||
### Service Result
|
||||
Pipelines rejected by the external validation service aren't created, and don't
|
||||
appear in pipeline lists in the GitLab UI or API. If you create a pipeline in the
|
||||
UI that is rejected, `Pipeline cannot be run. External validation failed` is displayed.
|
||||
|
||||
Pipelines rejected by the external validation service aren't created or visible in pipeline lists, in either the GitLab user interface or API. Creating an unaccepted pipeline when using the GitLab user interface displays an error message that states: `Pipeline cannot be run. External validation failed`
|
||||
|
||||
## Configuration
|
||||
## Configure external pipeline validation
|
||||
|
||||
To configure external pipeline validation, add the
|
||||
[`EXTERNAL_VALIDATION_SERVICE_URL` environment variable](environment_variables.md)
|
||||
|
|
@ -39,7 +36,7 @@ By default, requests to the external service time out after five seconds. To ove
|
|||
the default, set the `EXTERNAL_VALIDATION_SERVICE_TIMEOUT` environment variable to the
|
||||
required number of seconds.
|
||||
|
||||
## Payload Schema
|
||||
## Payload schema
|
||||
|
||||
```json
|
||||
{
|
||||
|
|
|
|||
|
|
@ -11831,9 +11831,14 @@ Returns [`Tree`](#tree).
|
|||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="repositoryblobcanmodifyblob"></a>`canModifyBlob` | [`Boolean`](#boolean) | Whether the current user can modify the blob. |
|
||||
| <a id="repositoryblobeditblobpath"></a>`editBlobPath` | [`String`](#string) | Web path to edit the blob in the old-style editor. |
|
||||
| <a id="repositoryblobexternalstorageurl"></a>`externalStorageUrl` | [`String`](#string) | Web path to download the raw blob via external storage, if enabled. |
|
||||
| <a id="repositoryblobfiletype"></a>`fileType` | [`String`](#string) | The expected format of the blob based on the extension. |
|
||||
| <a id="repositoryblobforkandeditpath"></a>`forkAndEditPath` | [`String`](#string) | Web path to edit this blob using a forked project. |
|
||||
| <a id="repositoryblobid"></a>`id` | [`ID!`](#id) | ID of the blob. |
|
||||
| <a id="repositoryblobideeditpath"></a>`ideEditPath` | [`String`](#string) | Web path to edit this blob in the Web IDE. |
|
||||
| <a id="repositoryblobideforkandeditpath"></a>`ideForkAndEditPath` | [`String`](#string) | Web path to edit this blob in the Web IDE using a forked project. |
|
||||
| <a id="repositorybloblfsoid"></a>`lfsOid` | [`String`](#string) | LFS OID of the blob. |
|
||||
| <a id="repositoryblobmode"></a>`mode` | [`String`](#string) | Blob mode. |
|
||||
| <a id="repositoryblobname"></a>`name` | [`String`](#string) | Blob name. |
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ module AfterCommitQueue
|
|||
|
||||
def run_after_commit_or_now(&block)
|
||||
if Gitlab::Database.inside_transaction?
|
||||
if ActiveRecord::Base.connection.current_transaction.records.include?(self)
|
||||
if ActiveRecord::Base.connection.current_transaction.records&.include?(self)
|
||||
run_after_commit(&block)
|
||||
else
|
||||
# If the current transaction does not include this record, we can run
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ module Gitlab
|
|||
# polluted with other unrelated errors (e.g. state machine)
|
||||
# https://gitlab.com/gitlab-org/gitlab/-/issues/220823
|
||||
pipeline.errors.add(:base, message)
|
||||
|
||||
pipeline.errors.full_messages
|
||||
end
|
||||
|
||||
def warning(message)
|
||||
|
|
|
|||
|
|
@ -36,12 +36,12 @@ module Gitlab
|
|||
def add_complementary_review_note!(author_id)
|
||||
return if review.note.empty? && !review.approval?
|
||||
|
||||
note = "*Created by %{login}*\n\n%{note}" % {
|
||||
note: review_note_content,
|
||||
login: review.author.login
|
||||
}
|
||||
note_body = MarkdownText.format(
|
||||
review_note_content,
|
||||
review.author
|
||||
)
|
||||
|
||||
add_note!(author_id, note)
|
||||
add_note!(author_id, note_body)
|
||||
end
|
||||
|
||||
def review_note_content
|
||||
|
|
|
|||
|
|
@ -19,10 +19,10 @@ module Gitlab
|
|||
end
|
||||
|
||||
def to_s
|
||||
if exists
|
||||
text
|
||||
else
|
||||
if author&.login.present? && !exists
|
||||
"*Created by: #{author.login}*\n\n#{text}"
|
||||
else
|
||||
text
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ module Gitlab
|
|||
#
|
||||
# user - An instance of `Gitlab::GithubImport::Representation::User`.
|
||||
def user_id_for(user)
|
||||
find(user.id, user.login)
|
||||
find(user.id, user.login) if user.present?
|
||||
end
|
||||
|
||||
# Returns the GitLab ID for the given GitHub ID or username.
|
||||
|
|
|
|||
|
|
@ -607,7 +607,7 @@ module Gitlab
|
|||
unique_users_all_imports: unique_users_all_imports(time_period),
|
||||
bulk_imports: {
|
||||
gitlab: DEPRECATED_VALUE,
|
||||
gitlab_v1: count(::BulkImport.where(time_period, source_type: :gitlab))
|
||||
gitlab_v1: count(::BulkImport.where(**time_period, source_type: :gitlab))
|
||||
},
|
||||
project_imports: project_imports(time_period),
|
||||
issue_imports: issue_imports(time_period),
|
||||
|
|
|
|||
|
|
@ -14265,6 +14265,15 @@ msgstr ""
|
|||
msgid "ForkProject|Want to house several dependent projects under the same namespace?"
|
||||
msgstr ""
|
||||
|
||||
msgid "ForkSuggestion|Cancel"
|
||||
msgstr ""
|
||||
|
||||
msgid "ForkSuggestion|Fork"
|
||||
msgstr ""
|
||||
|
||||
msgid "ForkSuggestion|You can’t %{edit_start}edit%{edit_end} files directly in this project. Fork this project and submit a merge request with your changes."
|
||||
msgstr ""
|
||||
|
||||
msgid "ForkedFromProjectPath|Forked from"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -23200,6 +23209,9 @@ msgstr ""
|
|||
msgid "PackageRegistry|Add Gradle Groovy DSL repository command"
|
||||
msgstr ""
|
||||
|
||||
msgid "PackageRegistry|Add Gradle Kotlin DSL repository command"
|
||||
msgstr ""
|
||||
|
||||
msgid "PackageRegistry|Add NuGet Source"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -23242,6 +23254,9 @@ msgstr ""
|
|||
msgid "PackageRegistry|Copy Gradle Groovy DSL install command"
|
||||
msgstr ""
|
||||
|
||||
msgid "PackageRegistry|Copy Gradle Kotlin DSL install command"
|
||||
msgstr ""
|
||||
|
||||
msgid "PackageRegistry|Copy Maven XML"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -23263,6 +23278,9 @@ msgstr ""
|
|||
msgid "PackageRegistry|Copy add Gradle Groovy DSL repository command"
|
||||
msgstr ""
|
||||
|
||||
msgid "PackageRegistry|Copy add Gradle Kotlin DSL repository command"
|
||||
msgstr ""
|
||||
|
||||
msgid "PackageRegistry|Copy and paste this inside your %{codeStart}pom.xml%{codeEnd} %{codeStart}dependencies%{codeEnd} block."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -23314,9 +23332,18 @@ msgstr ""
|
|||
msgid "PackageRegistry|GitLab Packages allows organizations to utilize GitLab as a private repository for a variety of common package formats. %{linkStart}More Information%{linkEnd}"
|
||||
msgstr ""
|
||||
|
||||
msgid "PackageRegistry|Gradle Groovy DSL"
|
||||
msgstr ""
|
||||
|
||||
msgid "PackageRegistry|Gradle Groovy DSL install command"
|
||||
msgstr ""
|
||||
|
||||
msgid "PackageRegistry|Gradle Kotlin DSL"
|
||||
msgstr ""
|
||||
|
||||
msgid "PackageRegistry|Gradle Kotlin DSL install command"
|
||||
msgstr ""
|
||||
|
||||
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -23341,6 +23368,9 @@ msgstr ""
|
|||
msgid "PackageRegistry|Maven Command"
|
||||
msgstr ""
|
||||
|
||||
msgid "PackageRegistry|Maven XML"
|
||||
msgstr ""
|
||||
|
||||
msgid "PackageRegistry|NuGet"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -23398,12 +23428,6 @@ msgstr ""
|
|||
msgid "PackageRegistry|Show Conan commands"
|
||||
msgstr ""
|
||||
|
||||
msgid "PackageRegistry|Show Gradle Groovy DSL commands"
|
||||
msgstr ""
|
||||
|
||||
msgid "PackageRegistry|Show Maven commands"
|
||||
msgstr ""
|
||||
|
||||
msgid "PackageRegistry|Show NPM commands"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -36135,18 +36159,18 @@ msgstr ""
|
|||
msgid "WebIDE|This project does not accept unsigned commits."
|
||||
msgstr ""
|
||||
|
||||
msgid "WebIDE|This project does not accept unsigned commits. You will not be able to commit your changes through the Web IDE."
|
||||
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
|
||||
msgstr ""
|
||||
|
||||
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
|
||||
msgstr ""
|
||||
|
||||
msgid "WebIDE|You can’t edit files directly in this project. Go to your fork and submit a merge request with your changes."
|
||||
msgstr ""
|
||||
|
||||
msgid "WebIDE|You need permission to edit files directly in this project."
|
||||
msgstr ""
|
||||
|
||||
msgid "WebIDE|You need permission to edit files directly in this project. Fork this project to make your changes and submit a merge request."
|
||||
msgstr ""
|
||||
|
||||
msgid "WebIDE|You need permission to edit files directly in this project. Go to your fork to make changes and submit a merge request."
|
||||
msgstr ""
|
||||
|
||||
msgid "WebexTeamsService|Send notifications about project events to Webex Teams."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -36959,6 +36983,9 @@ msgstr ""
|
|||
msgid "You cannot write to this read-only GitLab instance."
|
||||
msgstr ""
|
||||
|
||||
msgid "You can’t %{tag_start}edit%{tag_end} files directly in this project. Fork this project and submit a merge request with your changes."
|
||||
msgstr ""
|
||||
|
||||
msgid "You could not create a new trigger."
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
44
package.json
44
package.json
|
|
@ -59,28 +59,28 @@
|
|||
"@rails/ujs": "^6.0.3-4",
|
||||
"@sentry/browser": "^5.22.3",
|
||||
"@sourcegraph/code-host-integration": "0.0.57",
|
||||
"@tiptap/core": "^2.0.0-beta.38",
|
||||
"@tiptap/extension-blockquote": "^2.0.0-beta.6",
|
||||
"@tiptap/extension-bold": "^2.0.0-beta.6",
|
||||
"@tiptap/extension-bullet-list": "^2.0.0-beta.6",
|
||||
"@tiptap/extension-code": "^2.0.0-beta.6",
|
||||
"@tiptap/extension-code-block-lowlight": "^2.0.0-beta.9",
|
||||
"@tiptap/extension-document": "^2.0.0-beta.5",
|
||||
"@tiptap/extension-dropcursor": "^2.0.0-beta.6",
|
||||
"@tiptap/extension-gapcursor": "^2.0.0-beta.10",
|
||||
"@tiptap/extension-hard-break": "^2.0.0-beta.6",
|
||||
"@tiptap/extension-heading": "^2.0.0-beta.6",
|
||||
"@tiptap/extension-history": "^2.0.0-beta.5",
|
||||
"@tiptap/extension-horizontal-rule": "^2.0.0-beta.7",
|
||||
"@tiptap/extension-image": "^2.0.0-beta.4",
|
||||
"@tiptap/extension-italic": "^2.0.0-beta.6",
|
||||
"@tiptap/extension-link": "^2.0.0-beta.6",
|
||||
"@tiptap/extension-list-item": "^2.0.0-beta.6",
|
||||
"@tiptap/extension-ordered-list": "^2.0.0-beta.6",
|
||||
"@tiptap/extension-paragraph": "^2.0.0-beta.7",
|
||||
"@tiptap/extension-strike": "^2.0.0-beta.7",
|
||||
"@tiptap/extension-text": "^2.0.0-beta.5",
|
||||
"@tiptap/vue-2": "^2.0.0-beta.21",
|
||||
"@tiptap/core": "^2.0.0-beta.54",
|
||||
"@tiptap/extension-blockquote": "^2.0.0-beta.11",
|
||||
"@tiptap/extension-bold": "^2.0.0-beta.11",
|
||||
"@tiptap/extension-bullet-list": "^2.0.0-beta.11",
|
||||
"@tiptap/extension-code": "^2.0.0-beta.11",
|
||||
"@tiptap/extension-code-block-lowlight": "^2.0.0-beta.18",
|
||||
"@tiptap/extension-document": "^2.0.0-beta.10",
|
||||
"@tiptap/extension-dropcursor": "^2.0.0-beta.11",
|
||||
"@tiptap/extension-gapcursor": "^2.0.0-beta.15",
|
||||
"@tiptap/extension-hard-break": "^2.0.0-beta.11",
|
||||
"@tiptap/extension-heading": "^2.0.0-beta.11",
|
||||
"@tiptap/extension-history": "^2.0.0-beta.10",
|
||||
"@tiptap/extension-horizontal-rule": "^2.0.0-beta.14",
|
||||
"@tiptap/extension-image": "^2.0.0-beta.11",
|
||||
"@tiptap/extension-italic": "^2.0.0-beta.11",
|
||||
"@tiptap/extension-link": "^2.0.0-beta.15",
|
||||
"@tiptap/extension-list-item": "^2.0.0-beta.11",
|
||||
"@tiptap/extension-ordered-list": "^2.0.0-beta.11",
|
||||
"@tiptap/extension-paragraph": "^2.0.0-beta.12",
|
||||
"@tiptap/extension-strike": "^2.0.0-beta.12",
|
||||
"@tiptap/extension-text": "^2.0.0-beta.10",
|
||||
"@tiptap/vue-2": "^2.0.0-beta.27",
|
||||
"@toast-ui/editor": "^2.5.2",
|
||||
"@toast-ui/vue-editor": "^2.5.2",
|
||||
"apollo-cache-inmemory": "^1.6.6",
|
||||
|
|
|
|||
|
|
@ -131,8 +131,8 @@ RSpec.describe 'Projects > Files > User edits files', :js do
|
|||
expect(page).to have_selector(:link_or_button, 'Fork')
|
||||
expect(page).to have_selector(:link_or_button, 'Cancel')
|
||||
expect(page).to have_content(
|
||||
"You're not allowed to edit files in this project directly. "\
|
||||
"Please fork this project, make your changes there, and submit a merge request."
|
||||
"You can’t edit files directly in this project. "\
|
||||
"Fork this project and submit a merge request with your changes."
|
||||
)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -4,13 +4,25 @@ require 'spec_helper'
|
|||
|
||||
RSpec.describe 'AdditionalEmailToExistingAccount' do
|
||||
describe 'add secondary email associated with account' do
|
||||
let(:user) { create(:user) }
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:email) { create(:email, user: user) }
|
||||
|
||||
before do
|
||||
sign_in(user)
|
||||
end
|
||||
|
||||
it 'verifies confirmation of additional email' do
|
||||
sign_in(user)
|
||||
|
||||
email = create(:email, user: user)
|
||||
visit email_confirmation_path(confirmation_token: email.confirmation_token)
|
||||
|
||||
expect(page).to have_content 'Your email address has been successfully confirmed.'
|
||||
end
|
||||
|
||||
it 'accepts any pending invites for an email confirmation' do
|
||||
member = create(:group_member, :invited, invite_email: email.email)
|
||||
|
||||
visit email_confirmation_path(confirmation_token: email.confirmation_token)
|
||||
|
||||
expect(member.reload.user).to eq(user)
|
||||
expect(page).to have_content 'Your email address has been successfully confirmed.'
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@ export const locationSearch = [
|
|||
'confidential=no',
|
||||
'iteration_title=season:+%234',
|
||||
'not[iteration_title]=season:+%2320',
|
||||
'epic_id=12',
|
||||
'not[epic_id]=34',
|
||||
'weight=1',
|
||||
'not[weight]=3',
|
||||
].join('&');
|
||||
|
|
@ -24,6 +26,7 @@ export const locationSearchWithSpecialValues = [
|
|||
'assignee_id=None',
|
||||
'my_reaction_emoji=None',
|
||||
'iteration_id=Current',
|
||||
'epic_id=None',
|
||||
'weight=None',
|
||||
].join('&');
|
||||
|
||||
|
|
@ -42,6 +45,8 @@ export const filteredTokens = [
|
|||
{ type: 'confidential', value: { data: 'no', operator: OPERATOR_IS } },
|
||||
{ type: 'iteration', value: { data: 'season: #4', operator: OPERATOR_IS } },
|
||||
{ type: 'iteration', value: { data: 'season: #20', operator: OPERATOR_IS_NOT } },
|
||||
{ type: 'epic_id', value: { data: '12', operator: OPERATOR_IS } },
|
||||
{ type: 'epic_id', value: { data: '34', operator: OPERATOR_IS_NOT } },
|
||||
{ type: 'weight', value: { data: '1', operator: OPERATOR_IS } },
|
||||
{ type: 'weight', value: { data: '3', operator: OPERATOR_IS_NOT } },
|
||||
{ type: 'filtered-search-term', value: { data: 'find' } },
|
||||
|
|
@ -52,6 +57,7 @@ export const filteredTokensWithSpecialValues = [
|
|||
{ type: 'assignee_username', value: { data: 'None', operator: OPERATOR_IS } },
|
||||
{ type: 'my_reaction_emoji', value: { data: 'None', operator: OPERATOR_IS } },
|
||||
{ type: 'iteration', value: { data: 'Current', operator: OPERATOR_IS } },
|
||||
{ type: 'epic_id', value: { data: 'None', operator: OPERATOR_IS } },
|
||||
{ type: 'weight', value: { data: 'None', operator: OPERATOR_IS } },
|
||||
];
|
||||
|
||||
|
|
@ -68,6 +74,8 @@ export const apiParams = {
|
|||
confidential: 'no',
|
||||
iteration_title: 'season: #4',
|
||||
'not[iteration_title]': 'season: #20',
|
||||
epic_id: '12',
|
||||
'not[epic_id]': '34',
|
||||
weight: '1',
|
||||
'not[weight]': '3',
|
||||
};
|
||||
|
|
@ -76,6 +84,7 @@ export const apiParamsWithSpecialValues = {
|
|||
assignee_id: 'None',
|
||||
my_reaction_emoji: 'None',
|
||||
iteration_id: 'Current',
|
||||
epic_id: 'None',
|
||||
weight: 'None',
|
||||
};
|
||||
|
||||
|
|
@ -92,6 +101,8 @@ export const urlParams = {
|
|||
confidential: ['no'],
|
||||
iteration_title: ['season: #4'],
|
||||
'not[iteration_title]': ['season: #20'],
|
||||
epic_id: ['12'],
|
||||
'not[epic_id]': ['34'],
|
||||
weight: ['1'],
|
||||
'not[weight]': ['3'],
|
||||
};
|
||||
|
|
@ -100,5 +111,6 @@ export const urlParamsWithSpecialValues = {
|
|||
assignee_id: ['None'],
|
||||
my_reaction_emoji: ['None'],
|
||||
iteration_id: ['Current'],
|
||||
epic_id: ['None'],
|
||||
weight: ['None'],
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { createWrapper } from '@vue/test-utils';
|
|||
import MembersApp from '~/members/components/app.vue';
|
||||
import { MEMBER_TYPES } from '~/members/constants';
|
||||
import { initMembersApp } from '~/members/index';
|
||||
import { membersJsonString, members, paginationJsonString, pagination } from './mock_data';
|
||||
import { members, pagination, dataAttribute } from './mock_data';
|
||||
|
||||
describe('initMembersApp', () => {
|
||||
let el;
|
||||
|
|
@ -23,11 +23,7 @@ describe('initMembersApp', () => {
|
|||
|
||||
beforeEach(() => {
|
||||
el = document.createElement('div');
|
||||
el.setAttribute('data-members', membersJsonString);
|
||||
el.setAttribute('data-pagination', paginationJsonString);
|
||||
el.setAttribute('data-source-id', '234');
|
||||
el.setAttribute('data-can-manage-members', 'true');
|
||||
el.setAttribute('data-member-path', '/groups/foo-bar/-/group_members/:id');
|
||||
el.setAttribute('data-members-data', dataAttribute);
|
||||
|
||||
window.gon = { current_user_id: 123 };
|
||||
});
|
||||
|
|
|
|||
|
|
@ -80,13 +80,13 @@ export const inheritedMember = { ...member, isDirectMember: false };
|
|||
|
||||
export const member2faEnabled = { ...member, user: { ...member.user, twoFactorEnabled: true } };
|
||||
|
||||
export const paginationJsonString = JSON.stringify({
|
||||
export const paginationData = {
|
||||
current_page: 1,
|
||||
per_page: 5,
|
||||
total_items: 10,
|
||||
param_name: 'page',
|
||||
params: { search_groups: null },
|
||||
});
|
||||
};
|
||||
|
||||
export const pagination = {
|
||||
currentPage: 1,
|
||||
|
|
@ -95,3 +95,12 @@ export const pagination = {
|
|||
paramName: 'page',
|
||||
params: { search_groups: null },
|
||||
};
|
||||
|
||||
export const dataAttribute = JSON.stringify({
|
||||
members,
|
||||
pagination: paginationData,
|
||||
source_id: 234,
|
||||
can_manage_members: true,
|
||||
member_path: '/groups/foo-bar/-/group_members/:id',
|
||||
ldap_override_path: '/groups/ldap-group/-/group_members/:id/override',
|
||||
});
|
||||
|
|
|
|||
|
|
@ -20,10 +20,9 @@ import {
|
|||
member2faEnabled,
|
||||
group,
|
||||
invite,
|
||||
membersJsonString,
|
||||
members,
|
||||
paginationJsonString,
|
||||
pagination,
|
||||
dataAttribute,
|
||||
} from './mock_data';
|
||||
|
||||
const IS_CURRENT_USER_ID = 123;
|
||||
|
|
@ -260,22 +259,20 @@ describe('Members Utils', () => {
|
|||
|
||||
beforeEach(() => {
|
||||
el = document.createElement('div');
|
||||
el.setAttribute('data-members', membersJsonString);
|
||||
el.setAttribute('data-pagination', paginationJsonString);
|
||||
el.setAttribute('data-source-id', '234');
|
||||
el.setAttribute('data-can-manage-members', 'true');
|
||||
el.setAttribute('data-members-data', dataAttribute);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
el = null;
|
||||
});
|
||||
|
||||
it('correctly parses the data attributes', () => {
|
||||
expect(parseDataAttributes(el)).toEqual({
|
||||
it('correctly parses the data attribute', () => {
|
||||
expect(parseDataAttributes(el)).toMatchObject({
|
||||
members,
|
||||
pagination,
|
||||
sourceId: 234,
|
||||
canManageMembers: true,
|
||||
memberPath: '/groups/foo-bar/-/group_members/:id',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,16 +1,16 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`MavenInstallation gradle renders all the messages 1`] = `
|
||||
exports[`MavenInstallation groovy renders all the messages 1`] = `
|
||||
<div>
|
||||
<installation-title-stub
|
||||
options="[object Object],[object Object]"
|
||||
options="[object Object],[object Object],[object Object]"
|
||||
packagetype="maven"
|
||||
/>
|
||||
|
||||
<code-instruction-stub
|
||||
class="gl-mb-5"
|
||||
copytext="Copy Gradle Groovy DSL install command"
|
||||
instruction="foo/gradle/install"
|
||||
instruction="foo/gradle/groovy/install"
|
||||
label="Gradle Groovy DSL install command"
|
||||
trackingaction="copy_gradle_install_command"
|
||||
trackinglabel="code_instruction"
|
||||
|
|
@ -18,7 +18,7 @@ exports[`MavenInstallation gradle renders all the messages 1`] = `
|
|||
|
||||
<code-instruction-stub
|
||||
copytext="Copy add Gradle Groovy DSL repository command"
|
||||
instruction="foo/gradle/add/source"
|
||||
instruction="foo/gradle/groovy/add/source"
|
||||
label="Add Gradle Groovy DSL repository command"
|
||||
multiline="true"
|
||||
trackingaction="copy_gradle_add_to_source_command"
|
||||
|
|
@ -27,10 +27,37 @@ exports[`MavenInstallation gradle renders all the messages 1`] = `
|
|||
</div>
|
||||
`;
|
||||
|
||||
exports[`MavenInstallation kotlin renders all the messages 1`] = `
|
||||
<div>
|
||||
<installation-title-stub
|
||||
options="[object Object],[object Object],[object Object]"
|
||||
packagetype="maven"
|
||||
/>
|
||||
|
||||
<code-instruction-stub
|
||||
class="gl-mb-5"
|
||||
copytext="Copy Gradle Kotlin DSL install command"
|
||||
instruction="foo/gradle/kotlin/install"
|
||||
label="Gradle Kotlin DSL install command"
|
||||
trackingaction="copy_kotlin_install_command"
|
||||
trackinglabel="code_instruction"
|
||||
/>
|
||||
|
||||
<code-instruction-stub
|
||||
copytext="Copy add Gradle Kotlin DSL repository command"
|
||||
instruction="foo/gradle/kotlin/add/source"
|
||||
label="Add Gradle Kotlin DSL repository command"
|
||||
multiline="true"
|
||||
trackingaction="copy_kotlin_add_to_source_command"
|
||||
trackinglabel="code_instruction"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`MavenInstallation maven renders all the messages 1`] = `
|
||||
<div>
|
||||
<installation-title-stub
|
||||
options="[object Object],[object Object]"
|
||||
options="[object Object],[object Object],[object Object]"
|
||||
packagetype="maven"
|
||||
/>
|
||||
|
||||
|
|
|
|||
|
|
@ -17,8 +17,10 @@ describe('MavenInstallation', () => {
|
|||
const xmlCodeBlock = 'foo/xml';
|
||||
const mavenCommandStr = 'foo/command';
|
||||
const mavenSetupXml = 'foo/setup';
|
||||
const gradleGroovyInstallCommandText = 'foo/gradle/install';
|
||||
const gradleGroovyAddSourceCommandText = 'foo/gradle/add/source';
|
||||
const gradleGroovyInstallCommandText = 'foo/gradle/groovy/install';
|
||||
const gradleGroovyAddSourceCommandText = 'foo/gradle/groovy/add/source';
|
||||
const gradleKotlinInstallCommandText = 'foo/gradle/kotlin/install';
|
||||
const gradleKotlinAddSourceCommandText = 'foo/gradle/kotlin/add/source';
|
||||
|
||||
const store = new Vuex.Store({
|
||||
state: {
|
||||
|
|
@ -31,6 +33,8 @@ describe('MavenInstallation', () => {
|
|||
mavenSetupXml: () => mavenSetupXml,
|
||||
gradleGroovyInstalCommand: () => gradleGroovyInstallCommandText,
|
||||
gradleGroovyAddSourceCommand: () => gradleGroovyAddSourceCommandText,
|
||||
gradleKotlinInstalCommand: () => gradleKotlinInstallCommandText,
|
||||
gradleKotlinAddSourceCommand: () => gradleKotlinAddSourceCommandText,
|
||||
},
|
||||
});
|
||||
|
||||
|
|
@ -59,8 +63,9 @@ describe('MavenInstallation', () => {
|
|||
expect(findInstallationTitle().props()).toMatchObject({
|
||||
packageType: 'maven',
|
||||
options: [
|
||||
{ value: 'maven', label: 'Show Maven commands' },
|
||||
{ value: 'groovy', label: 'Show Gradle Groovy DSL commands' },
|
||||
{ value: 'maven', label: 'Maven XML' },
|
||||
{ value: 'groovy', label: 'Gradle Groovy DSL' },
|
||||
{ value: 'kotlin', label: 'Gradle Kotlin DSL' },
|
||||
],
|
||||
});
|
||||
});
|
||||
|
|
@ -117,9 +122,9 @@ describe('MavenInstallation', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('gradle', () => {
|
||||
describe('groovy', () => {
|
||||
beforeEach(() => {
|
||||
createComponent({ data: { instructionType: 'gradle' } });
|
||||
createComponent({ data: { instructionType: 'groovy' } });
|
||||
});
|
||||
|
||||
it('renders all the messages', () => {
|
||||
|
|
@ -146,4 +151,34 @@ describe('MavenInstallation', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('kotlin', () => {
|
||||
beforeEach(() => {
|
||||
createComponent({ data: { instructionType: 'kotlin' } });
|
||||
});
|
||||
|
||||
it('renders all the messages', () => {
|
||||
expect(wrapper.element).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe('installation commands', () => {
|
||||
it('renders the gradle install command', () => {
|
||||
expect(findCodeInstructions().at(0).props()).toMatchObject({
|
||||
instruction: gradleKotlinInstallCommandText,
|
||||
multiline: false,
|
||||
trackingAction: TrackingActions.COPY_KOTLIN_INSTALL_COMMAND,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('setup commands', () => {
|
||||
it('renders the correct gradle command', () => {
|
||||
expect(findCodeInstructions().at(1).props()).toMatchObject({
|
||||
instruction: gradleKotlinAddSourceCommandText,
|
||||
multiline: true,
|
||||
trackingAction: TrackingActions.COPY_KOTLIN_ADD_TO_SOURCE_COMMAND,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ import {
|
|||
groupExists,
|
||||
gradleGroovyInstalCommand,
|
||||
gradleGroovyAddSourceCommand,
|
||||
gradleKotlinInstalCommand,
|
||||
gradleKotlinAddSourceCommand,
|
||||
} from '~/packages/details/store/getters';
|
||||
import {
|
||||
conanPackage,
|
||||
|
|
@ -259,6 +261,24 @@ describe('Getters PackageDetails Store', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('gradle kotlin string getters', () => {
|
||||
it('gets the correct gradleKotlinInstalCommand', () => {
|
||||
setupState();
|
||||
|
||||
expect(gradleKotlinInstalCommand(state)).toMatchInlineSnapshot(
|
||||
`"implementation(\\"com.test.app:test-app:1.0-SNAPSHOT\\")"`,
|
||||
);
|
||||
});
|
||||
|
||||
it('gets the correct gradleKotlinAddSourceCommand', () => {
|
||||
setupState();
|
||||
|
||||
expect(gradleKotlinAddSourceCommand(state)).toMatchInlineSnapshot(
|
||||
`"maven(\\"foo/registry\\")"`,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('check if group', () => {
|
||||
it('is set', () => {
|
||||
setupState({ groupListUrl: '/groups/composer/-/packages' });
|
||||
|
|
|
|||
|
|
@ -139,8 +139,8 @@ export const mockEpicToken = {
|
|||
symbol: '&',
|
||||
token: EpicToken,
|
||||
operators: [{ value: '=', description: 'is', default: 'true' }],
|
||||
idProperty: 'iid',
|
||||
fetchEpics: () => Promise.resolve({ data: mockEpics }),
|
||||
fetchSingleEpic: () => Promise.resolve({ data: mockEpics[0] }),
|
||||
};
|
||||
|
||||
export const mockReactionEmojiToken = {
|
||||
|
|
|
|||
|
|
@ -68,21 +68,6 @@ describe('EpicToken', () => {
|
|||
await wrapper.vm.$nextTick();
|
||||
});
|
||||
|
||||
describe('currentValue', () => {
|
||||
it.each`
|
||||
data | id
|
||||
${`${mockEpics[0].title}::&${mockEpics[0].iid}`} | ${mockEpics[0].iid}
|
||||
${mockEpics[0].iid} | ${mockEpics[0].iid}
|
||||
${'foobar'} | ${'foobar'}
|
||||
`('$data returns $id', async ({ data, id }) => {
|
||||
wrapper.setProps({ value: { data } });
|
||||
|
||||
await wrapper.vm.$nextTick();
|
||||
|
||||
expect(wrapper.vm.currentValue).toBe(id);
|
||||
});
|
||||
});
|
||||
|
||||
describe('activeEpic', () => {
|
||||
it('returns object for currently present `value.data`', async () => {
|
||||
wrapper.setProps({
|
||||
|
|
@ -140,20 +125,6 @@ describe('EpicToken', () => {
|
|||
expect(wrapper.vm.loading).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('fetchSingleEpic', () => {
|
||||
it('calls `config.fetchSingleEpic` with provided iid param', async () => {
|
||||
jest.spyOn(wrapper.vm.config, 'fetchSingleEpic');
|
||||
|
||||
wrapper.vm.fetchSingleEpic(1);
|
||||
|
||||
expect(wrapper.vm.config.fetchSingleEpic).toHaveBeenCalledWith(1);
|
||||
|
||||
await waitForPromises();
|
||||
|
||||
expect(wrapper.vm.epics).toEqual([mockEpics[0]]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('template', () => {
|
||||
|
|
|
|||
|
|
@ -25,7 +25,12 @@ RSpec.describe Types::Repository::BlobType do
|
|||
:replace_path,
|
||||
:simple_viewer,
|
||||
:rich_viewer,
|
||||
:plain_data
|
||||
:plain_data,
|
||||
:can_modify_blob,
|
||||
:ide_edit_path,
|
||||
:external_storage_url,
|
||||
:fork_and_edit_path,
|
||||
:ide_fork_and_edit_path
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -23,122 +23,119 @@ RSpec.describe Groups::GroupMembersHelper do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#group_group_links_data_json' do
|
||||
include_context 'group_group_link'
|
||||
describe '#group_members_list_data_json' do
|
||||
let(:group_members) { create_list(:group_member, 2, group: group, created_by: current_user) }
|
||||
|
||||
it 'matches json schema' do
|
||||
json = helper.group_group_links_data_json(shared_group.shared_with_group_links)
|
||||
let(:pagination) { {} }
|
||||
let(:collection) { group_members }
|
||||
let(:presented_members) { present_members(collection) }
|
||||
|
||||
expect(json).to match_schema('group_link/group_group_links')
|
||||
end
|
||||
end
|
||||
subject { Gitlab::Json.parse(helper.group_members_list_data_json(group, presented_members, pagination)) }
|
||||
|
||||
describe '#members_data_json' do
|
||||
shared_examples 'members.json' do
|
||||
it 'matches json schema' do
|
||||
json = helper.members_data_json(group, present_members([group_member]))
|
||||
|
||||
expect(json).to match_schema('members')
|
||||
it 'returns `members` property that matches json schema' do
|
||||
expect(subject['members'].to_json).to match_schema('members')
|
||||
end
|
||||
end
|
||||
|
||||
context 'for a group member' do
|
||||
let(:group_member) { create(:group_member, group: group, created_by: current_user) }
|
||||
|
||||
it_behaves_like 'members.json'
|
||||
|
||||
context 'with user status set' do
|
||||
let(:user) { create(:user) }
|
||||
let!(:status) { create(:user_status, user: user) }
|
||||
let(:group_member) { create(:group_member, group: group, user: user, created_by: current_user) }
|
||||
|
||||
it_behaves_like 'members.json'
|
||||
end
|
||||
end
|
||||
|
||||
context 'for an invited group member' do
|
||||
let(:group_member) { create(:group_member, :invited, group: group, created_by: current_user) }
|
||||
|
||||
it_behaves_like 'members.json'
|
||||
end
|
||||
|
||||
context 'for an access request' do
|
||||
let(:group_member) { create(:group_member, :access_request, group: group, created_by: current_user) }
|
||||
|
||||
it_behaves_like 'members.json'
|
||||
end
|
||||
end
|
||||
|
||||
describe '#group_members_list_data_attributes' do
|
||||
let_it_be(:group_members) { create_list(:group_member, 2, group: group, created_by: current_user) }
|
||||
|
||||
before do
|
||||
allow(helper).to receive(:group_group_member_path).with(group, ':id').and_return('/groups/foo-bar/-/group_members/:id')
|
||||
allow(helper).to receive(:can?).with(current_user, :admin_group_member, group).and_return(true)
|
||||
end
|
||||
|
||||
it 'returns expected hash' do
|
||||
expect(helper.group_members_list_data_attributes(group, present_members(group_members))).to include({
|
||||
members: helper.members_data_json(group, present_members(group_members)),
|
||||
it 'returns expected json' do
|
||||
expected = {
|
||||
member_path: '/groups/foo-bar/-/group_members/:id',
|
||||
source_id: group.id,
|
||||
can_manage_members: 'true'
|
||||
})
|
||||
can_manage_members: true
|
||||
}.as_json
|
||||
|
||||
expect(subject).to include(expected)
|
||||
end
|
||||
|
||||
context 'for a group member' do
|
||||
it_behaves_like 'members.json'
|
||||
|
||||
context 'with user status set' do
|
||||
let(:user) { create(:user) }
|
||||
let!(:status) { create(:user_status, user: user) }
|
||||
let(:group_members) { [create(:group_member, group: group, user: user, created_by: current_user)] }
|
||||
|
||||
it_behaves_like 'members.json'
|
||||
end
|
||||
end
|
||||
|
||||
context 'for an invited group member' do
|
||||
let(:group_members) { create_list(:group_member, 2, :invited, group: group, created_by: current_user) }
|
||||
|
||||
it_behaves_like 'members.json'
|
||||
end
|
||||
|
||||
context 'for an access request' do
|
||||
let(:group_members) { create_list(:group_member, 2, :access_request, group: group, created_by: current_user) }
|
||||
|
||||
it_behaves_like 'members.json'
|
||||
end
|
||||
|
||||
context 'when pagination is not available' do
|
||||
it 'sets `pagination` attribute to expected json' do
|
||||
expect(helper.group_members_list_data_attributes(group, present_members(group_members))[:pagination]).to match({
|
||||
expected = {
|
||||
current_page: nil,
|
||||
per_page: nil,
|
||||
total_items: 2,
|
||||
param_name: nil,
|
||||
params: {}
|
||||
}.to_json)
|
||||
}.as_json
|
||||
|
||||
expect(subject['pagination']).to include(expected)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when pagination is available' do
|
||||
let(:collection) { Kaminari.paginate_array(group_members).page(1).per(1) }
|
||||
let(:pagination) { { param_name: :page, params: { search_groups: nil } } }
|
||||
|
||||
it 'sets `pagination` attribute to expected json' do
|
||||
expect(
|
||||
helper.group_members_list_data_attributes(
|
||||
group,
|
||||
present_members(collection),
|
||||
{ param_name: :page, params: { search_groups: nil } }
|
||||
)[:pagination]
|
||||
).to match({
|
||||
expected = {
|
||||
current_page: 1,
|
||||
per_page: 1,
|
||||
total_items: 2,
|
||||
param_name: :page,
|
||||
params: { search_groups: nil }
|
||||
}.to_json)
|
||||
}.as_json
|
||||
|
||||
expect(subject['pagination']).to include(expected)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#group_group_links_list_data_attributes' do
|
||||
describe '#group_group_links_list_data_json' do
|
||||
include_context 'group_group_link'
|
||||
|
||||
subject { Gitlab::Json.parse(helper.group_group_links_list_data_json(shared_group)) }
|
||||
|
||||
before do
|
||||
allow(helper).to receive(:group_group_link_path).with(shared_group, ':id').and_return('/groups/foo-bar/-/group_links/:id')
|
||||
end
|
||||
|
||||
it 'returns expected hash' do
|
||||
expect(helper.group_group_links_list_data_attributes(shared_group)).to include({
|
||||
it 'returns expected json' do
|
||||
expected = {
|
||||
pagination: {
|
||||
current_page: nil,
|
||||
per_page: nil,
|
||||
total_items: 1,
|
||||
param_name: nil,
|
||||
params: {}
|
||||
}.to_json,
|
||||
members: helper.group_group_links_data_json(shared_group.shared_with_group_links),
|
||||
},
|
||||
member_path: '/groups/foo-bar/-/group_links/:id',
|
||||
source_id: shared_group.id
|
||||
})
|
||||
}.as_json
|
||||
|
||||
expect(subject).to include(expected)
|
||||
end
|
||||
|
||||
it 'returns `members` property that matches json schema' do
|
||||
expect(subject['members'].to_json).to match_schema('group_link/group_group_links')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -149,57 +149,61 @@ RSpec.describe Projects::ProjectMembersHelper do
|
|||
describe 'project members' do
|
||||
let_it_be(:project_members) { create_list(:project_member, 2, project: project) }
|
||||
|
||||
describe '#project_members_data_json' do
|
||||
it 'matches json schema' do
|
||||
expect(helper.project_members_data_json(project, present_members(project_members))).to match_schema('members')
|
||||
end
|
||||
end
|
||||
let(:collection) { project_members }
|
||||
let(:presented_members) { present_members(collection) }
|
||||
|
||||
describe '#project_members_list_data_attributes' do
|
||||
describe '#project_members_list_data_json' do
|
||||
let(:allow_admin_project) { true }
|
||||
let(:pagination) { {} }
|
||||
|
||||
subject { Gitlab::Json.parse(helper.project_members_list_data_json(project, presented_members, pagination)) }
|
||||
|
||||
before do
|
||||
allow(helper).to receive(:project_project_member_path).with(project, ':id').and_return('/foo-bar/-/project_members/:id')
|
||||
end
|
||||
|
||||
it 'returns expected hash' do
|
||||
expect(helper.project_members_list_data_attributes(project, present_members(project_members))).to include({
|
||||
members: helper.project_members_data_json(project, present_members(project_members)),
|
||||
it 'returns expected json' do
|
||||
expected = {
|
||||
member_path: '/foo-bar/-/project_members/:id',
|
||||
source_id: project.id,
|
||||
can_manage_members: 'true'
|
||||
})
|
||||
can_manage_members: true
|
||||
}.as_json
|
||||
|
||||
expect(subject).to include(expected)
|
||||
end
|
||||
|
||||
it 'returns `members` property that matches json schema' do
|
||||
expect(subject['members'].to_json).to match_schema('members')
|
||||
end
|
||||
|
||||
context 'when pagination is not available' do
|
||||
it 'sets `pagination` attribute to expected json' do
|
||||
expect(helper.project_members_list_data_attributes(project, present_members(project_members))[:pagination]).to match({
|
||||
expected = {
|
||||
current_page: nil,
|
||||
per_page: nil,
|
||||
total_items: 2,
|
||||
param_name: nil,
|
||||
params: {}
|
||||
}.to_json)
|
||||
}.as_json
|
||||
|
||||
expect(subject['pagination']).to include(expected)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when pagination is available' do
|
||||
let(:collection) { Kaminari.paginate_array(project_members).page(1).per(1) }
|
||||
let(:pagination) { { param_name: :page, params: { search_groups: nil } } }
|
||||
|
||||
it 'sets `pagination` attribute to expected json' do
|
||||
expect(
|
||||
helper.project_members_list_data_attributes(
|
||||
project,
|
||||
present_members(collection),
|
||||
{ param_name: :page, params: { search_groups: nil } }
|
||||
)[:pagination]
|
||||
).to match({
|
||||
expected = {
|
||||
current_page: 1,
|
||||
per_page: 1,
|
||||
total_items: 2,
|
||||
param_name: :page,
|
||||
params: { search_groups: nil }
|
||||
}.to_json)
|
||||
}.as_json
|
||||
|
||||
expect(subject['pagination']).to match(expected)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -210,32 +214,33 @@ RSpec.describe Projects::ProjectMembersHelper do
|
|||
|
||||
let(:allow_admin_project) { true }
|
||||
|
||||
describe '#project_group_links_data_json' do
|
||||
it 'matches json schema' do
|
||||
expect(helper.project_group_links_data_json(project_group_links)).to match_schema('group_link/project_group_links')
|
||||
end
|
||||
end
|
||||
describe '#project_group_links_list_data_json' do
|
||||
subject { Gitlab::Json.parse(helper.project_group_links_list_data_json(project, project_group_links)) }
|
||||
|
||||
describe '#project_group_links_list_data_attributes' do
|
||||
before do
|
||||
allow(helper).to receive(:project_group_link_path).with(project, ':id').and_return('/foo-bar/-/group_links/:id')
|
||||
allow(helper).to receive(:can?).with(current_user, :admin_project_member, project).and_return(true)
|
||||
end
|
||||
|
||||
it 'returns expected hash' do
|
||||
expect(helper.project_group_links_list_data_attributes(project, project_group_links)).to include({
|
||||
members: helper.project_group_links_data_json(project_group_links),
|
||||
it 'returns expected json' do
|
||||
expected = {
|
||||
pagination: {
|
||||
current_page: nil,
|
||||
per_page: nil,
|
||||
total_items: 1,
|
||||
param_name: nil,
|
||||
params: {}
|
||||
}.to_json,
|
||||
},
|
||||
member_path: '/foo-bar/-/group_links/:id',
|
||||
source_id: project.id,
|
||||
can_manage_members: 'true'
|
||||
})
|
||||
can_manage_members: true
|
||||
}.as_json
|
||||
|
||||
expect(subject).to include(expected)
|
||||
end
|
||||
|
||||
it 'returns `members` property that matches json schema' do
|
||||
expect(subject['members'].to_json).to match_schema('group_link/project_group_links')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@ RSpec.describe Gitlab::GithubImport::Importer::PullRequestReviewImporter, :clean
|
|||
.to change(Note, :count).by(1)
|
||||
|
||||
last_note = merge_request.notes.last
|
||||
expect(last_note.note).to eq("*Created by author*\n\n**Review:** Approved")
|
||||
expect(last_note.note).to eq("*Created by: author*\n\n**Review:** Approved")
|
||||
expect(last_note.author).to eq(project.creator)
|
||||
expect(last_note.created_at).to eq(submitted_at)
|
||||
end
|
||||
|
|
@ -153,6 +153,20 @@ RSpec.describe Gitlab::GithubImport::Importer::PullRequestReviewImporter, :clean
|
|||
end
|
||||
end
|
||||
|
||||
context 'when original author was deleted in github' do
|
||||
let(:review) { create_review(type: 'APPROVED', note: '', author: nil) }
|
||||
|
||||
it 'creates a note for the review without the author information' do
|
||||
expect { subject.execute }
|
||||
.to change(Note, :count).by(1)
|
||||
|
||||
last_note = merge_request.notes.last
|
||||
expect(last_note.note).to eq('**Review:** Approved')
|
||||
expect(last_note.author).to eq(project.creator)
|
||||
expect(last_note.created_at).to eq(submitted_at)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the review has a note text' do
|
||||
context 'when the review is "APPROVED"' do
|
||||
let(:review) { create_review(type: 'APPROVED') }
|
||||
|
|
@ -163,7 +177,7 @@ RSpec.describe Gitlab::GithubImport::Importer::PullRequestReviewImporter, :clean
|
|||
|
||||
last_note = merge_request.notes.last
|
||||
|
||||
expect(last_note.note).to eq("*Created by author*\n\n**Review:** Approved\n\nnote")
|
||||
expect(last_note.note).to eq("*Created by: author*\n\n**Review:** Approved\n\nnote")
|
||||
expect(last_note.author).to eq(project.creator)
|
||||
expect(last_note.created_at).to eq(submitted_at)
|
||||
end
|
||||
|
|
@ -178,7 +192,7 @@ RSpec.describe Gitlab::GithubImport::Importer::PullRequestReviewImporter, :clean
|
|||
|
||||
last_note = merge_request.notes.last
|
||||
|
||||
expect(last_note.note).to eq("*Created by author*\n\n**Review:** Commented\n\nnote")
|
||||
expect(last_note.note).to eq("*Created by: author*\n\n**Review:** Commented\n\nnote")
|
||||
expect(last_note.author).to eq(project.creator)
|
||||
expect(last_note.created_at).to eq(submitted_at)
|
||||
end
|
||||
|
|
@ -193,7 +207,7 @@ RSpec.describe Gitlab::GithubImport::Importer::PullRequestReviewImporter, :clean
|
|||
|
||||
last_note = merge_request.notes.last
|
||||
|
||||
expect(last_note.note).to eq("*Created by author*\n\n**Review:** Changes requested\n\nnote")
|
||||
expect(last_note.note).to eq("*Created by: author*\n\n**Review:** Changes requested\n\nnote")
|
||||
expect(last_note.author).to eq(project.creator)
|
||||
expect(last_note.created_at).to eq(submitted_at)
|
||||
end
|
||||
|
|
@ -201,13 +215,13 @@ RSpec.describe Gitlab::GithubImport::Importer::PullRequestReviewImporter, :clean
|
|||
end
|
||||
end
|
||||
|
||||
def create_review(type:, note: 'note')
|
||||
def create_review(type:, note: 'note', author: { id: 999, login: 'author' })
|
||||
Gitlab::GithubImport::Representation::PullRequestReview.from_json_hash(
|
||||
merge_request_id: merge_request.id,
|
||||
review_type: type,
|
||||
note: note,
|
||||
submitted_at: submitted_at.to_s,
|
||||
author: { id: 999, login: 'author' }
|
||||
author: author
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -61,6 +61,10 @@ RSpec.describe Gitlab::GithubImport::UserFinder, :clean_gitlab_redis_cache do
|
|||
expect(finder).to receive(:find).with(user.id, user.login).and_return(42)
|
||||
expect(finder.user_id_for(user)).to eq(42)
|
||||
end
|
||||
|
||||
it 'does not fail with empty input' do
|
||||
expect(finder.user_id_for(nil)).to eq(nil)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#find' do
|
||||
|
|
|
|||
|
|
@ -44,12 +44,11 @@ RSpec.describe Email do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'delegation' do
|
||||
let(:user) { create(:user) }
|
||||
|
||||
it 'delegates to :user' do
|
||||
expect(build(:email, user: user).username).to eq user.username
|
||||
end
|
||||
describe 'delegations' do
|
||||
it { is_expected.to delegate_method(:can?).to(:user) }
|
||||
it { is_expected.to delegate_method(:username).to(:user) }
|
||||
it { is_expected.to delegate_method(:pending_invitations).to(:user) }
|
||||
it { is_expected.to delegate_method(:accept_pending_invitations!).to(:user) }
|
||||
end
|
||||
|
||||
describe 'Devise emails' do
|
||||
|
|
|
|||
|
|
@ -100,7 +100,8 @@ RSpec.describe InternalId do
|
|||
|
||||
context 'when executed outside of transaction' do
|
||||
it 'increments counter with in_transaction: "false"' do
|
||||
expect(ActiveRecord::Base.connection).to receive(:transaction_open?) { false }
|
||||
allow(ActiveRecord::Base.connection).to receive(:transaction_open?) { false }
|
||||
|
||||
expect(InternalId::InternalIdGenerator.internal_id_transactions_total).to receive(:increment)
|
||||
.with(operation: :generate, usage: 'issues', in_transaction: 'false').and_call_original
|
||||
|
||||
|
|
@ -158,7 +159,8 @@ RSpec.describe InternalId do
|
|||
let(:value) { 2 }
|
||||
|
||||
it 'increments counter with in_transaction: "false"' do
|
||||
expect(ActiveRecord::Base.connection).to receive(:transaction_open?) { false }
|
||||
allow(ActiveRecord::Base.connection).to receive(:transaction_open?) { false }
|
||||
|
||||
expect(InternalId::InternalIdGenerator.internal_id_transactions_total).to receive(:increment)
|
||||
.with(operation: :reset, usage: 'issues', in_transaction: 'false').and_call_original
|
||||
|
||||
|
|
@ -228,7 +230,8 @@ RSpec.describe InternalId do
|
|||
|
||||
context 'when executed outside of transaction' do
|
||||
it 'increments counter with in_transaction: "false"' do
|
||||
expect(ActiveRecord::Base.connection).to receive(:transaction_open?) { false }
|
||||
allow(ActiveRecord::Base.connection).to receive(:transaction_open?) { false }
|
||||
|
||||
expect(InternalId::InternalIdGenerator.internal_id_transactions_total).to receive(:increment)
|
||||
.with(operation: :track_greatest, usage: 'issues', in_transaction: 'false').and_call_original
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,11 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Packages::PackageFile, type: :model do
|
||||
let_it_be(:project) { create(:project) }
|
||||
let_it_be(:package_file1) { create(:package_file, :xml, file_name: 'FooBar') }
|
||||
let_it_be(:package_file2) { create(:package_file, :xml, file_name: 'ThisIsATest') }
|
||||
let_it_be(:debian_package) { create(:debian_package, project: project) }
|
||||
|
||||
describe 'relationships' do
|
||||
it { is_expected.to belong_to(:package) }
|
||||
it { is_expected.to have_one(:conan_file_metadatum) }
|
||||
|
|
@ -16,9 +21,6 @@ RSpec.describe Packages::PackageFile, type: :model do
|
|||
end
|
||||
|
||||
context 'with package filenames' do
|
||||
let_it_be(:package_file1) { create(:package_file, :xml, file_name: 'FooBar') }
|
||||
let_it_be(:package_file2) { create(:package_file, :xml, file_name: 'ThisIsATest') }
|
||||
|
||||
describe '.with_file_name' do
|
||||
let(:filename) { 'FooBar' }
|
||||
|
||||
|
|
@ -52,6 +54,13 @@ RSpec.describe Packages::PackageFile, type: :model do
|
|||
end
|
||||
end
|
||||
|
||||
describe '.for_package_ids' do
|
||||
it 'returns matching packages' do
|
||||
expect(described_class.for_package_ids([package_file1.package.id, package_file2.package.id]))
|
||||
.to contain_exactly(package_file1, package_file2)
|
||||
end
|
||||
end
|
||||
|
||||
describe '.with_conan_package_reference' do
|
||||
let_it_be(:non_matching_package_file) { create(:package_file, :nuget) }
|
||||
let_it_be(:metadatum) { create(:conan_file_metadatum, :package_file) }
|
||||
|
|
@ -64,7 +73,6 @@ RSpec.describe Packages::PackageFile, type: :model do
|
|||
end
|
||||
|
||||
describe '.for_rubygem_with_file_name' do
|
||||
let_it_be(:project) { create(:project) }
|
||||
let_it_be(:non_ruby_package) { create(:nuget_package, project: project, package_type: :nuget) }
|
||||
let_it_be(:ruby_package) { create(:rubygems_package, project: project, package_type: :rubygems) }
|
||||
let_it_be(:file_name) { 'other.gem' }
|
||||
|
|
@ -78,6 +86,36 @@ RSpec.describe Packages::PackageFile, type: :model do
|
|||
end
|
||||
end
|
||||
|
||||
context 'Debian scopes' do
|
||||
let_it_be(:debian_changes) { debian_package.package_files.last }
|
||||
let_it_be(:debian_deb) { create(:debian_package_file, package: debian_package)}
|
||||
let_it_be(:debian_udeb) { create(:debian_package_file, :udeb, package: debian_package)}
|
||||
|
||||
let_it_be(:debian_contrib) do
|
||||
create(:debian_package_file, package: debian_package).tap do |pf|
|
||||
pf.debian_file_metadatum.update!(component: 'contrib')
|
||||
end
|
||||
end
|
||||
|
||||
let_it_be(:debian_mipsel) do
|
||||
create(:debian_package_file, package: debian_package).tap do |pf|
|
||||
pf.debian_file_metadatum.update!(architecture: 'mipsel')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#with_debian_file_type' do
|
||||
it { expect(described_class.with_debian_file_type(:changes)).to contain_exactly(debian_changes) }
|
||||
end
|
||||
|
||||
describe '#with_debian_component_name' do
|
||||
it { expect(described_class.with_debian_component_name('contrib')).to contain_exactly(debian_contrib) }
|
||||
end
|
||||
|
||||
describe '#with_debian_architecture_name' do
|
||||
it { expect(described_class.with_debian_architecture_name('mipsel')).to contain_exactly(debian_mipsel) }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#update_file_store callback' do
|
||||
let_it_be(:package_file) { build(:package_file, :nuget, size: nil) }
|
||||
|
||||
|
|
|
|||
|
|
@ -4,11 +4,12 @@ require 'spec_helper'
|
|||
|
||||
RSpec.describe BlobPresenter do
|
||||
let_it_be(:project) { create(:project, :repository) }
|
||||
let_it_be(:user) { project.owner }
|
||||
|
||||
let(:repository) { project.repository }
|
||||
let(:blob) { repository.blob_at('HEAD', 'files/ruby/regex.rb') }
|
||||
|
||||
subject(:presenter) { described_class.new(blob) }
|
||||
subject(:presenter) { described_class.new(blob, current_user: user) }
|
||||
|
||||
describe '#web_url' do
|
||||
it { expect(presenter.web_url).to eq("http://localhost/#{project.full_path}/-/blob/#{blob.commit_id}/#{blob.path}") }
|
||||
|
|
@ -30,6 +31,42 @@ RSpec.describe BlobPresenter do
|
|||
it { expect(presenter.replace_path).to eq("/#{project.full_path}/-/create/#{blob.commit_id}/#{blob.path}") }
|
||||
end
|
||||
|
||||
describe '#ide_edit_path' do
|
||||
it { expect(presenter.ide_edit_path).to eq("/-/ide/project/#{project.full_path}/edit/HEAD/-/files/ruby/regex.rb") }
|
||||
end
|
||||
|
||||
describe '#fork_and_edit_path' do
|
||||
it 'generates expected URI + query' do
|
||||
uri = URI.parse(presenter.fork_and_edit_path)
|
||||
query = Rack::Utils.parse_query(uri.query)
|
||||
|
||||
expect(uri.path).to eq("/#{project.full_path}/-/forks")
|
||||
expect(query).to include('continue[to]' => presenter.edit_blob_path, 'namespace_key' => user.namespace_id.to_s)
|
||||
end
|
||||
|
||||
context 'current_user is nil' do
|
||||
let(:user) { nil }
|
||||
|
||||
it { expect(presenter.fork_and_edit_path).to be_nil }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#ide_fork_and_edit_path' do
|
||||
it 'generates expected URI + query' do
|
||||
uri = URI.parse(presenter.ide_fork_and_edit_path)
|
||||
query = Rack::Utils.parse_query(uri.query)
|
||||
|
||||
expect(uri.path).to eq("/#{project.full_path}/-/forks")
|
||||
expect(query).to include('continue[to]' => presenter.ide_edit_path, 'namespace_key' => user.namespace_id.to_s)
|
||||
end
|
||||
|
||||
context 'current_user is nil' do
|
||||
let(:user) { nil }
|
||||
|
||||
it { expect(presenter.ide_fork_and_edit_path).to be_nil }
|
||||
end
|
||||
end
|
||||
|
||||
context 'given a Gitlab::Graphql::Representation::TreeEntry' do
|
||||
let(:blob) { Gitlab::Graphql::Representation::TreeEntry.new(super(), repository) }
|
||||
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
|
|||
request
|
||||
|
||||
expect(response).to have_gitlab_http_status(:bad_request)
|
||||
expect(json_response['message']).to include('runner_projects' => ['is invalid'])
|
||||
expect(json_response['message']).to include('runner_projects.base' => ['Maximum number of ci registered project runners (1) exceeded'])
|
||||
expect(project.runners.reload.size).to eq(1)
|
||||
end
|
||||
end
|
||||
|
|
@ -143,7 +143,7 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
|
|||
request
|
||||
|
||||
expect(response).to have_gitlab_http_status(:bad_request)
|
||||
expect(json_response['message']).to include('runner_namespaces' => ['is invalid'])
|
||||
expect(json_response['message']).to include('runner_namespaces.base' => ['Maximum number of ci registered group runners (1) exceeded'])
|
||||
expect(group.runners.reload.size).to eq(1)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,182 @@
|
|||
# frozen_string_literal: true
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Packages::Debian::GenerateDistributionService do
|
||||
let_it_be(:group) { create(:group, :public) }
|
||||
let_it_be(:project) { create(:project, :public, group: group) }
|
||||
let_it_be(:project_distribution) { create("debian_project_distribution", container: project, codename: 'unstable', valid_time_duration_seconds: 48.hours.to_i) }
|
||||
|
||||
let_it_be(:incoming) { create(:debian_incoming, project: project) }
|
||||
|
||||
before_all do
|
||||
::Packages::Debian::ProcessChangesService.new(incoming.package_files.last, nil).execute
|
||||
end
|
||||
|
||||
let(:service) { described_class.new(distribution) }
|
||||
|
||||
describe '#execute' do
|
||||
subject { service.execute }
|
||||
|
||||
shared_examples 'Generate Distribution' do |container_type|
|
||||
context "for #{container_type}" do
|
||||
if container_type == :group
|
||||
let_it_be(:container) { group }
|
||||
let_it_be(:distribution, reload: true) { create('debian_group_distribution', container: group, codename: 'unstable', valid_time_duration_seconds: 48.hours.to_i) }
|
||||
else
|
||||
let_it_be(:container) { project }
|
||||
let_it_be(:distribution, reload: true) { project_distribution }
|
||||
end
|
||||
|
||||
context 'with components and architectures' do
|
||||
let_it_be(:component_main ) { create("debian_#{container_type}_component", distribution: distribution, name: 'main') }
|
||||
let_it_be(:component_contrib) { create("debian_#{container_type}_component", distribution: distribution, name: 'contrib') }
|
||||
|
||||
let_it_be(:architecture_all ) { create("debian_#{container_type}_architecture", distribution: distribution, name: 'all') }
|
||||
let_it_be(:architecture_amd64) { create("debian_#{container_type}_architecture", distribution: distribution, name: 'amd64') }
|
||||
let_it_be(:architecture_arm64) { create("debian_#{container_type}_architecture", distribution: distribution, name: 'arm64') }
|
||||
|
||||
let_it_be(:component_file1) { create("debian_#{container_type}_component_file", component: component_main, architecture: architecture_all, created_at: '2020-01-24T09:00:00.000Z') } # destroyed
|
||||
let_it_be(:component_file2) { create("debian_#{container_type}_component_file", component: component_main, architecture: architecture_amd64, created_at: '2020-01-24T10:29:59.000Z') } # destroyed
|
||||
let_it_be(:component_file3) { create("debian_#{container_type}_component_file", component: component_contrib, architecture: architecture_all, created_at: '2020-01-24T10:30:00.000Z') } # kept
|
||||
let_it_be(:component_file4) { create("debian_#{container_type}_component_file", component: component_contrib, architecture: architecture_amd64, created_at: '2020-01-24T11:30:00.000Z') } # kept
|
||||
|
||||
def check_component_file(component_name, component_file_type, architecture_name, expected_content)
|
||||
component_file = distribution
|
||||
.component_files
|
||||
.with_component_name(component_name)
|
||||
.with_file_type(component_file_type)
|
||||
.with_architecture_name(architecture_name)
|
||||
.last
|
||||
|
||||
expect(component_file).not_to be_nil
|
||||
expect(component_file.file.exists?).to eq(!expected_content.nil?)
|
||||
|
||||
unless expected_content.nil?
|
||||
component_file.file.use_file do |file_path|
|
||||
expect(File.read(file_path)).to eq(expected_content)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it 'updates distribution and component files', :aggregate_failures do
|
||||
travel_to(Time.utc(2020, 01, 25, 15, 17, 18, 123456)) do
|
||||
expect(Gitlab::ErrorTracking).not_to receive(:log_exception)
|
||||
|
||||
expect { subject }
|
||||
.to not_change { Packages::Package.count }
|
||||
.and not_change { Packages::PackageFile.count }
|
||||
.and change { distribution.component_files.count }.from(4).to(2 + 6)
|
||||
|
||||
expected_main_amd64_content = <<~EOF
|
||||
Package: libsample0
|
||||
Source: sample
|
||||
Version: 1.2.3~alpha2
|
||||
Installed-Size: 7
|
||||
Maintainer: John Doe <john.doe@example.com>
|
||||
Architecture: amd64
|
||||
Description: Some mostly empty lib
|
||||
Used in GitLab tests.
|
||||
.
|
||||
Testing another paragraph.
|
||||
Multi-Arch: same
|
||||
Homepage: https://gitlab.com/
|
||||
Section: libs
|
||||
Priority: optional
|
||||
Filename: pool/unstable/#{project.id}/s/sample/libsample0_1.2.3~alpha2_amd64.deb
|
||||
Size: 409600
|
||||
MD5sum: fb0842b21adc44207996296fe14439dd
|
||||
SHA256: 1c383a525bfcba619c7305ccd106d61db501a6bbaf0003bf8d0c429fbdb7fcc1
|
||||
|
||||
Package: sample-dev
|
||||
Source: sample (1.2.3~alpha2)
|
||||
Version: 1.2.3~binary
|
||||
Installed-Size: 7
|
||||
Maintainer: John Doe <john.doe@example.com>
|
||||
Architecture: amd64
|
||||
Depends: libsample0 (= 1.2.3~binary)
|
||||
Description: Some mostly empty developpement files
|
||||
Used in GitLab tests.
|
||||
.
|
||||
Testing another paragraph.
|
||||
Multi-Arch: same
|
||||
Homepage: https://gitlab.com/
|
||||
Section: libdevel
|
||||
Priority: optional
|
||||
Filename: pool/unstable/#{project.id}/s/sample/sample-dev_1.2.3~binary_amd64.deb
|
||||
Size: 409600
|
||||
MD5sum: d2afbd28e4d74430d22f9504e18bfdf5
|
||||
SHA256: 9fbeee2191ce4dab5288fad5ecac1bd369f58fef9a992a880eadf0caf25f086d
|
||||
EOF
|
||||
|
||||
check_component_file('main', :packages, 'all', nil)
|
||||
check_component_file('main', :packages, 'amd64', expected_main_amd64_content)
|
||||
check_component_file('main', :packages, 'arm64', nil)
|
||||
|
||||
check_component_file('contrib', :packages, 'all', nil)
|
||||
check_component_file('contrib', :packages, 'amd64', nil)
|
||||
check_component_file('contrib', :packages, 'arm64', nil)
|
||||
|
||||
size = expected_main_amd64_content.length
|
||||
md5sum = Digest::MD5.hexdigest(expected_main_amd64_content)
|
||||
sha256 = Digest::SHA256.hexdigest(expected_main_amd64_content)
|
||||
|
||||
expected_release_content = <<~EOF
|
||||
Codename: unstable
|
||||
Date: Sat, 25 Jan 2020 15:17:18 +0000
|
||||
Valid-Until: Mon, 27 Jan 2020 15:17:18 +0000
|
||||
Architectures: all amd64 arm64
|
||||
Components: contrib main
|
||||
MD5Sum:
|
||||
d41d8cd98f00b204e9800998ecf8427e 0 contrib/binary-all/Packages
|
||||
d41d8cd98f00b204e9800998ecf8427e 0 contrib/binary-amd64/Packages
|
||||
d41d8cd98f00b204e9800998ecf8427e 0 contrib/binary-arm64/Packages
|
||||
d41d8cd98f00b204e9800998ecf8427e 0 main/binary-all/Packages
|
||||
#{md5sum} #{size} main/binary-amd64/Packages
|
||||
d41d8cd98f00b204e9800998ecf8427e 0 main/binary-arm64/Packages
|
||||
SHA256:
|
||||
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 contrib/binary-all/Packages
|
||||
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 contrib/binary-amd64/Packages
|
||||
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 contrib/binary-arm64/Packages
|
||||
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 main/binary-all/Packages
|
||||
#{sha256} #{size} main/binary-amd64/Packages
|
||||
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 main/binary-arm64/Packages
|
||||
EOF
|
||||
|
||||
distribution.file.use_file do |file_path|
|
||||
expect(File.read(file_path)).to eq(expected_release_content)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'without components and architectures' do
|
||||
it 'updates distribution and component files', :aggregate_failures do
|
||||
travel_to(Time.utc(2020, 01, 25, 15, 17, 18, 123456)) do
|
||||
expect(Gitlab::ErrorTracking).not_to receive(:log_exception)
|
||||
|
||||
expect { subject }
|
||||
.to not_change { Packages::Package.count }
|
||||
.and not_change { Packages::PackageFile.count }
|
||||
.and not_change { distribution.component_files.count }
|
||||
|
||||
expected_release_content = <<~EOF
|
||||
Codename: unstable
|
||||
Date: Sat, 25 Jan 2020 15:17:18 +0000
|
||||
Valid-Until: Mon, 27 Jan 2020 15:17:18 +0000
|
||||
MD5Sum:
|
||||
SHA256:
|
||||
EOF
|
||||
|
||||
distribution.file.use_file do |file_path|
|
||||
expect(File.read(file_path)).to eq(expected_release_content)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it_behaves_like 'Generate Distribution', :project
|
||||
it_behaves_like 'Generate Distribution', :group
|
||||
end
|
||||
end
|
||||
|
|
@ -179,7 +179,7 @@ RSpec.describe Users::BuildService do
|
|||
params.merge!({ user_type: :project_bot })
|
||||
end
|
||||
|
||||
it { expect(user.project_bot?).to be true}
|
||||
it { expect(user.project_bot?).to be true }
|
||||
end
|
||||
|
||||
context 'when not a project_bot' do
|
||||
|
|
@ -187,7 +187,7 @@ RSpec.describe Users::BuildService do
|
|||
params.merge!({ user_type: :alert_bot })
|
||||
end
|
||||
|
||||
it { expect(user.user_type).to be nil }
|
||||
it { expect(user).to be_human }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.shared_examples 'Debian Distribution Architecture' do |factory, container, can_freeze|
|
||||
let_it_be_with_refind(:architecture) { create(factory) } # rubocop:disable Rails/SaveBang
|
||||
let_it_be(:architecture_same_distribution, freeze: can_freeze) { create(factory, distribution: architecture.distribution) }
|
||||
let_it_be_with_refind(:architecture) { create(factory, name: 'name1') }
|
||||
let_it_be(:architecture_same_distribution, freeze: can_freeze) { create(factory, distribution: architecture.distribution, name: 'name2') }
|
||||
let_it_be(:architecture_same_name, freeze: can_freeze) { create(factory, name: architecture.name) }
|
||||
|
||||
subject { architecture }
|
||||
|
|
@ -30,20 +30,22 @@ RSpec.shared_examples 'Debian Distribution Architecture' do |factory, container,
|
|||
end
|
||||
|
||||
describe 'scopes' do
|
||||
describe '.ordered_by_name' do
|
||||
subject { described_class.with_distribution(architecture.distribution).ordered_by_name }
|
||||
|
||||
it { expect(subject).to match_array([architecture, architecture_same_distribution]) }
|
||||
end
|
||||
|
||||
describe '.with_distribution' do
|
||||
subject { described_class.with_distribution(architecture.distribution) }
|
||||
|
||||
it 'does not return other distributions' do
|
||||
expect(subject.to_a).to match_array([architecture, architecture_same_distribution])
|
||||
end
|
||||
it { expect(subject).to match_array([architecture, architecture_same_distribution]) }
|
||||
end
|
||||
|
||||
describe '.with_name' do
|
||||
subject { described_class.with_name(architecture.name) }
|
||||
|
||||
it 'does not return other distributions' do
|
||||
expect(subject.to_a).to match_array([architecture, architecture_same_name])
|
||||
end
|
||||
it { expect(subject).to match_array([architecture, architecture_same_name]) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -114,11 +114,7 @@ RSpec.shared_examples 'Debian Component File' do |container_type, can_freeze|
|
|||
subject { described_class.with_container(container2) }
|
||||
|
||||
it do
|
||||
queries = ActiveRecord::QueryRecorder.new do
|
||||
expect(subject.to_a).to contain_exactly(component_file_other_container)
|
||||
end
|
||||
|
||||
expect(queries.count).to eq(1)
|
||||
expect(subject.to_a).to contain_exactly(component_file_other_container)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -126,11 +122,7 @@ RSpec.shared_examples 'Debian Component File' do |container_type, can_freeze|
|
|||
subject { described_class.with_codename_or_suite(distribution2.codename) }
|
||||
|
||||
it do
|
||||
queries = ActiveRecord::QueryRecorder.new do
|
||||
expect(subject.to_a).to contain_exactly(component_file_other_container)
|
||||
end
|
||||
|
||||
expect(queries.count).to eq(1)
|
||||
expect(subject.to_a).to contain_exactly(component_file_other_container)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -138,11 +130,7 @@ RSpec.shared_examples 'Debian Component File' do |container_type, can_freeze|
|
|||
subject { described_class.with_component_name(component1_2.name) }
|
||||
|
||||
it do
|
||||
queries = ActiveRecord::QueryRecorder.new do
|
||||
expect(subject.to_a).to contain_exactly(component_file_other_component)
|
||||
end
|
||||
|
||||
expect(queries.count).to eq(1)
|
||||
expect(subject.to_a).to contain_exactly(component_file_other_component)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -150,14 +138,7 @@ RSpec.shared_examples 'Debian Component File' do |container_type, can_freeze|
|
|||
subject { described_class.with_file_type(:source) }
|
||||
|
||||
it do
|
||||
# let_it_be_with_refind triggers a query
|
||||
component_file_with_file_type_source
|
||||
|
||||
queries = ActiveRecord::QueryRecorder.new do
|
||||
expect(subject.to_a).to contain_exactly(component_file_with_file_type_source)
|
||||
end
|
||||
|
||||
expect(queries.count).to eq(1)
|
||||
expect(subject.to_a).to contain_exactly(component_file_with_file_type_source)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -165,11 +146,7 @@ RSpec.shared_examples 'Debian Component File' do |container_type, can_freeze|
|
|||
subject { described_class.with_architecture_name(architecture1_2.name) }
|
||||
|
||||
it do
|
||||
queries = ActiveRecord::QueryRecorder.new do
|
||||
expect(subject.to_a).to contain_exactly(component_file_other_architecture)
|
||||
end
|
||||
|
||||
expect(queries.count).to eq(1)
|
||||
expect(subject.to_a).to contain_exactly(component_file_other_architecture)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -177,11 +154,7 @@ RSpec.shared_examples 'Debian Component File' do |container_type, can_freeze|
|
|||
subject { described_class.with_compression_type(:xz) }
|
||||
|
||||
it do
|
||||
queries = ActiveRecord::QueryRecorder.new do
|
||||
expect(subject.to_a).to contain_exactly(component_file_other_compression_type)
|
||||
end
|
||||
|
||||
expect(queries.count).to eq(1)
|
||||
expect(subject.to_a).to contain_exactly(component_file_other_compression_type)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -189,11 +162,19 @@ RSpec.shared_examples 'Debian Component File' do |container_type, can_freeze|
|
|||
subject { described_class.with_file_sha256('other_sha256') }
|
||||
|
||||
it do
|
||||
queries = ActiveRecord::QueryRecorder.new do
|
||||
expect(subject.to_a).to contain_exactly(component_file_other_file_sha256)
|
||||
end
|
||||
expect(subject.to_a).to contain_exactly(component_file_other_file_sha256)
|
||||
end
|
||||
end
|
||||
|
||||
expect(queries.count).to eq(1)
|
||||
describe '.created_before' do
|
||||
let_it_be(:component_file1) { create("debian_#{container_type}_component_file", component: component1_1, architecture: architecture1_1, created_at: 4.hours.ago) }
|
||||
let_it_be(:component_file2) { create("debian_#{container_type}_component_file", component: component1_1, architecture: architecture1_1, created_at: 3.hours.ago) }
|
||||
let_it_be(:component_file3) { create("debian_#{container_type}_component_file", component: component1_1, architecture: architecture1_1, created_at: 1.hour.ago) }
|
||||
|
||||
subject { described_class.created_before(2.hours.ago) }
|
||||
|
||||
it do
|
||||
expect(subject.to_a).to contain_exactly(component_file1, component_file2)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.shared_examples 'Debian Distribution Component' do |factory, container, can_freeze|
|
||||
let_it_be_with_refind(:component) { create(factory) } # rubocop:disable Rails/SaveBang
|
||||
let_it_be(:component_same_distribution, freeze: can_freeze) { create(factory, distribution: component.distribution) }
|
||||
let_it_be_with_refind(:component) { create(factory, name: 'name1') }
|
||||
let_it_be(:component_same_distribution, freeze: can_freeze) { create(factory, distribution: component.distribution, name: 'name2') }
|
||||
let_it_be(:component_same_name, freeze: can_freeze) { create(factory, name: component.name) }
|
||||
|
||||
subject { component }
|
||||
|
|
@ -32,6 +32,14 @@ RSpec.shared_examples 'Debian Distribution Component' do |factory, container, ca
|
|||
end
|
||||
|
||||
describe 'scopes' do
|
||||
describe '.ordered_by_name' do
|
||||
subject { described_class.with_distribution(component.distribution).ordered_by_name }
|
||||
|
||||
it 'sorts by name' do
|
||||
expect(subject.to_a).to eq([component, component_same_distribution])
|
||||
end
|
||||
end
|
||||
|
||||
describe '.with_distribution' do
|
||||
subject { described_class.with_distribution(component.distribution) }
|
||||
|
||||
|
|
|
|||
|
|
@ -19,11 +19,6 @@ RSpec.shared_examples 'Debian Distribution' do |factory, container, can_freeze|
|
|||
|
||||
it { is_expected.to have_many(:components).class_name("Packages::Debian::#{container.capitalize}Component").inverse_of(:distribution) }
|
||||
it { is_expected.to have_many(:architectures).class_name("Packages::Debian::#{container.capitalize}Architecture").inverse_of(:distribution) }
|
||||
|
||||
if container != :group
|
||||
it { is_expected.to have_many(:publications).class_name('Packages::Debian::Publication').inverse_of(:distribution).with_foreign_key(:distribution_id) }
|
||||
it { is_expected.to have_many(:packages).class_name('Packages::Package').through(:publications) }
|
||||
end
|
||||
end
|
||||
|
||||
describe 'validations' do
|
||||
|
|
@ -228,4 +223,44 @@ RSpec.shared_examples 'Debian Distribution' do |factory, container, can_freeze|
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
if container == :project
|
||||
describe 'project distribution specifics' do
|
||||
describe 'relationships' do
|
||||
it { is_expected.to have_many(:publications).class_name('Packages::Debian::Publication').inverse_of(:distribution).with_foreign_key(:distribution_id) }
|
||||
it { is_expected.to have_many(:packages).class_name('Packages::Package').through(:publications) }
|
||||
it { is_expected.to have_many(:package_files).class_name('Packages::PackageFile').through(:packages) }
|
||||
end
|
||||
end
|
||||
else
|
||||
describe 'group distribution specifics' do
|
||||
let_it_be(:public_project) { create(:project, :public, group: distribution_with_suite.container)}
|
||||
let_it_be(:public_distribution_with_same_codename) { create(:debian_project_distribution, container: public_project, codename: distribution_with_suite.codename) }
|
||||
let_it_be(:public_package_with_same_codename) { create(:debian_package, project: public_project, published_in: public_distribution_with_same_codename)}
|
||||
let_it_be(:public_distribution_with_same_suite) { create(:debian_project_distribution, container: public_project, suite: distribution_with_suite.suite) }
|
||||
let_it_be(:public_package_with_same_suite) { create(:debian_package, project: public_project, published_in: public_distribution_with_same_suite)}
|
||||
|
||||
let_it_be(:private_project) { create(:project, :private, group: distribution_with_suite.container)}
|
||||
let_it_be(:private_distribution_with_same_codename) { create(:debian_project_distribution, container: private_project, codename: distribution_with_suite.codename) }
|
||||
let_it_be(:private_package_with_same_codename) { create(:debian_package, project: private_project, published_in: private_distribution_with_same_codename)}
|
||||
let_it_be(:private_distribution_with_same_suite) { create(:debian_project_distribution, container: private_project, suite: distribution_with_suite.suite) }
|
||||
let_it_be(:private_package_with_same_suite) { create(:debian_package, project: private_project, published_in: private_distribution_with_same_codename)}
|
||||
|
||||
describe '#packages' do
|
||||
subject { distribution_with_suite.packages }
|
||||
|
||||
it 'returns only public packages with same codename' do
|
||||
expect(subject.to_a).to contain_exactly(public_package_with_same_codename)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#package_files' do
|
||||
subject { distribution_with_suite.package_files }
|
||||
|
||||
it 'returns only files from public packages with same codename' do
|
||||
expect(subject.to_a).to contain_exactly(*public_package_with_same_codename.package_files)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
236
yarn.lock
236
yarn.lock
|
|
@ -1296,10 +1296,10 @@
|
|||
dom-accessibility-api "^0.5.1"
|
||||
pretty-format "^26.4.2"
|
||||
|
||||
"@tiptap/core@^2.0.0-beta.38":
|
||||
version "2.0.0-beta.38"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/core/-/core-2.0.0-beta.38.tgz#b0ded8d6ced0a345cc8739f6d86dec3d96636987"
|
||||
integrity sha512-5ZbFQjJoyFtpUbjvSxjlb5NB8MIgaP1jNKiceG/aDt0wEf7vLgPalcfu76e+iITTjHU9VruaKINN1T+QA0fIZw==
|
||||
"@tiptap/core@^2.0.0-beta.54":
|
||||
version "2.0.0-beta.54"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/core/-/core-2.0.0-beta.54.tgz#3630c78aab0a72cff0ffa5dda7ff7a2623a307e5"
|
||||
integrity sha512-N89gA7MKxbXXN/aoe9Qp9fyzgg26Sm+7t+/ADB2HqCvVJhN0fQI0MhNdwOTvxHSxo3AASBMgo7Yj1Zw29TfG1Q==
|
||||
dependencies:
|
||||
"@types/prosemirror-commands" "^1.0.4"
|
||||
"@types/prosemirror-inputrules" "^1.0.4"
|
||||
|
|
@ -1312,173 +1312,173 @@
|
|||
prosemirror-commands "^1.1.7"
|
||||
prosemirror-inputrules "^1.1.3"
|
||||
prosemirror-keymap "^1.1.3"
|
||||
prosemirror-model "^1.14.0"
|
||||
prosemirror-model "^1.14.1"
|
||||
prosemirror-schema-list "^1.1.4"
|
||||
prosemirror-state "^1.3.4"
|
||||
prosemirror-transform "^1.3.2"
|
||||
prosemirror-view "^1.18.2"
|
||||
prosemirror-view "^1.18.4"
|
||||
|
||||
"@tiptap/extension-blockquote@^2.0.0-beta.6":
|
||||
version "2.0.0-beta.6"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-blockquote/-/extension-blockquote-2.0.0-beta.6.tgz#7670998307e88a0d0edf59558355a9328a6acec7"
|
||||
integrity sha512-DOtr1Iy+wdyX2lrSX9KF6BaHvi0Sxg5tWfrAVHxPU7tCfxt33Xp6Ym97fyuZLlwUIbrzsy/DqBkdTYQ5v+CPMA==
|
||||
"@tiptap/extension-blockquote@^2.0.0-beta.11":
|
||||
version "2.0.0-beta.11"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-blockquote/-/extension-blockquote-2.0.0-beta.11.tgz#ca0be20501506a5555f39c4ec61d0fb3fb8a1713"
|
||||
integrity sha512-lIE+VYm22rtDPe6nCxisn5YfSibP/oJwiaOdcYNVqBHNx49PDyYKqCT4EO7RWBw2CqZ+SuPIabrU0JYkjmHU7g==
|
||||
dependencies:
|
||||
prosemirror-inputrules "^1.1.3"
|
||||
|
||||
"@tiptap/extension-bold@^2.0.0-beta.6":
|
||||
version "2.0.0-beta.6"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-bold/-/extension-bold-2.0.0-beta.6.tgz#347ddb7ad726d369337299b3800367815106de7f"
|
||||
integrity sha512-hFxVQZcXWBCaCTCG3PJONhvTwoVGq/fJAQuPrYlI18z124Rhx6DeBkPG0FSwQgBeuJyezi4Jz61onkc48jwmSA==
|
||||
"@tiptap/extension-bold@^2.0.0-beta.11":
|
||||
version "2.0.0-beta.11"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-bold/-/extension-bold-2.0.0-beta.11.tgz#d8ac973d2795fc46231e5969d922ce8c3f7404b8"
|
||||
integrity sha512-ppak6sIYp2amVWwbU714rGrd+uN0jPLrg3RNh3+uZOuFNEeJK9IHuumhVqIiHqAd1aJ/m9M+tz2x5mrk0M/T3g==
|
||||
|
||||
"@tiptap/extension-bubble-menu@^2.0.0-beta.9":
|
||||
version "2.0.0-beta.9"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.0.0-beta.9.tgz#bbf6b819c7edd78f1dbc347f3d102f316928c385"
|
||||
integrity sha512-GGxHwurQ6PediGy2b6q5at73CRznD6M6f1OSSuFVoIm2Q+FQMOECXKqLHpIOuHke6zYJpaAp1SfdX87/Zs5qaQ==
|
||||
"@tiptap/extension-bubble-menu@^2.0.0-beta.15":
|
||||
version "2.0.0-beta.15"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.0.0-beta.15.tgz#307f94785caa6d57cbc33dcb37128fc9e910e184"
|
||||
integrity sha512-FP4AbsAu36PgTXrSWqJoMqDKMNtDx8fU0JffcGpegl8lG2JXlxFg/34RUrAwm4wlSJLHzV87Oasgxrk5QI/tsQ==
|
||||
dependencies:
|
||||
prosemirror-state "^1.3.4"
|
||||
prosemirror-view "^1.18.2"
|
||||
prosemirror-view "^1.18.4"
|
||||
tippy.js "^6.3.1"
|
||||
|
||||
"@tiptap/extension-bullet-list@^2.0.0-beta.6":
|
||||
version "2.0.0-beta.6"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-bullet-list/-/extension-bullet-list-2.0.0-beta.6.tgz#3830f4a6355f84061929085603f5423ae448d346"
|
||||
integrity sha512-uO2t1CUc2Puq23c06xJvK9Imh895j1fsTJKJfEiSPDVMGrS3+tGOnQ2f9Fc5IOJITZZzFOpKnxRHC9AS5DySmg==
|
||||
"@tiptap/extension-bullet-list@^2.0.0-beta.11":
|
||||
version "2.0.0-beta.11"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-bullet-list/-/extension-bullet-list-2.0.0-beta.11.tgz#6d3ccc047120bdd7576f0d1d286ae61a03c8b96e"
|
||||
integrity sha512-2Fq3uoq1tkwghUezuPO/5UcFEZUn7Ksn7CZ9MY0nPGONazxf2oHPbQjjH/jQW4b9H/qsDBVrxgype+qsW9cOkA==
|
||||
dependencies:
|
||||
prosemirror-inputrules "^1.1.3"
|
||||
|
||||
"@tiptap/extension-code-block-lowlight@^2.0.0-beta.9":
|
||||
version "2.0.0-beta.9"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block-lowlight/-/extension-code-block-lowlight-2.0.0-beta.9.tgz#96095ca9e00553c488e5f10b2eedd904c1d5ed9e"
|
||||
integrity sha512-EwDcARAxj8ZowpUQlhM/8aGlw+jmOtuov96Wg9KVmLJbUVmhETivhhlD31WVjyFdDB3nOA6bHqygjy+GP1/jAQ==
|
||||
"@tiptap/extension-code-block-lowlight@^2.0.0-beta.18":
|
||||
version "2.0.0-beta.18"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block-lowlight/-/extension-code-block-lowlight-2.0.0-beta.18.tgz#f90e557f0b62761f104937b0d41a4c4dd5569ee8"
|
||||
integrity sha512-UYtD6PcfbT8VgcU3x4452xpYi0oORx+jKi/eRoxMnCPPFiDUKLkuAmwM5dEcflCsZHaHRDn1c5pfRFQg9X+Y5A==
|
||||
dependencies:
|
||||
"@tiptap/extension-code-block" "^2.0.0-beta.6"
|
||||
"@tiptap/extension-code-block" "^2.0.0-beta.13"
|
||||
"@types/lowlight" "^0.0.1"
|
||||
lowlight "^1.20.0"
|
||||
prosemirror-model "^1.14.0"
|
||||
prosemirror-model "^1.14.1"
|
||||
prosemirror-state "^1.3.4"
|
||||
prosemirror-view "^1.18.2"
|
||||
prosemirror-view "^1.18.4"
|
||||
|
||||
"@tiptap/extension-code-block@^2.0.0-beta.6":
|
||||
version "2.0.0-beta.8"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block/-/extension-code-block-2.0.0-beta.8.tgz#f26d8992be6ea78f34a7db52b0a706293d19922d"
|
||||
integrity sha512-lSeC98qJ8szMUgp/hFZFMqDfV/boGpMN3kek98BR6dCI8QSHvZWpHrQ8n9dyc8NEGAuvBhP/lu0PSD1TzYwkig==
|
||||
"@tiptap/extension-code-block@^2.0.0-beta.13":
|
||||
version "2.0.0-beta.13"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block/-/extension-code-block-2.0.0-beta.13.tgz#9a41d103ed5b5a4810564c67105a89725b12559a"
|
||||
integrity sha512-IjYxiEkHmcRQu9qSc/InalurSxQD33ti39VqwDRZqKKG0rkAZSJhKyETdopVjr3EuE6YIp38CJdQfma7OENUXw==
|
||||
dependencies:
|
||||
prosemirror-inputrules "^1.1.3"
|
||||
|
||||
"@tiptap/extension-code@^2.0.0-beta.6":
|
||||
version "2.0.0-beta.6"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-code/-/extension-code-2.0.0-beta.6.tgz#c35f0a8b1f3fe05b5ec9ced5aea6c9b093073d09"
|
||||
integrity sha512-i0s3yTSdONUOp0fM/VrdSQfdj0SsqTPyP2ev2Ji1KgzGQ49Rw8gewT6RorHMwvMdv+F5+wE47wI2rcdUjpNwMQ==
|
||||
"@tiptap/extension-code@^2.0.0-beta.11":
|
||||
version "2.0.0-beta.11"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-code/-/extension-code-2.0.0-beta.11.tgz#484d63cde6ad5951e9075e2a47ebe0f6b633742f"
|
||||
integrity sha512-8u69zfc5Rd7QKZ3bZTj2IC4hJx34pT6lZ5u8XPS9DTlEPEXBp3XWgpZxuxFmoNhABqEPHYyBJao5eINtfQhhRg==
|
||||
|
||||
"@tiptap/extension-document@^2.0.0-beta.5":
|
||||
version "2.0.0-beta.5"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-document/-/extension-document-2.0.0-beta.5.tgz#595c25879eb39f26cdb58e9b01ff5e48d65b2e4b"
|
||||
integrity sha512-6GAZ7gA3vzStkASe+Qsd/OqqQ9QnDTjBKpXVxMZZnqutUmWjPau9e0kLEFYoU57f5bJa2w/TCWICSp+o4ka3jg==
|
||||
"@tiptap/extension-document@^2.0.0-beta.10":
|
||||
version "2.0.0-beta.10"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-document/-/extension-document-2.0.0-beta.10.tgz#2ccf4e5496f6b15c6bfa4f720b89af74fb871df4"
|
||||
integrity sha512-ugWixuQnZnmeXCk6Tp0lFWLdER5WL2QHJ9QOXSYoiT0LIfDivRhDvm4a0C0pToUL+f++jzfI8jcIvroHATWwVg==
|
||||
|
||||
"@tiptap/extension-dropcursor@^2.0.0-beta.6":
|
||||
version "2.0.0-beta.6"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-dropcursor/-/extension-dropcursor-2.0.0-beta.6.tgz#9a7569c970010c47424e93f67f907ce7f0c3c429"
|
||||
integrity sha512-EUmagYkamxuxZprKCXcSrwqUZkOW6edxIb7iyL0RQLYAcJ2jwCe9hJU0G6a8ILDr027W7fXd6LDbrzPMcVK/ug==
|
||||
"@tiptap/extension-dropcursor@^2.0.0-beta.11":
|
||||
version "2.0.0-beta.11"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-dropcursor/-/extension-dropcursor-2.0.0-beta.11.tgz#620120a7f95e7cf21e6a3362ba38b2eacfa98a88"
|
||||
integrity sha512-FwNoazT3BbvFsYxoQrmtVgLG1owEVhtoeaHndIWzMNxOGCWa96JtXsPgch9hSzQzb95qA5TFrFAftF/d5fkG8w==
|
||||
dependencies:
|
||||
"@types/prosemirror-dropcursor" "^1.0.1"
|
||||
prosemirror-dropcursor "^1.3.4"
|
||||
|
||||
"@tiptap/extension-floating-menu@^2.0.0-beta.6":
|
||||
version "2.0.0-beta.6"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-floating-menu/-/extension-floating-menu-2.0.0-beta.6.tgz#617290bd0533412e40c09dde7ecadc4a8c3cf960"
|
||||
integrity sha512-2j73cDaN+flG8mF/PHd8OrZjaG62r3Kbskzpdsa2Oa6fV3laNg0jMhFzcuBJwFKFa0l8RHB/zMXNpacxCHa9vw==
|
||||
"@tiptap/extension-floating-menu@^2.0.0-beta.12":
|
||||
version "2.0.0-beta.12"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-floating-menu/-/extension-floating-menu-2.0.0-beta.12.tgz#de38a4fc5e24c0f70caafeeece79e6623bd8a579"
|
||||
integrity sha512-mPfBKCW9hatT2UueIpLZTnN4qJ8YmS3EktQBlZLOuYwrBPqDZXu2qCPn1CyIV3emOmfFvnOHO3n9sIqbDDbZaQ==
|
||||
dependencies:
|
||||
prosemirror-state "^1.3.4"
|
||||
prosemirror-view "^1.18.2"
|
||||
prosemirror-view "^1.18.4"
|
||||
tippy.js "^6.3.1"
|
||||
|
||||
"@tiptap/extension-gapcursor@^2.0.0-beta.10":
|
||||
version "2.0.0-beta.10"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-gapcursor/-/extension-gapcursor-2.0.0-beta.10.tgz#f045d90def63559797576a299f904f539c304fe9"
|
||||
integrity sha512-q5S3AjDTBi5WHwl1V7iYSk32t3mk/Z/ZYAViLDsqffzurx6KIxq9Yw6Ad1L+h04wXq/rJiFeaMeCnGs4DmWa3w==
|
||||
"@tiptap/extension-gapcursor@^2.0.0-beta.15":
|
||||
version "2.0.0-beta.15"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-gapcursor/-/extension-gapcursor-2.0.0-beta.15.tgz#6bafbd095e8673449f976935200f22a623d4043c"
|
||||
integrity sha512-1qV9Wy4xa2oKD3JT5htK0Eu+tsPdknfXzWpdQT/P1NmTGk/Ysfy7CuipYNMaYD31NAreumXrC3CyDvel+1xo/A==
|
||||
dependencies:
|
||||
"@types/prosemirror-gapcursor" "^1.0.3"
|
||||
prosemirror-gapcursor "^1.1.5"
|
||||
|
||||
"@tiptap/extension-hard-break@^2.0.0-beta.6":
|
||||
version "2.0.0-beta.6"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-hard-break/-/extension-hard-break-2.0.0-beta.6.tgz#37bee563b06a528d6b72ea875de7645f97a43656"
|
||||
integrity sha512-FZ/wpC9YQY50rt85DuPl+Dxe157LtHAhKW08BRAds/o6zrwcBpbg7zzVPxnu1wH1L0ObhyxCjNFXUyKalLnk8g==
|
||||
"@tiptap/extension-hard-break@^2.0.0-beta.11":
|
||||
version "2.0.0-beta.11"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-hard-break/-/extension-hard-break-2.0.0-beta.11.tgz#b2d457bb5c4f97d052b2537a7624d9609822ef65"
|
||||
integrity sha512-jjJDY6buBu/2hGp4lpO+jrfMPfqnTaRJxMVv21eZylFHsEvrBFfy5yAj5RdLaqHg8RO3Av2aRwztXFn6oiEQ1Q==
|
||||
|
||||
"@tiptap/extension-heading@^2.0.0-beta.6":
|
||||
version "2.0.0-beta.6"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-heading/-/extension-heading-2.0.0-beta.6.tgz#077919803ed4d8c729a72cc122cfca851bfaeff3"
|
||||
integrity sha512-zM5zaWGbJDYDmuHZ+YHTZK2nncDs+tlhfYKTKPK+0iIFCO4iTkvs7ERUO9qdbuQKjHGp28Q3RhS7YORss2bOhA==
|
||||
"@tiptap/extension-heading@^2.0.0-beta.11":
|
||||
version "2.0.0-beta.11"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-heading/-/extension-heading-2.0.0-beta.11.tgz#9da6864aeafaeed83551559932253c9ab16621fb"
|
||||
integrity sha512-ymhb5q7iBIGFGU4hRrsVFJDx6zOUqF9qBBzufD44lT4KukFEqxjOO1RofOKI5V8VOTuhfx/hAt67fvwh4UR5iQ==
|
||||
dependencies:
|
||||
prosemirror-inputrules "^1.1.3"
|
||||
|
||||
"@tiptap/extension-history@^2.0.0-beta.5":
|
||||
version "2.0.0-beta.5"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-history/-/extension-history-2.0.0-beta.5.tgz#bb9b257c110b0ad324407443972a623efa71816d"
|
||||
integrity sha512-ej0QtStZVm8QInWHEtyduK9WQcYpfPN2EtIkwtPL9HFm9u7xgouBVdj1TqIABV3vJVGL28KKpGVVg8ZuBF4h7g==
|
||||
"@tiptap/extension-history@^2.0.0-beta.10":
|
||||
version "2.0.0-beta.10"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-history/-/extension-history-2.0.0-beta.10.tgz#bb14500e193118295eb8c55ae4c2ddc5f2ae5d72"
|
||||
integrity sha512-iy6H4Y63hvIkD+W1YJ5fOpvhRXHurRuypZajnupommxRigorA3z8MTySsUs7PIKx3vYvxYjr4dKS/6Shs72DSQ==
|
||||
dependencies:
|
||||
"@types/prosemirror-history" "^1.0.2"
|
||||
prosemirror-history "^1.1.3"
|
||||
|
||||
"@tiptap/extension-horizontal-rule@^2.0.0-beta.7":
|
||||
version "2.0.0-beta.7"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.0.0-beta.7.tgz#6e75336a0316bef1a359de7d1888c8fb97d5e659"
|
||||
integrity sha512-TOxoVyKL3qF0e+VCQ5B7BpdtspvvY0TdU6/AJVIatPK9rXXXcJTM68k0O4koXgeuu33CSPXWVNwgm3QcxMi3Dg==
|
||||
"@tiptap/extension-horizontal-rule@^2.0.0-beta.14":
|
||||
version "2.0.0-beta.14"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.0.0-beta.14.tgz#bc23541ab5885c25a804b6b6f3c0ed2e505f7327"
|
||||
integrity sha512-gCqJWhdqTfYKntlZ9dNlImFdFawRzfDbXDiffsnu1hqrEwCTweR5mWE+8qayRDL/JAEAqsFDLbgyPrYZQ1bvbA==
|
||||
dependencies:
|
||||
prosemirror-state "^1.3.4"
|
||||
|
||||
"@tiptap/extension-image@^2.0.0-beta.4":
|
||||
version "2.0.0-beta.4"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-image/-/extension-image-2.0.0-beta.4.tgz#91151af0268b2de911ba9ea22099f00638f08d1e"
|
||||
integrity sha512-NKqTmrxh8SmWUGex4QBq9Mjv7gIaJ8QlG//CXSW5s6QtLhjRbY9QFtBWK2FYOgyk2UBU6gmUA4wX6Eb0KGa4XQ==
|
||||
"@tiptap/extension-image@^2.0.0-beta.11":
|
||||
version "2.0.0-beta.11"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-image/-/extension-image-2.0.0-beta.11.tgz#b7c2961118c9468fd4bdb8632663379f618978e9"
|
||||
integrity sha512-0ItQgR6laHLqamWH4aEqbxPiiU2Vd9rTXnSKH/UE6N+O/7eyhSb/ABbbxVdS9P7EmnuDhlo2F12ysNgI1D9Uyw==
|
||||
|
||||
"@tiptap/extension-italic@^2.0.0-beta.6":
|
||||
version "2.0.0-beta.6"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-italic/-/extension-italic-2.0.0-beta.6.tgz#497cc5aac4077b27d6c548896601dd240771401a"
|
||||
integrity sha512-HjB6YCm4oQ04peQ9M2zi4101JSgNfOLTkyfbDhpQv+B61sZtuweJx27SxYDOB34dA+i513orCVZdI6AgSSCEHA==
|
||||
"@tiptap/extension-italic@^2.0.0-beta.11":
|
||||
version "2.0.0-beta.11"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-italic/-/extension-italic-2.0.0-beta.11.tgz#fa5668ede5dd5373277da4bafc26415a2771d7f6"
|
||||
integrity sha512-bm7iYB6HZTWa/ncU83hcAvjXjB7hei86xG5u+Hl2d11PvR6j/6srn1FWcXmf/2xwuWI/mUCTpl+ZfkoY7oTu9w==
|
||||
|
||||
"@tiptap/extension-link@^2.0.0-beta.6":
|
||||
version "2.0.0-beta.6"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-link/-/extension-link-2.0.0-beta.6.tgz#8e0051593d24ee232387535de716f87d4c388062"
|
||||
integrity sha512-zV7AJTgvGfYqtKYeywLg0lDLkYFynRW6Llh6C+hYw2w9Wq0fSZfTtpkcQPYv+jOcOoAFi2Ea02jyGQ+VthGZKg==
|
||||
"@tiptap/extension-link@^2.0.0-beta.15":
|
||||
version "2.0.0-beta.15"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-link/-/extension-link-2.0.0-beta.15.tgz#bb9adad12c55688e220f7d8a15d8456fbad47116"
|
||||
integrity sha512-/iIc1PjLSrteezXn8wmdKrXsMHS8zwV+UiPOSFPaGYzmJTt3kA+FVOo7xLOV1dZjM+nWDd02/QFNBNUCjGOeug==
|
||||
dependencies:
|
||||
prosemirror-state "^1.3.4"
|
||||
|
||||
"@tiptap/extension-list-item@^2.0.0-beta.6":
|
||||
version "2.0.0-beta.6"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-list-item/-/extension-list-item-2.0.0-beta.6.tgz#69850d2d9242e213a24a7e10baecb0f0933f3cbe"
|
||||
integrity sha512-zhssny5W2Q7CvB9qZT1Wc7k0V+R7IqCbNBmoijwF9a+uehBpJcxdN1DFB1v0qdmIEdDLU9dnBUfIpWPnLwiAXw==
|
||||
"@tiptap/extension-list-item@^2.0.0-beta.11":
|
||||
version "2.0.0-beta.11"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-list-item/-/extension-list-item-2.0.0-beta.11.tgz#22639904f9fdee8b80e344fe142e9065e9451337"
|
||||
integrity sha512-HKA9q2q9AobbB3er12FbXAy3rHVd41LXFKegpP/2Fle3gembN+VlazSXqHHWzlbaHgQAVn1MP6pnwaDFDYGNeA==
|
||||
|
||||
"@tiptap/extension-ordered-list@^2.0.0-beta.6":
|
||||
version "2.0.0-beta.6"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-ordered-list/-/extension-ordered-list-2.0.0-beta.6.tgz#ce214854946284c7ff2d458c7f4b3ac6ae33a9b8"
|
||||
integrity sha512-dUiTO9bV3cuxWedp164KVufW3BzIwY/beQ64aQjnRyA3TPyiPrhp4qvHrxQujm31XPJy4zUY0PO/VafJ+69cGw==
|
||||
"@tiptap/extension-ordered-list@^2.0.0-beta.11":
|
||||
version "2.0.0-beta.11"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-ordered-list/-/extension-ordered-list-2.0.0-beta.11.tgz#37dd6cbb8b271bf8902ffcbad2a2e282ea078f6e"
|
||||
integrity sha512-EYv8jKahmGgumIz/MHfI1zsGTz7YgTII7WdKPG8C3hpkDdkg/tb28Ue14CXlQ2hSGWjFTf1U0gHgHcPaJHMYJg==
|
||||
dependencies:
|
||||
prosemirror-inputrules "^1.1.3"
|
||||
|
||||
"@tiptap/extension-paragraph@^2.0.0-beta.7":
|
||||
version "2.0.0-beta.7"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-paragraph/-/extension-paragraph-2.0.0-beta.7.tgz#5dca1524247a57e98a60eb394ae66cd30072b9f4"
|
||||
integrity sha512-bk9/KNbJ4wAvaAwrPLwp89QtEyef9VxbbaPd2+Q21EArTP2SGPNTWrjARq1Flc41fERo+2A23K5AcbNDBID9DA==
|
||||
"@tiptap/extension-paragraph@^2.0.0-beta.12":
|
||||
version "2.0.0-beta.12"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-paragraph/-/extension-paragraph-2.0.0-beta.12.tgz#849aad4294a341abd93781174dbdc369d9b7570c"
|
||||
integrity sha512-qzURExCJ9gKLnzRE219BWp0S/wNNhX8NQI+ipMSIRoh5wZInCHwZnObRLsGuQI/qH/lQ0Y0QYWzA8VknCaH1kA==
|
||||
|
||||
"@tiptap/extension-strike@^2.0.0-beta.7":
|
||||
version "2.0.0-beta.7"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-strike/-/extension-strike-2.0.0-beta.7.tgz#cee0f3c087d2914f8435dc2cc4580c9aec0a42bb"
|
||||
integrity sha512-GBctBeHSkDW4ivXAUaEBtOgQXJgT2q2iqWuI8kTHCO1z7c/mns4J19U24dx8bPFhJBw++sDDd8yBkLQH2lP/Pw==
|
||||
"@tiptap/extension-strike@^2.0.0-beta.12":
|
||||
version "2.0.0-beta.12"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-strike/-/extension-strike-2.0.0-beta.12.tgz#0a7452e92d5042c8884eda38f6496a1ecc28e264"
|
||||
integrity sha512-qAJiC31BmRUOnDzGmMev2PMR5hhTIGIlH3aeZDiIsfiGCUleuyM3qJHIasq11W4Yap0s52qsSGI0+cmdVkbR/w==
|
||||
|
||||
"@tiptap/extension-text@^2.0.0-beta.5":
|
||||
version "2.0.0-beta.5"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-text/-/extension-text-2.0.0-beta.5.tgz#cce1f9b22a5e0ad35b081774059b8c2ec6c92ae3"
|
||||
integrity sha512-WCavPVqi+tndW8tAQ4KBq98ZnkLgKW9nc/T8wE3oKQ+df9YBauIl3OxxMA6At/oK+vlcFfubBpzFRAg9iygRAA==
|
||||
"@tiptap/extension-text@^2.0.0-beta.10":
|
||||
version "2.0.0-beta.10"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-text/-/extension-text-2.0.0-beta.10.tgz#50681ba2c8e8a54305a89efb1adb0e68d683e4eb"
|
||||
integrity sha512-4AdB5e88FmDbBWe9nTOCpvV5QpY2RoBKMqdSTsJcBhxGCXspomgOjbjYMtMabNkhd5mt76l2l65TyjRKSh5BCQ==
|
||||
|
||||
"@tiptap/vue-2@^2.0.0-beta.21":
|
||||
version "2.0.0-beta.21"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/vue-2/-/vue-2-2.0.0-beta.21.tgz#838257ef91bbd54995aa7d34e4682fc9c69cec6a"
|
||||
integrity sha512-WTL6iw6cgMkQQ2b++kClQOxsByAUKYLcjO1UsjmrrWnaSDmfMO1ZpkmKKSp1SsuQAk7W0t9aybeyWrDzjxfU3g==
|
||||
"@tiptap/vue-2@^2.0.0-beta.27":
|
||||
version "2.0.0-beta.27"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/vue-2/-/vue-2-2.0.0-beta.27.tgz#f9e3242a75957d46f1a4707e4a1bb29ec1d19e46"
|
||||
integrity sha512-8SG5EutZL+//Vu967yRZkSFatDXViOhRmlMxJpuK4xPL3/Y9EeqbmrK6NjZh7/nScTtTlg35oAwFZ2Sss818gw==
|
||||
dependencies:
|
||||
"@tiptap/extension-bubble-menu" "^2.0.0-beta.9"
|
||||
"@tiptap/extension-floating-menu" "^2.0.0-beta.6"
|
||||
prosemirror-view "^1.18.2"
|
||||
"@tiptap/extension-bubble-menu" "^2.0.0-beta.15"
|
||||
"@tiptap/extension-floating-menu" "^2.0.0-beta.12"
|
||||
prosemirror-view "^1.18.4"
|
||||
|
||||
"@toast-ui/editor@^2.5.2":
|
||||
version "2.5.2"
|
||||
|
|
@ -9597,10 +9597,10 @@ prosemirror-markdown@^1.5.1:
|
|||
markdown-it "^10.0.0"
|
||||
prosemirror-model "^1.0.0"
|
||||
|
||||
prosemirror-model@^1.0.0, prosemirror-model@^1.1.0, prosemirror-model@^1.13.1, prosemirror-model@^1.13.3, prosemirror-model@^1.14.0, prosemirror-model@^1.8.1:
|
||||
version "1.14.0"
|
||||
resolved "https://registry.yarnpkg.com/prosemirror-model/-/prosemirror-model-1.14.0.tgz#44042a16942dfc5dcd79daf6ec37b0efcfef53c8"
|
||||
integrity sha512-+9J7YE2qD2lsRgaI5aF7u6LynBoHxb/8sW1gaMKRAhK+yeQ+motBIaxb2GxRWSadDWMOq5haAImSTBo6jDkv2A==
|
||||
prosemirror-model@^1.0.0, prosemirror-model@^1.1.0, prosemirror-model@^1.13.1, prosemirror-model@^1.13.3, prosemirror-model@^1.14.1, prosemirror-model@^1.8.1:
|
||||
version "1.14.1"
|
||||
resolved "https://registry.yarnpkg.com/prosemirror-model/-/prosemirror-model-1.14.1.tgz#d784c67f95a5d66b853e82ff9a87a50353ef9cd5"
|
||||
integrity sha512-vZcbI+24VloFefKZkDnMaEpipL/vSKKPdFiik4KOnTzq3e6AO7+CAOixZ2G/SsfRaYC965XvnOIEbhIQdgki7w==
|
||||
dependencies:
|
||||
orderedmap "^1.1.0"
|
||||
|
||||
|
|
@ -9638,10 +9638,10 @@ prosemirror-transform@^1.0.0, prosemirror-transform@^1.1.0, prosemirror-transfor
|
|||
dependencies:
|
||||
prosemirror-model "^1.0.0"
|
||||
|
||||
prosemirror-view@^1.0.0, prosemirror-view@^1.1.0, prosemirror-view@^1.13.3, prosemirror-view@^1.16.5, prosemirror-view@^1.18.2:
|
||||
version "1.18.3"
|
||||
resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.18.3.tgz#cfc70169cb300e9503d97362463ea870efffd3ef"
|
||||
integrity sha512-B0zlzjBI0cHadpghyvAA+JgqLGbkNU9Vxywqkfaa+AdmOZUZImBKH6ufhpK+AEZn97WWgSIkr/MT9RmGpaboAA==
|
||||
prosemirror-view@^1.0.0, prosemirror-view@^1.1.0, prosemirror-view@^1.13.3, prosemirror-view@^1.16.5, prosemirror-view@^1.18.4:
|
||||
version "1.18.4"
|
||||
resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.18.4.tgz#179141df117cf414434ade08115f2e233d135f6d"
|
||||
integrity sha512-6oi62XRK5WxhMX1Amjk5uMsWILUEcFbFF75i09BzpAdI+5glhs7heCaRvKOj4v3YRJ7LJVkOXS9xvjetlE3+pA==
|
||||
dependencies:
|
||||
prosemirror-model "^1.1.0"
|
||||
prosemirror-state "^1.0.0"
|
||||
|
|
|
|||
Loading…
Reference in New Issue