Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
1b044a566c
commit
cddf2db96b
|
|
@ -117,7 +117,7 @@ export default {
|
|||
class="ide-navigator-btn d-flex align-items-center d-transparent border-0 bg-transparent"
|
||||
@click="refresh"
|
||||
>
|
||||
<gl-icon :size="18" name="retry" use-deprecated-sizes class="m-auto" />
|
||||
<gl-icon :size="16" name="retry" class="m-auto" />
|
||||
</button>
|
||||
<div class="position-relative w-100 gl-ml-2">
|
||||
<input
|
||||
|
|
|
|||
|
|
@ -1,94 +0,0 @@
|
|||
<script>
|
||||
import { GlLink, GlSprintf } from '@gitlab/ui';
|
||||
import { s__ } from '~/locale';
|
||||
import DetailsRow from '~/vue_shared/components/registry/details_row.vue';
|
||||
import { PackageType } from '../../shared/constants';
|
||||
|
||||
export default {
|
||||
i18n: {
|
||||
sourceText: s__('PackageRegistry|Source project located at %{link}'),
|
||||
licenseText: s__('PackageRegistry|License information located at %{link}'),
|
||||
recipeText: s__('PackageRegistry|Recipe: %{recipe}'),
|
||||
appGroup: s__('PackageRegistry|App group: %{group}'),
|
||||
appName: s__('PackageRegistry|App name: %{name}'),
|
||||
},
|
||||
components: {
|
||||
DetailsRow,
|
||||
GlLink,
|
||||
GlSprintf,
|
||||
},
|
||||
props: {
|
||||
packageEntity: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
showMetadata() {
|
||||
const visibilityConditions = {
|
||||
[PackageType.NUGET]: this.packageEntity.nuget_metadatum,
|
||||
[PackageType.CONAN]: this.packageEntity.conan_metadatum,
|
||||
[PackageType.MAVEN]: this.packageEntity.maven_metadatum,
|
||||
};
|
||||
return visibilityConditions[this.packageEntity.package_type];
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="showMetadata">
|
||||
<h3 class="gl-font-lg" data-testid="title">{{ __('Additional Metadata') }}</h3>
|
||||
|
||||
<div class="gl-bg-gray-50 gl-inset-border-1-gray-100 gl-rounded-base" data-testid="main">
|
||||
<template v-if="packageEntity.nuget_metadatum">
|
||||
<details-row icon="project" padding="gl-p-4" dashed data-testid="nuget-source">
|
||||
<gl-sprintf :message="$options.i18n.sourceText">
|
||||
<template #link>
|
||||
<gl-link :href="packageEntity.nuget_metadatum.project_url" target="_blank">{{
|
||||
packageEntity.nuget_metadatum.project_url
|
||||
}}</gl-link>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</details-row>
|
||||
<details-row icon="license" padding="gl-p-4" data-testid="nuget-license">
|
||||
<gl-sprintf :message="$options.i18n.licenseText">
|
||||
<template #link>
|
||||
<gl-link :href="packageEntity.nuget_metadatum.license_url" target="_blank">{{
|
||||
packageEntity.nuget_metadatum.license_url
|
||||
}}</gl-link>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</details-row>
|
||||
</template>
|
||||
|
||||
<details-row
|
||||
v-else-if="packageEntity.conan_metadatum"
|
||||
icon="information-o"
|
||||
padding="gl-p-4"
|
||||
data-testid="conan-recipe"
|
||||
>
|
||||
<gl-sprintf :message="$options.i18n.recipeText">
|
||||
<template #recipe>{{ packageEntity.name }}</template>
|
||||
</gl-sprintf>
|
||||
</details-row>
|
||||
|
||||
<template v-else-if="packageEntity.maven_metadatum">
|
||||
<details-row icon="information-o" padding="gl-p-4" dashed data-testid="maven-app">
|
||||
<gl-sprintf :message="$options.i18n.appName">
|
||||
<template #name>
|
||||
<strong>{{ packageEntity.maven_metadatum.app_name }}</strong>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</details-row>
|
||||
<details-row icon="information-o" padding="gl-p-4" data-testid="maven-group">
|
||||
<gl-sprintf :message="$options.i18n.appGroup">
|
||||
<template #group>
|
||||
<strong>{{ packageEntity.maven_metadatum.app_group }}</strong>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</details-row>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
<script>
|
||||
import {
|
||||
GlBadge,
|
||||
GlButton,
|
||||
GlModal,
|
||||
GlModalDirective,
|
||||
|
|
@ -14,36 +13,30 @@ import { mapActions, mapState } from 'vuex';
|
|||
import { numberToHumanSize } from '~/lib/utils/number_utils';
|
||||
import { objectToQuery } from '~/lib/utils/url_utility';
|
||||
import { s__, __ } from '~/locale';
|
||||
import TerraformTitle from '~/packages_and_registries/infrastructure_registry/components/details_title.vue';
|
||||
import TerraformInstallation from '~/packages_and_registries/infrastructure_registry/components/terraform_installation.vue';
|
||||
import Tracking from '~/tracking';
|
||||
import PackageListRow from '../../shared/components/package_list_row.vue';
|
||||
import PackagesListLoader from '../../shared/components/packages_list_loader.vue';
|
||||
import { PackageType, TrackingActions, SHOW_DELETE_SUCCESS_ALERT } from '../../shared/constants';
|
||||
import { TrackingActions, SHOW_DELETE_SUCCESS_ALERT } from '../../shared/constants';
|
||||
import { packageTypeToTrackCategory } from '../../shared/utils';
|
||||
import AdditionalMetadata from './additional_metadata.vue';
|
||||
import DependencyRow from './dependency_row.vue';
|
||||
import InstallationCommands from './installation_commands.vue';
|
||||
import PackageFiles from './package_files.vue';
|
||||
import PackageHistory from './package_history.vue';
|
||||
|
||||
export default {
|
||||
name: 'PackagesApp',
|
||||
components: {
|
||||
GlBadge,
|
||||
GlButton,
|
||||
GlEmptyState,
|
||||
GlModal,
|
||||
GlTab,
|
||||
GlTabs,
|
||||
GlSprintf,
|
||||
PackageTitle: () => import('./package_title.vue'),
|
||||
TerraformTitle: () =>
|
||||
import('~/packages_and_registries/infrastructure_registry/components/details_title.vue'),
|
||||
TerraformTitle,
|
||||
PackagesListLoader,
|
||||
PackageListRow,
|
||||
DependencyRow,
|
||||
PackageHistory,
|
||||
AdditionalMetadata,
|
||||
InstallationCommands,
|
||||
TerraformInstallation,
|
||||
PackageFiles,
|
||||
},
|
||||
directives: {
|
||||
|
|
@ -51,12 +44,6 @@ export default {
|
|||
GlModal: GlModalDirective,
|
||||
},
|
||||
mixins: [Tracking.mixin()],
|
||||
inject: {
|
||||
titleComponent: {
|
||||
default: 'PackageTitle',
|
||||
from: 'titleComponent',
|
||||
},
|
||||
},
|
||||
trackingActions: { ...TrackingActions },
|
||||
data() {
|
||||
return {
|
||||
|
|
@ -87,15 +74,6 @@ export default {
|
|||
hasVersions() {
|
||||
return this.packageEntity.versions?.length > 0;
|
||||
},
|
||||
packageDependencies() {
|
||||
return this.packageEntity.dependency_links || [];
|
||||
},
|
||||
showDependencies() {
|
||||
return this.packageEntity.package_type === PackageType.NUGET;
|
||||
},
|
||||
showFiles() {
|
||||
return this.packageEntity?.package_type !== PackageType.COMPOSER;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
...mapActions(['deletePackage', 'fetchPackageVersions', 'deletePackageFile']),
|
||||
|
|
@ -167,7 +145,7 @@ export default {
|
|||
/>
|
||||
|
||||
<div v-else class="packages-app">
|
||||
<component :is="titleComponent">
|
||||
<terraform-title>
|
||||
<template #delete-button>
|
||||
<gl-button
|
||||
v-if="canDelete"
|
||||
|
|
@ -180,24 +158,16 @@ export default {
|
|||
{{ __('Delete') }}
|
||||
</gl-button>
|
||||
</template>
|
||||
</component>
|
||||
</terraform-title>
|
||||
|
||||
<gl-tabs>
|
||||
<gl-tab :title="__('Detail')">
|
||||
<div data-qa-selector="package_information_content">
|
||||
<package-history :package-entity="packageEntity" :project-name="projectName" />
|
||||
|
||||
<installation-commands
|
||||
:package-entity="packageEntity"
|
||||
:npm-path="npmPath"
|
||||
:npm-help-path="npmHelpPath"
|
||||
/>
|
||||
|
||||
<additional-metadata :package-entity="packageEntity" />
|
||||
<terraform-installation />
|
||||
</div>
|
||||
|
||||
<package-files
|
||||
v-if="showFiles"
|
||||
:package-files="packageFiles"
|
||||
:can-delete="canDelete"
|
||||
@download-file="track($options.trackingActions.PULL_PACKAGE)"
|
||||
|
|
@ -205,27 +175,6 @@ export default {
|
|||
/>
|
||||
</gl-tab>
|
||||
|
||||
<gl-tab v-if="showDependencies" title-item-class="js-dependencies-tab">
|
||||
<template #title>
|
||||
<span>{{ __('Dependencies') }}</span>
|
||||
<gl-badge size="sm" data-testid="dependencies-badge">{{
|
||||
packageDependencies.length
|
||||
}}</gl-badge>
|
||||
</template>
|
||||
|
||||
<template v-if="packageDependencies.length > 0">
|
||||
<dependency-row
|
||||
v-for="(dep, index) in packageDependencies"
|
||||
:key="index"
|
||||
:dependency="dep"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<p v-else class="gl-mt-3" data-testid="no-dependencies-message">
|
||||
{{ s__('PackageRegistry|This NuGet package has no dependencies.') }}
|
||||
</p>
|
||||
</gl-tab>
|
||||
|
||||
<gl-tab
|
||||
:title="__('Other versions')"
|
||||
title-item-class="js-versions-tab"
|
||||
|
|
@ -254,7 +203,6 @@ export default {
|
|||
|
||||
<gl-modal
|
||||
ref="deleteModal"
|
||||
class="js-delete-modal"
|
||||
modal-id="delete-modal"
|
||||
:action-primary="$options.modal.packageDeletePrimaryAction"
|
||||
:action-cancel="$options.modal.cancelAction"
|
||||
|
|
|
|||
|
|
@ -1,65 +0,0 @@
|
|||
<script>
|
||||
import { GlLink, GlSprintf } from '@gitlab/ui';
|
||||
import { mapGetters, mapState } from 'vuex';
|
||||
import { s__ } from '~/locale';
|
||||
import InstallationTitle from '~/packages/details/components/installation_title.vue';
|
||||
import CodeInstruction from '~/vue_shared/components/registry/code_instruction.vue';
|
||||
import { TrackingActions, TrackingLabels } from '../constants';
|
||||
|
||||
export default {
|
||||
name: 'ComposerInstallation',
|
||||
components: {
|
||||
InstallationTitle,
|
||||
CodeInstruction,
|
||||
GlLink,
|
||||
GlSprintf,
|
||||
},
|
||||
computed: {
|
||||
...mapState(['composerHelpPath']),
|
||||
...mapGetters(['composerRegistryInclude', 'composerPackageInclude', 'groupExists']),
|
||||
},
|
||||
i18n: {
|
||||
registryInclude: s__('PackageRegistry|Add composer registry'),
|
||||
copyRegistryInclude: s__('PackageRegistry|Copy registry include'),
|
||||
packageInclude: s__('PackageRegistry|Install package version'),
|
||||
copyPackageInclude: s__('PackageRegistry|Copy require package include'),
|
||||
infoLine: s__(
|
||||
'PackageRegistry|For more information on Composer packages in GitLab, %{linkStart}see the documentation.%{linkEnd}',
|
||||
),
|
||||
},
|
||||
trackingActions: { ...TrackingActions },
|
||||
TrackingLabels,
|
||||
installOptions: [{ value: 'composer', label: s__('PackageRegistry|Show Composer commands') }],
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="groupExists" data-testid="root-node">
|
||||
<installation-title package-type="composer" :options="$options.installOptions" />
|
||||
|
||||
<code-instruction
|
||||
:label="$options.i18n.registryInclude"
|
||||
:instruction="composerRegistryInclude"
|
||||
:copy-text="$options.i18n.copyRegistryInclude"
|
||||
:tracking-action="$options.trackingActions.COPY_COMPOSER_REGISTRY_INCLUDE_COMMAND"
|
||||
:tracking-label="$options.TrackingLabels.CODE_INSTRUCTION"
|
||||
data-testid="registry-include"
|
||||
/>
|
||||
|
||||
<code-instruction
|
||||
:label="$options.i18n.packageInclude"
|
||||
:instruction="composerPackageInclude"
|
||||
:copy-text="$options.i18n.copyPackageInclude"
|
||||
:tracking-action="$options.trackingActions.COPY_COMPOSER_PACKAGE_INCLUDE_COMMAND"
|
||||
:tracking-label="$options.TrackingLabels.CODE_INSTRUCTION"
|
||||
data-testid="package-include"
|
||||
/>
|
||||
<span data-testid="help-text">
|
||||
<gl-sprintf :message="$options.i18n.infoLine">
|
||||
<template #link="{ content }">
|
||||
<gl-link :href="composerHelpPath" target="_blank">{{ content }}</gl-link>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
<script>
|
||||
import { GlLink, GlSprintf } from '@gitlab/ui';
|
||||
import { mapGetters, mapState } from 'vuex';
|
||||
import { s__ } from '~/locale';
|
||||
import InstallationTitle from '~/packages/details/components/installation_title.vue';
|
||||
import CodeInstruction from '~/vue_shared/components/registry/code_instruction.vue';
|
||||
import { TrackingActions, TrackingLabels } from '../constants';
|
||||
|
||||
export default {
|
||||
name: 'ConanInstallation',
|
||||
components: {
|
||||
InstallationTitle,
|
||||
CodeInstruction,
|
||||
GlLink,
|
||||
GlSprintf,
|
||||
},
|
||||
computed: {
|
||||
...mapState(['conanHelpPath']),
|
||||
...mapGetters(['conanInstallationCommand', 'conanSetupCommand']),
|
||||
},
|
||||
i18n: {
|
||||
helpText: s__(
|
||||
'PackageRegistry|For more information on the Conan registry, %{linkStart}see the documentation%{linkEnd}.',
|
||||
),
|
||||
},
|
||||
trackingActions: { ...TrackingActions },
|
||||
TrackingLabels,
|
||||
installOptions: [{ value: 'conan', label: s__('PackageRegistry|Show Conan commands') }],
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<installation-title package-type="conan" :options="$options.installOptions" />
|
||||
|
||||
<code-instruction
|
||||
:label="s__('PackageRegistry|Conan Command')"
|
||||
:instruction="conanInstallationCommand"
|
||||
:copy-text="s__('PackageRegistry|Copy Conan Command')"
|
||||
:tracking-action="$options.trackingActions.COPY_CONAN_COMMAND"
|
||||
:tracking-label="$options.TrackingLabels.CODE_INSTRUCTION"
|
||||
/>
|
||||
|
||||
<h3 class="gl-font-lg">{{ __('Registry setup') }}</h3>
|
||||
|
||||
<code-instruction
|
||||
:label="s__('PackageRegistry|Add Conan Remote')"
|
||||
:instruction="conanSetupCommand"
|
||||
:copy-text="s__('PackageRegistry|Copy Conan Setup Command')"
|
||||
:tracking-action="$options.trackingActions.COPY_CONAN_SETUP_COMMAND"
|
||||
:tracking-label="$options.TrackingLabels.CODE_INSTRUCTION"
|
||||
/>
|
||||
<gl-sprintf :message="$options.i18n.helpText">
|
||||
<template #link="{ content }">
|
||||
<gl-link :href="conanHelpPath" target="_blank">{{ content }}</gl-link>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
<script>
|
||||
export default {
|
||||
name: 'DependencyRow',
|
||||
props: {
|
||||
dependency: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
showVersion() {
|
||||
return Boolean(this.dependency.version_pattern);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="gl-responsive-table-row">
|
||||
<div class="table-section section-50">
|
||||
<strong class="gl-text-body">{{ dependency.name }}</strong>
|
||||
<span v-if="dependency.target_framework" data-testid="target-framework"
|
||||
>({{ dependency.target_framework }})</span
|
||||
>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="showVersion"
|
||||
class="table-section section-50 gl-display-flex gl-md-justify-content-end"
|
||||
data-testid="version-pattern"
|
||||
>
|
||||
<span class="gl-text-body">{{ dependency.version_pattern }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
<script>
|
||||
import TerraformInstallation from '~/packages_and_registries/infrastructure_registry/components/terraform_installation.vue';
|
||||
import { PackageType, TERRAFORM_PACKAGE_TYPE } from '../../shared/constants';
|
||||
import ComposerInstallation from './composer_installation.vue';
|
||||
import ConanInstallation from './conan_installation.vue';
|
||||
import MavenInstallation from './maven_installation.vue';
|
||||
import NpmInstallation from './npm_installation.vue';
|
||||
import NugetInstallation from './nuget_installation.vue';
|
||||
import PypiInstallation from './pypi_installation.vue';
|
||||
|
||||
export default {
|
||||
name: 'InstallationCommands',
|
||||
components: {
|
||||
[PackageType.CONAN]: ConanInstallation,
|
||||
[PackageType.MAVEN]: MavenInstallation,
|
||||
[PackageType.NPM]: NpmInstallation,
|
||||
[PackageType.NUGET]: NugetInstallation,
|
||||
[PackageType.PYPI]: PypiInstallation,
|
||||
[PackageType.COMPOSER]: ComposerInstallation,
|
||||
[TERRAFORM_PACKAGE_TYPE]: TerraformInstallation,
|
||||
},
|
||||
props: {
|
||||
packageEntity: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
npmPath: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
npmHelpPath: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
installationComponent() {
|
||||
return this.$options.components[this.packageEntity.package_type];
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="installationComponent">
|
||||
<component
|
||||
:is="installationComponent"
|
||||
:name="packageEntity.name"
|
||||
:registry-url="npmPath"
|
||||
:help-url="npmHelpPath"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
<script>
|
||||
import PersistedDropdownSelection from '~/vue_shared/components/registry/persisted_dropdown_selection.vue';
|
||||
|
||||
export default {
|
||||
name: 'InstallationTitle',
|
||||
components: {
|
||||
PersistedDropdownSelection,
|
||||
},
|
||||
props: {
|
||||
packageType: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
options: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
storageKey() {
|
||||
return `package_${this.packageType}_installation_instructions`;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="gl-display-flex gl-justify-content-space-between gl-align-items-center">
|
||||
<h3 class="gl-font-lg">{{ __('Installation') }}</h3>
|
||||
<div>
|
||||
<persisted-dropdown-selection
|
||||
:storage-key="storageKey"
|
||||
:options="options"
|
||||
@change="$emit('change', $event)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -1,153 +0,0 @@
|
|||
<script>
|
||||
import { GlLink, GlSprintf } from '@gitlab/ui';
|
||||
import { mapGetters, mapState } from 'vuex';
|
||||
import { s__ } from '~/locale';
|
||||
import InstallationTitle from '~/packages/details/components/installation_title.vue';
|
||||
import CodeInstruction from '~/vue_shared/components/registry/code_instruction.vue';
|
||||
|
||||
import { TrackingActions, TrackingLabels } from '../constants';
|
||||
|
||||
export default {
|
||||
name: 'MavenInstallation',
|
||||
components: {
|
||||
InstallationTitle,
|
||||
CodeInstruction,
|
||||
GlLink,
|
||||
GlSprintf,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
instructionType: 'maven',
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState(['mavenHelpPath']),
|
||||
...mapGetters([
|
||||
'mavenInstallationXml',
|
||||
'mavenInstallationCommand',
|
||||
'mavenSetupXml',
|
||||
'gradleGroovyInstalCommand',
|
||||
'gradleGroovyAddSourceCommand',
|
||||
'gradleKotlinInstalCommand',
|
||||
'gradleKotlinAddSourceCommand',
|
||||
]),
|
||||
showMaven() {
|
||||
return this.instructionType === 'maven';
|
||||
},
|
||||
showGroovy() {
|
||||
return this.instructionType === 'groovy';
|
||||
},
|
||||
},
|
||||
i18n: {
|
||||
xmlText: s__(
|
||||
`PackageRegistry|Copy and paste this inside your %{codeStart}pom.xml%{codeEnd} %{codeStart}dependencies%{codeEnd} block.`,
|
||||
),
|
||||
setupText: s__(
|
||||
`PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}pom.xml%{codeEnd} file.`,
|
||||
),
|
||||
helpText: s__(
|
||||
'PackageRegistry|For more information on the Maven registry, %{linkStart}see the documentation%{linkEnd}.',
|
||||
),
|
||||
},
|
||||
trackingActions: { ...TrackingActions },
|
||||
TrackingLabels,
|
||||
installOptions: [
|
||||
{ value: 'maven', label: s__('PackageRegistry|Maven XML') },
|
||||
{ value: 'groovy', label: s__('PackageRegistry|Gradle Groovy DSL') },
|
||||
{ value: 'kotlin', label: s__('PackageRegistry|Gradle Kotlin DSL') },
|
||||
],
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<installation-title
|
||||
package-type="maven"
|
||||
:options="$options.installOptions"
|
||||
@change="instructionType = $event"
|
||||
/>
|
||||
|
||||
<template v-if="showMaven">
|
||||
<p>
|
||||
<gl-sprintf :message="$options.i18n.xmlText">
|
||||
<template #code="{ content }">
|
||||
<code>{{ content }}</code>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</p>
|
||||
|
||||
<code-instruction
|
||||
:instruction="mavenInstallationXml"
|
||||
:copy-text="s__('PackageRegistry|Copy Maven XML')"
|
||||
:tracking-action="$options.trackingActions.COPY_MAVEN_XML"
|
||||
:tracking-label="$options.TrackingLabels.CODE_INSTRUCTION"
|
||||
multiline
|
||||
/>
|
||||
|
||||
<code-instruction
|
||||
:label="s__('PackageRegistry|Maven Command')"
|
||||
:instruction="mavenInstallationCommand"
|
||||
:copy-text="s__('PackageRegistry|Copy Maven command')"
|
||||
:tracking-action="$options.trackingActions.COPY_MAVEN_COMMAND"
|
||||
:tracking-label="$options.TrackingLabels.CODE_INSTRUCTION"
|
||||
/>
|
||||
|
||||
<h3 class="gl-font-lg">{{ s__('PackageRegistry|Registry setup') }}</h3>
|
||||
<p>
|
||||
<gl-sprintf :message="$options.i18n.setupText">
|
||||
<template #code="{ content }">
|
||||
<code>{{ content }}</code>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</p>
|
||||
<code-instruction
|
||||
:instruction="mavenSetupXml"
|
||||
:copy-text="s__('PackageRegistry|Copy Maven registry XML')"
|
||||
:tracking-action="$options.trackingActions.COPY_MAVEN_SETUP"
|
||||
:tracking-label="$options.TrackingLabels.CODE_INSTRUCTION"
|
||||
multiline
|
||||
/>
|
||||
<gl-sprintf :message="$options.i18n.helpText">
|
||||
<template #link="{ content }">
|
||||
<gl-link :href="mavenHelpPath" target="_blank">{{ content }}</gl-link>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</template>
|
||||
<template v-else-if="showGroovy">
|
||||
<code-instruction
|
||||
class="gl-mb-5"
|
||||
:label="s__('PackageRegistry|Gradle Groovy DSL install command')"
|
||||
:instruction="gradleGroovyInstalCommand"
|
||||
:copy-text="s__('PackageRegistry|Copy Gradle Groovy DSL install command')"
|
||||
:tracking-action="$options.trackingActions.COPY_GRADLE_INSTALL_COMMAND"
|
||||
:tracking-label="$options.TrackingLabels.CODE_INSTRUCTION"
|
||||
/>
|
||||
<code-instruction
|
||||
:label="s__('PackageRegistry|Add Gradle Groovy DSL repository command')"
|
||||
:instruction="gradleGroovyAddSourceCommand"
|
||||
:copy-text="s__('PackageRegistry|Copy add Gradle Groovy DSL repository command')"
|
||||
:tracking-action="$options.trackingActions.COPY_GRADLE_ADD_TO_SOURCE_COMMAND"
|
||||
:tracking-label="$options.TrackingLabels.CODE_INSTRUCTION"
|
||||
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>
|
||||
|
|
@ -1,103 +0,0 @@
|
|||
<script>
|
||||
import { GlLink, GlSprintf } from '@gitlab/ui';
|
||||
import { mapGetters, mapState } from 'vuex';
|
||||
import { s__ } from '~/locale';
|
||||
import InstallationTitle from '~/packages/details/components/installation_title.vue';
|
||||
import CodeInstruction from '~/vue_shared/components/registry/code_instruction.vue';
|
||||
import { NpmManager, TrackingActions, TrackingLabels } from '../constants';
|
||||
|
||||
export default {
|
||||
name: 'NpmInstallation',
|
||||
components: {
|
||||
InstallationTitle,
|
||||
CodeInstruction,
|
||||
GlLink,
|
||||
GlSprintf,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
instructionType: 'npm',
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState(['npmHelpPath']),
|
||||
...mapGetters(['npmInstallationCommand', 'npmSetupCommand']),
|
||||
npmCommand() {
|
||||
return this.npmInstallationCommand(NpmManager.NPM);
|
||||
},
|
||||
npmSetup() {
|
||||
return this.npmSetupCommand(NpmManager.NPM);
|
||||
},
|
||||
yarnCommand() {
|
||||
return this.npmInstallationCommand(NpmManager.YARN);
|
||||
},
|
||||
yarnSetupCommand() {
|
||||
return this.npmSetupCommand(NpmManager.YARN);
|
||||
},
|
||||
showNpm() {
|
||||
return this.instructionType === 'npm';
|
||||
},
|
||||
},
|
||||
i18n: {
|
||||
helpText: s__(
|
||||
'PackageRegistry|You may also need to setup authentication using an auth token. %{linkStart}See the documentation%{linkEnd} to find out more.',
|
||||
),
|
||||
},
|
||||
trackingActions: { ...TrackingActions },
|
||||
TrackingLabels,
|
||||
installOptions: [
|
||||
{ value: 'npm', label: s__('PackageRegistry|Show NPM commands') },
|
||||
{ value: 'yarn', label: s__('PackageRegistry|Show Yarn commands') },
|
||||
],
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<installation-title
|
||||
package-type="npm"
|
||||
:options="$options.installOptions"
|
||||
@change="instructionType = $event"
|
||||
/>
|
||||
|
||||
<code-instruction
|
||||
v-if="showNpm"
|
||||
:instruction="npmCommand"
|
||||
:copy-text="s__('PackageRegistry|Copy npm command')"
|
||||
:tracking-action="$options.trackingActions.COPY_NPM_INSTALL_COMMAND"
|
||||
:tracking-label="$options.TrackingLabels.CODE_INSTRUCTION"
|
||||
/>
|
||||
|
||||
<code-instruction
|
||||
v-else
|
||||
:instruction="yarnCommand"
|
||||
:copy-text="s__('PackageRegistry|Copy yarn command')"
|
||||
:tracking-action="$options.trackingActions.COPY_YARN_INSTALL_COMMAND"
|
||||
:tracking-label="$options.TrackingLabels.CODE_INSTRUCTION"
|
||||
/>
|
||||
|
||||
<h3 class="gl-font-lg">{{ __('Registry setup') }}</h3>
|
||||
|
||||
<code-instruction
|
||||
v-if="showNpm"
|
||||
:instruction="npmSetup"
|
||||
:copy-text="s__('PackageRegistry|Copy npm setup command')"
|
||||
:tracking-action="$options.trackingActions.COPY_NPM_SETUP_COMMAND"
|
||||
:tracking-label="$options.TrackingLabels.CODE_INSTRUCTION"
|
||||
/>
|
||||
|
||||
<code-instruction
|
||||
v-else
|
||||
:instruction="yarnSetupCommand"
|
||||
:copy-text="s__('PackageRegistry|Copy yarn setup command')"
|
||||
:tracking-action="$options.trackingActions.COPY_YARN_SETUP_COMMAND"
|
||||
:tracking-label="$options.TrackingLabels.CODE_INSTRUCTION"
|
||||
/>
|
||||
|
||||
<gl-sprintf :message="$options.i18n.helpText">
|
||||
<template #link="{ content }">
|
||||
<gl-link :href="npmHelpPath" target="_blank">{{ content }}</gl-link>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
<script>
|
||||
import { GlLink, GlSprintf } from '@gitlab/ui';
|
||||
import { mapGetters, mapState } from 'vuex';
|
||||
import { s__ } from '~/locale';
|
||||
import InstallationTitle from '~/packages/details/components/installation_title.vue';
|
||||
import CodeInstruction from '~/vue_shared/components/registry/code_instruction.vue';
|
||||
import { TrackingActions, TrackingLabels } from '../constants';
|
||||
|
||||
export default {
|
||||
name: 'NugetInstallation',
|
||||
components: {
|
||||
InstallationTitle,
|
||||
CodeInstruction,
|
||||
GlLink,
|
||||
GlSprintf,
|
||||
},
|
||||
computed: {
|
||||
...mapState(['nugetHelpPath']),
|
||||
...mapGetters(['nugetInstallationCommand', 'nugetSetupCommand']),
|
||||
},
|
||||
i18n: {
|
||||
helpText: s__(
|
||||
'PackageRegistry|For more information on the NuGet registry, %{linkStart}see the documentation%{linkEnd}.',
|
||||
),
|
||||
},
|
||||
trackingActions: { ...TrackingActions },
|
||||
TrackingLabels,
|
||||
installOptions: [{ value: 'nuget', label: s__('PackageRegistry|Show Nuget commands') }],
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<installation-title package-type="nuget" :options="$options.installOptions" />
|
||||
|
||||
<code-instruction
|
||||
:label="s__('PackageRegistry|NuGet Command')"
|
||||
:instruction="nugetInstallationCommand"
|
||||
:copy-text="s__('PackageRegistry|Copy NuGet Command')"
|
||||
:tracking-action="$options.trackingActions.COPY_NUGET_INSTALL_COMMAND"
|
||||
:tracking-label="$options.TrackingLabels.CODE_INSTRUCTION"
|
||||
/>
|
||||
<h3 class="gl-font-lg">{{ __('Registry setup') }}</h3>
|
||||
|
||||
<code-instruction
|
||||
:label="s__('PackageRegistry|Add NuGet Source')"
|
||||
:instruction="nugetSetupCommand"
|
||||
:copy-text="s__('PackageRegistry|Copy NuGet Setup Command')"
|
||||
:tracking-action="$options.trackingActions.COPY_NUGET_SETUP_COMMAND"
|
||||
:tracking-label="$options.TrackingLabels.CODE_INSTRUCTION"
|
||||
/>
|
||||
<gl-sprintf :message="$options.i18n.helpText">
|
||||
<template #link="{ content }">
|
||||
<gl-link :href="nugetHelpPath" target="_blank">{{ content }}</gl-link>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -1,113 +0,0 @@
|
|||
<script>
|
||||
/* eslint-disable vue/v-slot-style */
|
||||
import { GlIcon, GlSprintf, GlTooltipDirective, GlBadge } from '@gitlab/ui';
|
||||
import { GlBreakpointInstance } from '@gitlab/ui/dist/utils';
|
||||
import { mapState, mapGetters } from 'vuex';
|
||||
import { numberToHumanSize } from '~/lib/utils/number_utils';
|
||||
import { __ } from '~/locale';
|
||||
import MetadataItem from '~/vue_shared/components/registry/metadata_item.vue';
|
||||
import TitleArea from '~/vue_shared/components/registry/title_area.vue';
|
||||
import timeagoMixin from '~/vue_shared/mixins/timeago';
|
||||
import PackageTags from '../../shared/components/package_tags.vue';
|
||||
|
||||
export default {
|
||||
name: 'PackageTitle',
|
||||
components: {
|
||||
TitleArea,
|
||||
GlIcon,
|
||||
GlSprintf,
|
||||
PackageTags,
|
||||
MetadataItem,
|
||||
GlBadge,
|
||||
},
|
||||
directives: {
|
||||
GlTooltip: GlTooltipDirective,
|
||||
},
|
||||
mixins: [timeagoMixin],
|
||||
i18n: {
|
||||
packageInfo: __('v%{version} published %{timeAgo}'),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isDesktop: true,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState(['packageEntity', 'packageFiles']),
|
||||
...mapGetters(['packageTypeDisplay', 'packagePipeline', 'packageIcon']),
|
||||
hasTagsToDisplay() {
|
||||
return Boolean(this.packageEntity.tags && this.packageEntity.tags.length);
|
||||
},
|
||||
totalSize() {
|
||||
return numberToHumanSize(this.packageFiles.reduce((acc, p) => acc + p.size, 0));
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.isDesktop = GlBreakpointInstance.isDesktop();
|
||||
},
|
||||
methods: {
|
||||
dynamicSlotName(index) {
|
||||
return `metadata-tag${index}`;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<title-area :title="packageEntity.name" :avatar="packageIcon" data-qa-selector="package_title">
|
||||
<template #sub-header>
|
||||
<gl-icon name="eye" class="gl-mr-3" />
|
||||
<gl-sprintf :message="$options.i18n.packageInfo">
|
||||
<template #version>
|
||||
{{ packageEntity.version }}
|
||||
</template>
|
||||
|
||||
<template #timeAgo>
|
||||
<span v-gl-tooltip :title="tooltipTitle(packageEntity.created_at)">
|
||||
{{ timeFormatted(packageEntity.created_at) }}
|
||||
</span>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</template>
|
||||
|
||||
<template v-if="packageTypeDisplay" #metadata-type>
|
||||
<metadata-item data-testid="package-type" icon="package" :text="packageTypeDisplay" />
|
||||
</template>
|
||||
|
||||
<template #metadata-size>
|
||||
<metadata-item data-testid="package-size" icon="disk" :text="totalSize" />
|
||||
</template>
|
||||
|
||||
<template v-if="packagePipeline" #metadata-pipeline>
|
||||
<metadata-item
|
||||
data-testid="pipeline-project"
|
||||
icon="review-list"
|
||||
:text="packagePipeline.project.name"
|
||||
:link="packagePipeline.project.web_url"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template v-if="packagePipeline" #metadata-ref>
|
||||
<metadata-item data-testid="package-ref" icon="branch" :text="packagePipeline.ref" />
|
||||
</template>
|
||||
|
||||
<template v-if="isDesktop && hasTagsToDisplay" #metadata-tags>
|
||||
<package-tags :tag-display-limit="2" :tags="packageEntity.tags" hide-label />
|
||||
</template>
|
||||
|
||||
<!-- we need to duplicate the package tags on mobile to ensure proper styling inside the flex wrap -->
|
||||
<template
|
||||
v-for="(tag, index) in packageEntity.tags"
|
||||
v-else-if="hasTagsToDisplay"
|
||||
v-slot:[dynamicSlotName(index)]
|
||||
>
|
||||
<gl-badge :key="index" class="gl-my-1" data-testid="tag-badge" variant="info" size="sm">
|
||||
{{ tag.name }}
|
||||
</gl-badge>
|
||||
</template>
|
||||
|
||||
<template #right-actions>
|
||||
<slot name="delete-button"></slot>
|
||||
</template>
|
||||
</title-area>
|
||||
</template>
|
||||
|
|
@ -1,71 +0,0 @@
|
|||
<script>
|
||||
import { GlLink, GlSprintf } from '@gitlab/ui';
|
||||
import { mapGetters, mapState } from 'vuex';
|
||||
import { s__ } from '~/locale';
|
||||
import InstallationTitle from '~/packages/details/components/installation_title.vue';
|
||||
import CodeInstruction from '~/vue_shared/components/registry/code_instruction.vue';
|
||||
import { TrackingActions, TrackingLabels } from '../constants';
|
||||
|
||||
export default {
|
||||
name: 'PyPiInstallation',
|
||||
components: {
|
||||
InstallationTitle,
|
||||
CodeInstruction,
|
||||
GlLink,
|
||||
GlSprintf,
|
||||
},
|
||||
computed: {
|
||||
...mapState(['pypiHelpPath']),
|
||||
...mapGetters(['pypiPipCommand', 'pypiSetupCommand']),
|
||||
},
|
||||
i18n: {
|
||||
setupText: s__(
|
||||
`PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file.`,
|
||||
),
|
||||
helpText: s__(
|
||||
'PackageRegistry|For more information on the PyPi registry, %{linkStart}see the documentation%{linkEnd}.',
|
||||
),
|
||||
},
|
||||
trackingActions: { ...TrackingActions },
|
||||
TrackingLabels,
|
||||
installOptions: [{ value: 'pypi', label: s__('PackageRegistry|Show PyPi commands') }],
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<installation-title package-type="pypi" :options="$options.installOptions" />
|
||||
|
||||
<code-instruction
|
||||
:label="s__('PackageRegistry|Pip Command')"
|
||||
:instruction="pypiPipCommand"
|
||||
:copy-text="s__('PackageRegistry|Copy Pip command')"
|
||||
data-testid="pip-command"
|
||||
:tracking-action="$options.trackingActions.COPY_PIP_INSTALL_COMMAND"
|
||||
:tracking-label="$options.TrackingLabels.CODE_INSTRUCTION"
|
||||
/>
|
||||
|
||||
<h3 class="gl-font-lg">{{ __('Registry setup') }}</h3>
|
||||
<p>
|
||||
<gl-sprintf :message="$options.i18n.setupText">
|
||||
<template #code="{ content }">
|
||||
<code>{{ content }}</code>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</p>
|
||||
|
||||
<code-instruction
|
||||
:instruction="pypiSetupCommand"
|
||||
:copy-text="s__('PackageRegistry|Copy .pypirc content')"
|
||||
data-testid="pypi-setup-content"
|
||||
multiline
|
||||
:tracking-action="$options.trackingActions.COPY_PYPI_SETUP_COMMAND"
|
||||
:tracking-label="$options.TrackingLabels.CODE_INSTRUCTION"
|
||||
/>
|
||||
<gl-sprintf :message="$options.i18n.helpText">
|
||||
<template #link="{ content }">
|
||||
<gl-link :href="pypiHelpPath" target="_blank">{{ content }}</gl-link>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -6,6 +6,8 @@ module Types
|
|||
graphql_name 'Package'
|
||||
description 'Represents a package in the Package Registry. Note that this type is in beta and susceptible to changes'
|
||||
|
||||
connection_type_class(Types::CountableConnectionType)
|
||||
|
||||
authorize :read_package
|
||||
|
||||
field :id, ::Types::GlobalIDType[::Packages::Package], null: false,
|
||||
|
|
|
|||
|
|
@ -12,7 +12,8 @@ module IssueAvailableFeatures
|
|||
{
|
||||
assignee: %w(issue incident),
|
||||
confidentiality: %w(issue incident),
|
||||
time_tracking: %w(issue incident)
|
||||
time_tracking: %w(issue incident),
|
||||
move_and_clone: %w(issue incident)
|
||||
}.with_indifferent_access
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -542,6 +542,10 @@ class Issue < ApplicationRecord
|
|||
issue_type_supports?(:time_tracking)
|
||||
end
|
||||
|
||||
def supports_move_and_clone?
|
||||
issue_type_supports?(:move_and_clone)
|
||||
end
|
||||
|
||||
def email_participants_emails
|
||||
issue_email_participants.pluck(:email)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -8,13 +8,7 @@ module Issues
|
|||
@target_project = target_project
|
||||
@with_notes = with_notes
|
||||
|
||||
unless issue.can_clone?(current_user, target_project)
|
||||
raise CloneError, s_('CloneIssue|Cannot clone issue due to insufficient permissions!')
|
||||
end
|
||||
|
||||
if target_project.pending_delete?
|
||||
raise CloneError, s_('CloneIssue|Cannot clone issue to target project as it is pending deletion.')
|
||||
end
|
||||
verify_can_clone_issue!(issue, target_project)
|
||||
|
||||
super(issue, target_project)
|
||||
|
||||
|
|
@ -30,6 +24,20 @@ module Issues
|
|||
attr_reader :target_project
|
||||
attr_reader :with_notes
|
||||
|
||||
def verify_can_clone_issue!(issue, target_project)
|
||||
unless issue.supports_move_and_clone?
|
||||
raise CloneError, s_('CloneIssue|Cannot clone issues of \'%{issue_type}\' type.') % { issue_type: issue.issue_type }
|
||||
end
|
||||
|
||||
unless issue.can_clone?(current_user, target_project)
|
||||
raise CloneError, s_('CloneIssue|Cannot clone issue due to insufficient permissions!')
|
||||
end
|
||||
|
||||
if target_project.pending_delete?
|
||||
raise CloneError, s_('CloneIssue|Cannot clone issue to target project as it is pending deletion.')
|
||||
end
|
||||
end
|
||||
|
||||
def update_new_entity
|
||||
# we don't call `super` because we want to be able to decide whether or not to copy all comments over.
|
||||
update_new_entity_description
|
||||
|
|
|
|||
|
|
@ -7,13 +7,7 @@ module Issues
|
|||
def execute(issue, target_project)
|
||||
@target_project = target_project
|
||||
|
||||
unless issue.can_move?(current_user, @target_project)
|
||||
raise MoveError, s_('MoveIssue|Cannot move issue due to insufficient permissions!')
|
||||
end
|
||||
|
||||
if @project == @target_project
|
||||
raise MoveError, s_('MoveIssue|Cannot move issue to project it originates from!')
|
||||
end
|
||||
verify_can_move_issue!(issue, target_project)
|
||||
|
||||
super
|
||||
|
||||
|
|
@ -32,6 +26,20 @@ module Issues
|
|||
|
||||
attr_reader :target_project
|
||||
|
||||
def verify_can_move_issue!(issue, target_project)
|
||||
unless issue.supports_move_and_clone?
|
||||
raise MoveError, s_('MoveIssue|Cannot move issues of \'%{issue_type}\' type.') % { issue_type: issue.issue_type }
|
||||
end
|
||||
|
||||
unless issue.can_move?(current_user, @target_project)
|
||||
raise MoveError, s_('MoveIssue|Cannot move issue due to insufficient permissions!')
|
||||
end
|
||||
|
||||
if @project == @target_project
|
||||
raise MoveError, s_('MoveIssue|Cannot move issue to project it originates from!')
|
||||
end
|
||||
end
|
||||
|
||||
def update_service_desk_sent_notifications
|
||||
return unless original_entity.from_service_desk?
|
||||
|
||||
|
|
|
|||
|
|
@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/337214
|
|||
milestone: '14.2'
|
||||
type: development
|
||||
group: group::source code
|
||||
default_enabled: false
|
||||
default_enabled: true
|
||||
|
|
|
|||
|
|
@ -64,6 +64,8 @@ Example of response
|
|||
"slug": "review-fix-foo-dfjre3",
|
||||
"external_url": "https://review-fix-foo-dfjre3.gitlab.example.com",
|
||||
"state": "available",
|
||||
"created_at": "2019-05-25T18:55:13.252Z",
|
||||
"updated_at": "2019-05-27T18:55:13.252Z",
|
||||
"last_deployment": {
|
||||
"id": 100,
|
||||
"iid": 34,
|
||||
|
|
@ -176,7 +178,9 @@ Example response:
|
|||
"name": "deploy",
|
||||
"slug": "deploy",
|
||||
"external_url": "https://deploy.gitlab.example.com",
|
||||
"state": "available"
|
||||
"state": "available",
|
||||
"created_at": "2019-05-25T18:55:13.252Z",
|
||||
"updated_at": "2019-05-27T18:55:13.252Z"
|
||||
}
|
||||
```
|
||||
|
||||
|
|
@ -210,7 +214,9 @@ Example response:
|
|||
"name": "staging",
|
||||
"slug": "staging",
|
||||
"external_url": "https://staging.gitlab.example.com",
|
||||
"state": "available"
|
||||
"state": "available",
|
||||
"created_at": "2019-05-25T18:55:13.252Z",
|
||||
"updated_at": "2019-05-27T18:55:13.252Z"
|
||||
}
|
||||
```
|
||||
|
||||
|
|
@ -302,6 +308,8 @@ Example response:
|
|||
"name": "deploy",
|
||||
"slug": "deploy",
|
||||
"external_url": "https://deploy.gitlab.example.com",
|
||||
"state": "stopped"
|
||||
"state": "stopped",
|
||||
"created_at": "2019-05-25T18:55:13.252Z",
|
||||
"updated_at": "2019-05-27T18:55:13.252Z"
|
||||
}
|
||||
```
|
||||
|
|
|
|||
|
|
@ -6510,6 +6510,7 @@ The connection type for [`Package`](#package).
|
|||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="packageconnectioncount"></a>`count` | [`Int!`](#int) | Total count of collection. |
|
||||
| <a id="packageconnectionedges"></a>`edges` | [`[PackageEdge]`](#packageedge) | A list of edges. |
|
||||
| <a id="packageconnectionnodes"></a>`nodes` | [`[Package]`](#package) | A list of nodes. |
|
||||
| <a id="packageconnectionpageinfo"></a>`pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
|
||||
|
|
@ -13534,7 +13535,7 @@ Returns [`[String!]`](#string).
|
|||
|
||||
##### `Repository.paginatedTree`
|
||||
|
||||
Paginated tree of the repository. Available only when feature flag `paginated_tree_graphql_query` is enabled. This flag is disabled by default, because the feature is experimental and is subject to change without notice.
|
||||
Paginated tree of the repository. Available only when feature flag `paginated_tree_graphql_query` is enabled. This flag is enabled by default.
|
||||
|
||||
Returns [`TreeConnection`](#treeconnection).
|
||||
|
||||
|
|
|
|||
|
|
@ -111,9 +111,9 @@ public folder (for example `/tmp/`) fixes the issue.
|
|||
##### `Name can contain only letters, digits, emojis ...`
|
||||
|
||||
```plaintext
|
||||
Name can contain only letters, digits, emojis, '_', '.', dash, space. It must start with letter,
|
||||
digit, emoji or '_'. and Path can contain only letters, digits, '_', '-' and '.'. Cannot start
|
||||
with '-', end in '.git' or end in '.atom'
|
||||
Name can contain only letters, digits, emojis, '_', '.', '+', dashes, or spaces. It must start with a letter,
|
||||
digit, emoji, or '_', and Path can contain only letters, digits, '_', '-', or '.'. It cannot start
|
||||
with '-', end in '.git', or end in '.atom'.
|
||||
```
|
||||
|
||||
The project name specified in `project_path` is not valid for one of the specified reasons.
|
||||
|
|
|
|||
|
|
@ -51,3 +51,14 @@ The following Rake tasks are available for use with GitLab:
|
|||
| [User management](user_management.md) | Perform user management tasks. |
|
||||
| [Webhooks administration](web_hooks.md) | Maintain project webhooks. |
|
||||
| [X.509 signatures](x509_signatures.md) | Update X.509 commit signatures, which can be useful if the certificate store changed. |
|
||||
|
||||
To list all available Rake tasks:
|
||||
|
||||
```shell
|
||||
# Omnibus GitLab
|
||||
sudo gitlab-rake -vT
|
||||
|
||||
# Installations from source
|
||||
cd /home/git/gitlab
|
||||
sudo -u git -H bundle exec rake -vT RAILS_ENV=production
|
||||
```
|
||||
|
|
|
|||
|
|
@ -82,6 +82,7 @@ table.supported-languages tr td:last-child {
|
|||
}
|
||||
|
||||
table.supported-languages ul {
|
||||
font-size: 1em;
|
||||
list-style-type: none;
|
||||
padding-left: 0px;
|
||||
margin-bottom: 0px;
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
With a [cluster management project](management_project.md) you can manage
|
||||
your cluster's deployment and applications through a repository in GitLab.
|
||||
|
||||
The Custer Management project template provides you a baseline to get
|
||||
The Cluster Management project template provides you a baseline to get
|
||||
started and flexibility to customize your project to your cluster's needs.
|
||||
For instance, you can:
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
module API
|
||||
module Entities
|
||||
class EnvironmentBasic < Grape::Entity
|
||||
expose :id, :name, :slug, :external_url
|
||||
expose :id, :name, :slug, :external_url, :created_at, :updated_at
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -220,12 +220,12 @@ module Gitlab
|
|||
# The character range \p{Alnum} overlaps with \u{00A9}-\u{1f9ff}
|
||||
# hence the Ruby warning.
|
||||
# https://gitlab.com/gitlab-org/gitlab/merge_requests/23165#not-easy-fixable
|
||||
@project_name_regex ||= /\A[\p{Alnum}\u{00A9}-\u{1f9ff}_][\p{Alnum}\p{Pd}\u{00A9}-\u{1f9ff}_\. ]*\z/.freeze
|
||||
@project_name_regex ||= /\A[\p{Alnum}\u{00A9}-\u{1f9ff}_][\p{Alnum}\p{Pd}\u{002B}\u{00A9}-\u{1f9ff}_\. ]*\z/.freeze
|
||||
end
|
||||
|
||||
def project_name_regex_message
|
||||
"can contain only letters, digits, emojis, '_', '.', dash, space. " \
|
||||
"It must start with letter, digit, emoji or '_'."
|
||||
"can contain only letters, digits, emojis, '_', '.', '+', dashes, or spaces. " \
|
||||
"It must start with a letter, digit, emoji, or '_'."
|
||||
end
|
||||
|
||||
def group_name_regex
|
||||
|
|
|
|||
|
|
@ -7106,6 +7106,9 @@ msgstr ""
|
|||
msgid "CloneIssue|Cannot clone issue to target project as it is pending deletion."
|
||||
msgstr ""
|
||||
|
||||
msgid "CloneIssue|Cannot clone issues of '%{issue_type}' type."
|
||||
msgstr ""
|
||||
|
||||
msgid "Cloned this issue to %{path_to_project}."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -22168,6 +22171,9 @@ msgstr ""
|
|||
msgid "MoveIssue|Cannot move issue to project it originates from!"
|
||||
msgstr ""
|
||||
|
||||
msgid "MoveIssue|Cannot move issues of '%{issue_type}' type."
|
||||
msgstr ""
|
||||
|
||||
msgid "Moved issue to %{label} column in the board."
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -45,10 +45,8 @@ RSpec.describe 'Infrastructure Registry' do
|
|||
|
||||
expect(page).to have_css('.packages-app h1[data-testid="title"]', text: terraform_module.name)
|
||||
|
||||
page.within(%Q([name="#{terraform_module.name}"])) do
|
||||
expect(page).to have_content('Provision instructions')
|
||||
expect(page).to have_content('Registry setup')
|
||||
end
|
||||
expect(page).to have_content('Provision instructions')
|
||||
expect(page).to have_content('Registry setup')
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@
|
|||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"count": { "type": "integer" },
|
||||
"pageInfo": { "type": "object" },
|
||||
"edges": { "type": "array" },
|
||||
"nodes": { "type": "array" }
|
||||
|
|
@ -72,6 +73,7 @@
|
|||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"count": { "type": "integer" },
|
||||
"pageInfo": { "type": "object" },
|
||||
"edges": { "type": "array" },
|
||||
"nodes": { "type": "array" }
|
||||
|
|
@ -91,6 +93,7 @@
|
|||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"count": { "type": "integer" },
|
||||
"pageInfo": { "type": "object" },
|
||||
"edges": { "type": "array" },
|
||||
"nodes": { "type": "array" }
|
||||
|
|
@ -106,6 +109,7 @@
|
|||
"properties": {
|
||||
"pageInfo": { "type": "object" },
|
||||
"edges": { "type": "array" },
|
||||
"count": { "type": "integer" },
|
||||
"nodes": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,9 @@
|
|||
"name",
|
||||
"slug",
|
||||
"external_url",
|
||||
"last_deployment"
|
||||
"state",
|
||||
"created_at",
|
||||
"updated_at"
|
||||
],
|
||||
"properties": {
|
||||
"id": { "type": "integer" },
|
||||
|
|
@ -19,6 +21,9 @@
|
|||
]
|
||||
},
|
||||
"state": { "type": "string" },
|
||||
"created_at": { "type": "string", "format": "date-time" },
|
||||
"updated_at": { "type": "string", "format": "date-time" },
|
||||
"project": { "$ref": "project.json" },
|
||||
"enable_advanced_logs_querying": { "type": "boolean" },
|
||||
"logs_api_path": { "type": "string" },
|
||||
"gitlab_managed_apps_logs_path": { "type": "string" }
|
||||
|
|
|
|||
|
|
@ -1,36 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`ConanInstallation renders all the messages 1`] = `
|
||||
<div>
|
||||
<installation-title-stub
|
||||
options="[object Object]"
|
||||
packagetype="conan"
|
||||
/>
|
||||
|
||||
<code-instruction-stub
|
||||
copytext="Copy Conan Command"
|
||||
instruction="foo/command"
|
||||
label="Conan Command"
|
||||
trackingaction="copy_conan_command"
|
||||
trackinglabel="code_instruction"
|
||||
/>
|
||||
|
||||
<h3
|
||||
class="gl-font-lg"
|
||||
>
|
||||
Registry setup
|
||||
</h3>
|
||||
|
||||
<code-instruction-stub
|
||||
copytext="Copy Conan Setup Command"
|
||||
instruction="foo/setup"
|
||||
label="Add Conan Remote"
|
||||
trackingaction="copy_conan_setup_command"
|
||||
trackinglabel="code_instruction"
|
||||
/>
|
||||
|
||||
<gl-sprintf-stub
|
||||
message="For more information on the Conan registry, %{linkStart}see the documentation%{linkEnd}."
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`DependencyRow renders full dependency 1`] = `
|
||||
<div
|
||||
class="gl-responsive-table-row"
|
||||
>
|
||||
<div
|
||||
class="table-section section-50"
|
||||
>
|
||||
<strong
|
||||
class="gl-text-body"
|
||||
>
|
||||
Test.Dependency
|
||||
</strong>
|
||||
|
||||
<span
|
||||
data-testid="target-framework"
|
||||
>
|
||||
(.NETStandard2.0)
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="table-section section-50 gl-display-flex gl-md-justify-content-end"
|
||||
data-testid="version-pattern"
|
||||
>
|
||||
<span
|
||||
class="gl-text-body"
|
||||
>
|
||||
2.3.7
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
|
@ -1,112 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`MavenInstallation groovy 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 Groovy DSL install command"
|
||||
instruction="foo/gradle/groovy/install"
|
||||
label="Gradle Groovy DSL install command"
|
||||
trackingaction="copy_gradle_install_command"
|
||||
trackinglabel="code_instruction"
|
||||
/>
|
||||
|
||||
<code-instruction-stub
|
||||
copytext="Copy add Gradle Groovy DSL repository command"
|
||||
instruction="foo/gradle/groovy/add/source"
|
||||
label="Add Gradle Groovy DSL repository command"
|
||||
multiline="true"
|
||||
trackingaction="copy_gradle_add_to_source_command"
|
||||
trackinglabel="code_instruction"
|
||||
/>
|
||||
</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],[object Object]"
|
||||
packagetype="maven"
|
||||
/>
|
||||
|
||||
<p>
|
||||
<gl-sprintf-stub
|
||||
message="Copy and paste this inside your %{codeStart}pom.xml%{codeEnd} %{codeStart}dependencies%{codeEnd} block."
|
||||
/>
|
||||
</p>
|
||||
|
||||
<code-instruction-stub
|
||||
copytext="Copy Maven XML"
|
||||
instruction="foo/xml"
|
||||
label=""
|
||||
multiline="true"
|
||||
trackingaction="copy_maven_xml"
|
||||
trackinglabel="code_instruction"
|
||||
/>
|
||||
|
||||
<code-instruction-stub
|
||||
copytext="Copy Maven command"
|
||||
instruction="foo/command"
|
||||
label="Maven Command"
|
||||
trackingaction="copy_maven_command"
|
||||
trackinglabel="code_instruction"
|
||||
/>
|
||||
|
||||
<h3
|
||||
class="gl-font-lg"
|
||||
>
|
||||
Registry setup
|
||||
</h3>
|
||||
|
||||
<p>
|
||||
<gl-sprintf-stub
|
||||
message="If you haven't already done so, you will need to add the below to your %{codeStart}pom.xml%{codeEnd} file."
|
||||
/>
|
||||
</p>
|
||||
|
||||
<code-instruction-stub
|
||||
copytext="Copy Maven registry XML"
|
||||
instruction="foo/setup"
|
||||
label=""
|
||||
multiline="true"
|
||||
trackingaction="copy_maven_setup_xml"
|
||||
trackinglabel="code_instruction"
|
||||
/>
|
||||
|
||||
<gl-sprintf-stub
|
||||
message="For more information on the Maven registry, %{linkStart}see the documentation%{linkEnd}."
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`NpmInstallation renders all the messages 1`] = `
|
||||
<div>
|
||||
<installation-title-stub
|
||||
options="[object Object],[object Object]"
|
||||
packagetype="npm"
|
||||
/>
|
||||
|
||||
<code-instruction-stub
|
||||
copytext="Copy npm command"
|
||||
instruction="npm i @Test/package"
|
||||
label=""
|
||||
trackingaction="copy_npm_install_command"
|
||||
trackinglabel="code_instruction"
|
||||
/>
|
||||
|
||||
<h3
|
||||
class="gl-font-lg"
|
||||
>
|
||||
Registry setup
|
||||
</h3>
|
||||
|
||||
<code-instruction-stub
|
||||
copytext="Copy npm setup command"
|
||||
instruction="echo @Test:registry=undefined/ >> .npmrc"
|
||||
label=""
|
||||
trackingaction="copy_npm_setup_command"
|
||||
trackinglabel="code_instruction"
|
||||
/>
|
||||
|
||||
<gl-sprintf-stub
|
||||
message="You may also need to setup authentication using an auth token. %{linkStart}See the documentation%{linkEnd} to find out more."
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`NugetInstallation renders all the messages 1`] = `
|
||||
<div>
|
||||
<installation-title-stub
|
||||
options="[object Object]"
|
||||
packagetype="nuget"
|
||||
/>
|
||||
|
||||
<code-instruction-stub
|
||||
copytext="Copy NuGet Command"
|
||||
instruction="foo/command"
|
||||
label="NuGet Command"
|
||||
trackingaction="copy_nuget_install_command"
|
||||
trackinglabel="code_instruction"
|
||||
/>
|
||||
|
||||
<h3
|
||||
class="gl-font-lg"
|
||||
>
|
||||
Registry setup
|
||||
</h3>
|
||||
|
||||
<code-instruction-stub
|
||||
copytext="Copy NuGet Setup Command"
|
||||
instruction="foo/setup"
|
||||
label="Add NuGet Source"
|
||||
trackingaction="copy_nuget_setup_command"
|
||||
trackinglabel="code_instruction"
|
||||
/>
|
||||
|
||||
<gl-sprintf-stub
|
||||
message="For more information on the NuGet registry, %{linkStart}see the documentation%{linkEnd}."
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
|
@ -1,168 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`PackageTitle renders with tags 1`] = `
|
||||
<div
|
||||
class="gl-display-flex gl-flex-direction-column"
|
||||
data-qa-selector="package_title"
|
||||
>
|
||||
<div
|
||||
class="gl-display-flex gl-justify-content-space-between gl-py-3"
|
||||
>
|
||||
<div
|
||||
class="gl-flex-direction-column gl-flex-grow-1"
|
||||
>
|
||||
<div
|
||||
class="gl-display-flex"
|
||||
>
|
||||
<!---->
|
||||
|
||||
<div
|
||||
class="gl-display-flex gl-flex-direction-column"
|
||||
>
|
||||
<h1
|
||||
class="gl-font-size-h1 gl-mt-3 gl-mb-2"
|
||||
data-testid="title"
|
||||
>
|
||||
Test package
|
||||
</h1>
|
||||
|
||||
<div
|
||||
class="gl-display-flex gl-align-items-center gl-text-gray-500 gl-mt-1"
|
||||
>
|
||||
<gl-icon-stub
|
||||
class="gl-mr-3"
|
||||
name="eye"
|
||||
size="16"
|
||||
/>
|
||||
|
||||
<gl-sprintf-stub
|
||||
message="v%{version} published %{timeAgo}"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="gl-display-flex gl-flex-wrap gl-align-items-center gl-mt-3"
|
||||
>
|
||||
<div
|
||||
class="gl-display-flex gl-align-items-center gl-mr-5"
|
||||
>
|
||||
<metadata-item-stub
|
||||
data-testid="package-type"
|
||||
icon="package"
|
||||
link=""
|
||||
size="s"
|
||||
text="maven"
|
||||
texttooltip=""
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="gl-display-flex gl-align-items-center gl-mr-5"
|
||||
>
|
||||
<metadata-item-stub
|
||||
data-testid="package-size"
|
||||
icon="disk"
|
||||
link=""
|
||||
size="s"
|
||||
text="300 bytes"
|
||||
texttooltip=""
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="gl-display-flex gl-align-items-center gl-mr-5"
|
||||
>
|
||||
<package-tags-stub
|
||||
hidelabel="true"
|
||||
tagdisplaylimit="2"
|
||||
tags="[object Object],[object Object],[object Object],[object Object]"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!---->
|
||||
</div>
|
||||
|
||||
<p />
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`PackageTitle renders without tags 1`] = `
|
||||
<div
|
||||
class="gl-display-flex gl-flex-direction-column"
|
||||
data-qa-selector="package_title"
|
||||
>
|
||||
<div
|
||||
class="gl-display-flex gl-justify-content-space-between gl-py-3"
|
||||
>
|
||||
<div
|
||||
class="gl-flex-direction-column gl-flex-grow-1"
|
||||
>
|
||||
<div
|
||||
class="gl-display-flex"
|
||||
>
|
||||
<!---->
|
||||
|
||||
<div
|
||||
class="gl-display-flex gl-flex-direction-column"
|
||||
>
|
||||
<h1
|
||||
class="gl-font-size-h1 gl-mt-3 gl-mb-2"
|
||||
data-testid="title"
|
||||
>
|
||||
Test package
|
||||
</h1>
|
||||
|
||||
<div
|
||||
class="gl-display-flex gl-align-items-center gl-text-gray-500 gl-mt-1"
|
||||
>
|
||||
<gl-icon-stub
|
||||
class="gl-mr-3"
|
||||
name="eye"
|
||||
size="16"
|
||||
/>
|
||||
|
||||
<gl-sprintf-stub
|
||||
message="v%{version} published %{timeAgo}"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="gl-display-flex gl-flex-wrap gl-align-items-center gl-mt-3"
|
||||
>
|
||||
<div
|
||||
class="gl-display-flex gl-align-items-center gl-mr-5"
|
||||
>
|
||||
<metadata-item-stub
|
||||
data-testid="package-type"
|
||||
icon="package"
|
||||
link=""
|
||||
size="s"
|
||||
text="maven"
|
||||
texttooltip=""
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="gl-display-flex gl-align-items-center gl-mr-5"
|
||||
>
|
||||
<metadata-item-stub
|
||||
data-testid="package-size"
|
||||
icon="disk"
|
||||
link=""
|
||||
size="s"
|
||||
text="300 bytes"
|
||||
texttooltip=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!---->
|
||||
</div>
|
||||
|
||||
<p />
|
||||
</div>
|
||||
`;
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`PypiInstallation renders all the messages 1`] = `
|
||||
<div>
|
||||
<installation-title-stub
|
||||
options="[object Object]"
|
||||
packagetype="pypi"
|
||||
/>
|
||||
|
||||
<code-instruction-stub
|
||||
copytext="Copy Pip command"
|
||||
data-testid="pip-command"
|
||||
instruction="pip install"
|
||||
label="Pip Command"
|
||||
trackingaction="copy_pip_install_command"
|
||||
trackinglabel="code_instruction"
|
||||
/>
|
||||
|
||||
<h3
|
||||
class="gl-font-lg"
|
||||
>
|
||||
Registry setup
|
||||
</h3>
|
||||
|
||||
<p>
|
||||
<gl-sprintf-stub
|
||||
message="If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
|
||||
/>
|
||||
</p>
|
||||
|
||||
<code-instruction-stub
|
||||
copytext="Copy .pypirc content"
|
||||
data-testid="pypi-setup-content"
|
||||
instruction="python setup"
|
||||
label=""
|
||||
multiline="true"
|
||||
trackingaction="copy_pypi_setup_command"
|
||||
trackinglabel="code_instruction"
|
||||
/>
|
||||
|
||||
<gl-sprintf-stub
|
||||
message="For more information on the PyPi registry, %{linkStart}see the documentation%{linkEnd}."
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
|
@ -1,119 +0,0 @@
|
|||
import { GlLink, GlSprintf } from '@gitlab/ui';
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import component from '~/packages/details/components/additional_metadata.vue';
|
||||
import DetailsRow from '~/vue_shared/components/registry/details_row.vue';
|
||||
|
||||
import { mavenPackage, conanPackage, nugetPackage, npmPackage } from '../../mock_data';
|
||||
|
||||
describe('Package Additional Metadata', () => {
|
||||
let wrapper;
|
||||
const defaultProps = {
|
||||
packageEntity: { ...mavenPackage },
|
||||
};
|
||||
|
||||
const mountComponent = (props) => {
|
||||
wrapper = shallowMount(component, {
|
||||
propsData: { ...defaultProps, ...props },
|
||||
stubs: {
|
||||
DetailsRow,
|
||||
GlSprintf,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
wrapper = null;
|
||||
});
|
||||
|
||||
const findTitle = () => wrapper.find('[data-testid="title"]');
|
||||
const findMainArea = () => wrapper.find('[data-testid="main"]');
|
||||
const findNugetSource = () => wrapper.find('[data-testid="nuget-source"]');
|
||||
const findNugetLicense = () => wrapper.find('[data-testid="nuget-license"]');
|
||||
const findConanRecipe = () => wrapper.find('[data-testid="conan-recipe"]');
|
||||
const findMavenApp = () => wrapper.find('[data-testid="maven-app"]');
|
||||
const findMavenGroup = () => wrapper.find('[data-testid="maven-group"]');
|
||||
const findElementLink = (container) => container.find(GlLink);
|
||||
|
||||
it('has the correct title', () => {
|
||||
mountComponent();
|
||||
|
||||
const title = findTitle();
|
||||
|
||||
expect(title.exists()).toBe(true);
|
||||
expect(title.text()).toBe('Additional Metadata');
|
||||
});
|
||||
|
||||
describe.each`
|
||||
packageEntity | visible | metadata
|
||||
${mavenPackage} | ${true} | ${'maven_metadatum'}
|
||||
${conanPackage} | ${true} | ${'conan_metadatum'}
|
||||
${nugetPackage} | ${true} | ${'nuget_metadatum'}
|
||||
${npmPackage} | ${false} | ${null}
|
||||
`('Component visibility', ({ packageEntity, visible, metadata }) => {
|
||||
it(`Is ${visible} that the component markup is visible when the package is ${packageEntity.package_type}`, () => {
|
||||
mountComponent({ packageEntity });
|
||||
|
||||
expect(findTitle().exists()).toBe(visible);
|
||||
expect(findMainArea().exists()).toBe(visible);
|
||||
});
|
||||
|
||||
it(`The component is hidden if ${metadata} is missing`, () => {
|
||||
mountComponent({ packageEntity: { ...packageEntity, [metadata]: null } });
|
||||
|
||||
expect(findTitle().exists()).toBe(false);
|
||||
expect(findMainArea().exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('nuget metadata', () => {
|
||||
beforeEach(() => {
|
||||
mountComponent({ packageEntity: nugetPackage });
|
||||
});
|
||||
|
||||
it.each`
|
||||
name | finderFunction | text | link | icon
|
||||
${'source'} | ${findNugetSource} | ${'Source project located at project-foo-url'} | ${'project_url'} | ${'project'}
|
||||
${'license'} | ${findNugetLicense} | ${'License information located at license-foo-url'} | ${'license_url'} | ${'license'}
|
||||
`('$name element', ({ finderFunction, text, link, icon }) => {
|
||||
const element = finderFunction();
|
||||
expect(element.exists()).toBe(true);
|
||||
expect(element.text()).toBe(text);
|
||||
expect(element.props('icon')).toBe(icon);
|
||||
expect(findElementLink(element).attributes('href')).toBe(nugetPackage.nuget_metadatum[link]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('conan metadata', () => {
|
||||
beforeEach(() => {
|
||||
mountComponent({ packageEntity: conanPackage });
|
||||
});
|
||||
|
||||
it.each`
|
||||
name | finderFunction | text | icon
|
||||
${'recipe'} | ${findConanRecipe} | ${'Recipe: conan-package/1.0.0@conan+conan-package/stable'} | ${'information-o'}
|
||||
`('$name element', ({ finderFunction, text, icon }) => {
|
||||
const element = finderFunction();
|
||||
expect(element.exists()).toBe(true);
|
||||
expect(element.text()).toBe(text);
|
||||
expect(element.props('icon')).toBe(icon);
|
||||
});
|
||||
});
|
||||
|
||||
describe('maven metadata', () => {
|
||||
beforeEach(() => {
|
||||
mountComponent();
|
||||
});
|
||||
|
||||
it.each`
|
||||
name | finderFunction | text | icon
|
||||
${'app'} | ${findMavenApp} | ${'App name: test-app'} | ${'information-o'}
|
||||
${'group'} | ${findMavenGroup} | ${'App group: com.test.app'} | ${'information-o'}
|
||||
`('$name element', ({ finderFunction, text, icon }) => {
|
||||
const element = finderFunction();
|
||||
expect(element.exists()).toBe(true);
|
||||
expect(element.text()).toBe(text);
|
||||
expect(element.props('icon')).toBe(icon);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -5,28 +5,19 @@ import Vuex from 'vuex';
|
|||
import { useMockLocationHelper } from 'helpers/mock_window_location_helper';
|
||||
import stubChildren from 'helpers/stub_children';
|
||||
|
||||
import AdditionalMetadata from '~/packages/details/components/additional_metadata.vue';
|
||||
import PackagesApp from '~/packages/details/components/app.vue';
|
||||
import DependencyRow from '~/packages/details/components/dependency_row.vue';
|
||||
import InstallationCommands from '~/packages/details/components/installation_commands.vue';
|
||||
import PackageFiles from '~/packages/details/components/package_files.vue';
|
||||
import PackageHistory from '~/packages/details/components/package_history.vue';
|
||||
import PackageTitle from '~/packages/details/components/package_title.vue';
|
||||
import * as getters from '~/packages/details/store/getters';
|
||||
import PackageListRow from '~/packages/shared/components/package_list_row.vue';
|
||||
import PackagesListLoader from '~/packages/shared/components/packages_list_loader.vue';
|
||||
import { TrackingActions } from '~/packages/shared/constants';
|
||||
import * as SharedUtils from '~/packages/shared/utils';
|
||||
import TerraformTitle from '~/packages_and_registries/infrastructure_registry/components/details_title.vue';
|
||||
import TerraformInstallation from '~/packages_and_registries/infrastructure_registry/components/terraform_installation.vue';
|
||||
import Tracking from '~/tracking';
|
||||
|
||||
import {
|
||||
composerPackage,
|
||||
conanPackage,
|
||||
mavenPackage,
|
||||
mavenFiles,
|
||||
npmPackage,
|
||||
nugetPackage,
|
||||
} from '../../mock_data';
|
||||
import { mavenPackage, mavenFiles, npmPackage } from '../../mock_data';
|
||||
|
||||
const localVue = createLocalVue();
|
||||
localVue.use(Vuex);
|
||||
|
|
@ -73,7 +64,7 @@ describe('PackagesApp', () => {
|
|||
store,
|
||||
stubs: {
|
||||
...stubChildren(PackagesApp),
|
||||
PackageTitle: false,
|
||||
TerraformTitle: false,
|
||||
TitleArea: false,
|
||||
GlButton: false,
|
||||
GlModal: false,
|
||||
|
|
@ -84,23 +75,18 @@ describe('PackagesApp', () => {
|
|||
});
|
||||
}
|
||||
|
||||
const packageTitle = () => wrapper.find(PackageTitle);
|
||||
const emptyState = () => wrapper.find(GlEmptyState);
|
||||
const packageTitle = () => wrapper.findComponent(TerraformTitle);
|
||||
const emptyState = () => wrapper.findComponent(GlEmptyState);
|
||||
const deleteButton = () => wrapper.find('.js-delete-button');
|
||||
const findDeleteModal = () => wrapper.find({ ref: 'deleteModal' });
|
||||
const findDeleteFileModal = () => wrapper.find({ ref: 'deleteFileModal' });
|
||||
const versionsTab = () => wrapper.find('.js-versions-tab > a');
|
||||
const packagesLoader = () => wrapper.find(PackagesListLoader);
|
||||
const packagesVersionRows = () => wrapper.findAll(PackageListRow);
|
||||
const packagesLoader = () => wrapper.findComponent(PackagesListLoader);
|
||||
const packagesVersionRows = () => wrapper.findAllComponents(PackageListRow);
|
||||
const noVersionsMessage = () => wrapper.find('[data-testid="no-versions-message"]');
|
||||
const dependenciesTab = () => wrapper.find('.js-dependencies-tab > a');
|
||||
const dependenciesCountBadge = () => wrapper.find('[data-testid="dependencies-badge"]');
|
||||
const noDependenciesMessage = () => wrapper.find('[data-testid="no-dependencies-message"]');
|
||||
const dependencyRows = () => wrapper.findAll(DependencyRow);
|
||||
const findPackageHistory = () => wrapper.find(PackageHistory);
|
||||
const findAdditionalMetadata = () => wrapper.find(AdditionalMetadata);
|
||||
const findInstallationCommands = () => wrapper.find(InstallationCommands);
|
||||
const findPackageFiles = () => wrapper.find(PackageFiles);
|
||||
const findPackageHistory = () => wrapper.findComponent(PackageHistory);
|
||||
const findTerraformInstallation = () => wrapper.findComponent(TerraformInstallation);
|
||||
const findPackageFiles = () => wrapper.findComponent(PackageFiles);
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
|
|
@ -129,21 +115,10 @@ describe('PackagesApp', () => {
|
|||
expect(findPackageHistory().props('projectName')).toEqual(wrapper.vm.projectName);
|
||||
});
|
||||
|
||||
it('additional metadata has the right props', () => {
|
||||
it('terraform installation exists', () => {
|
||||
createComponent();
|
||||
expect(findAdditionalMetadata().exists()).toBe(true);
|
||||
expect(findAdditionalMetadata().props('packageEntity')).toEqual(wrapper.vm.packageEntity);
|
||||
});
|
||||
|
||||
it('installation commands has the right props', () => {
|
||||
createComponent();
|
||||
expect(findInstallationCommands().exists()).toBe(true);
|
||||
expect(findInstallationCommands().props('packageEntity')).toEqual(wrapper.vm.packageEntity);
|
||||
});
|
||||
|
||||
it('hides the files table if package type is COMPOSER', () => {
|
||||
createComponent({ packageEntity: composerPackage });
|
||||
expect(findPackageFiles().exists()).toBe(false);
|
||||
expect(findTerraformInstallation().exists()).toBe(true);
|
||||
});
|
||||
|
||||
describe('deleting packages', () => {
|
||||
|
|
@ -198,45 +173,6 @@ describe('PackagesApp', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('dependency links', () => {
|
||||
it('does not show the dependency links for a non nuget package', () => {
|
||||
createComponent();
|
||||
|
||||
expect(dependenciesTab().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('shows the dependencies tab with 0 count when a nuget package with no dependencies', () => {
|
||||
createComponent({
|
||||
packageEntity: {
|
||||
...nugetPackage,
|
||||
dependency_links: [],
|
||||
},
|
||||
});
|
||||
|
||||
return wrapper.vm.$nextTick(() => {
|
||||
const dependenciesBadge = dependenciesCountBadge();
|
||||
|
||||
expect(dependenciesTab().exists()).toBe(true);
|
||||
expect(dependenciesBadge.exists()).toBe(true);
|
||||
expect(dependenciesBadge.text()).toBe('0');
|
||||
expect(noDependenciesMessage().exists()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
it('renders the correct number of dependency rows for a nuget package', () => {
|
||||
createComponent({ packageEntity: nugetPackage });
|
||||
|
||||
return wrapper.vm.$nextTick(() => {
|
||||
const dependenciesBadge = dependenciesCountBadge();
|
||||
|
||||
expect(dependenciesTab().exists()).toBe(true);
|
||||
expect(dependenciesBadge.exists()).toBe(true);
|
||||
expect(dependenciesBadge.text()).toBe(nugetPackage.dependency_links.length.toString());
|
||||
expect(dependencyRows()).toHaveLength(nugetPackage.dependency_links.length);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('tracking and delete', () => {
|
||||
describe('delete package', () => {
|
||||
const originalReferrer = document.referrer;
|
||||
|
|
@ -305,9 +241,9 @@ describe('PackagesApp', () => {
|
|||
});
|
||||
|
||||
it('tracking category calls packageTypeToTrackCategory', () => {
|
||||
createComponent({ packageEntity: conanPackage });
|
||||
createComponent({ packageEntity: npmPackage });
|
||||
expect(wrapper.vm.tracking.category).toBe(category);
|
||||
expect(utilSpy).toHaveBeenCalledWith('conan');
|
||||
expect(utilSpy).toHaveBeenCalledWith('npm');
|
||||
});
|
||||
|
||||
it(`delete button on delete modal call event with ${TrackingActions.DELETE_PACKAGE}`, () => {
|
||||
|
|
@ -371,7 +307,7 @@ describe('PackagesApp', () => {
|
|||
});
|
||||
|
||||
it(`file download link call event with ${TrackingActions.PULL_PACKAGE}`, () => {
|
||||
createComponent({ packageEntity: conanPackage });
|
||||
createComponent({ packageEntity: npmPackage });
|
||||
|
||||
findPackageFiles().vm.$emit('download-file');
|
||||
expect(eventSpy).toHaveBeenCalledWith(
|
||||
|
|
|
|||
|
|
@ -1,133 +0,0 @@
|
|||
import { GlSprintf, GlLink } from '@gitlab/ui';
|
||||
import { shallowMount, createLocalVue } from '@vue/test-utils';
|
||||
import Vuex from 'vuex';
|
||||
import { registryUrl as composerHelpPath } from 'jest/packages/details/mock_data';
|
||||
import { composerPackage as packageEntity } from 'jest/packages/mock_data';
|
||||
import ComposerInstallation from '~/packages/details/components/composer_installation.vue';
|
||||
import InstallationTitle from '~/packages/details/components/installation_title.vue';
|
||||
|
||||
import { TrackingActions } from '~/packages/details/constants';
|
||||
|
||||
const localVue = createLocalVue();
|
||||
localVue.use(Vuex);
|
||||
|
||||
describe('ComposerInstallation', () => {
|
||||
let wrapper;
|
||||
let store;
|
||||
|
||||
const composerRegistryIncludeStr = 'foo/registry';
|
||||
const composerPackageIncludeStr = 'foo/package';
|
||||
|
||||
const createStore = (groupExists = true) => {
|
||||
store = new Vuex.Store({
|
||||
state: { packageEntity, composerHelpPath },
|
||||
getters: {
|
||||
composerRegistryInclude: () => composerRegistryIncludeStr,
|
||||
composerPackageInclude: () => composerPackageIncludeStr,
|
||||
groupExists: () => groupExists,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const findRootNode = () => wrapper.find('[data-testid="root-node"]');
|
||||
const findRegistryInclude = () => wrapper.find('[data-testid="registry-include"]');
|
||||
const findPackageInclude = () => wrapper.find('[data-testid="package-include"]');
|
||||
const findHelpText = () => wrapper.find('[data-testid="help-text"]');
|
||||
const findHelpLink = () => wrapper.find(GlLink);
|
||||
const findInstallationTitle = () => wrapper.findComponent(InstallationTitle);
|
||||
|
||||
function createComponent() {
|
||||
wrapper = shallowMount(ComposerInstallation, {
|
||||
localVue,
|
||||
store,
|
||||
stubs: {
|
||||
GlSprintf,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
});
|
||||
|
||||
describe('install command switch', () => {
|
||||
it('has the installation title component', () => {
|
||||
createStore();
|
||||
createComponent();
|
||||
|
||||
expect(findInstallationTitle().exists()).toBe(true);
|
||||
expect(findInstallationTitle().props()).toMatchObject({
|
||||
packageType: 'composer',
|
||||
options: [{ value: 'composer', label: 'Show Composer commands' }],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('registry include command', () => {
|
||||
beforeEach(() => {
|
||||
createStore();
|
||||
createComponent();
|
||||
});
|
||||
|
||||
it('uses code_instructions', () => {
|
||||
const registryIncludeCommand = findRegistryInclude();
|
||||
expect(registryIncludeCommand.exists()).toBe(true);
|
||||
expect(registryIncludeCommand.props()).toMatchObject({
|
||||
instruction: composerRegistryIncludeStr,
|
||||
copyText: 'Copy registry include',
|
||||
trackingAction: TrackingActions.COPY_COMPOSER_REGISTRY_INCLUDE_COMMAND,
|
||||
});
|
||||
});
|
||||
|
||||
it('has the correct title', () => {
|
||||
expect(findRegistryInclude().props('label')).toBe('Add composer registry');
|
||||
});
|
||||
});
|
||||
|
||||
describe('package include command', () => {
|
||||
beforeEach(() => {
|
||||
createStore();
|
||||
createComponent();
|
||||
});
|
||||
|
||||
it('uses code_instructions', () => {
|
||||
const registryIncludeCommand = findPackageInclude();
|
||||
expect(registryIncludeCommand.exists()).toBe(true);
|
||||
expect(registryIncludeCommand.props()).toMatchObject({
|
||||
instruction: composerPackageIncludeStr,
|
||||
copyText: 'Copy require package include',
|
||||
trackingAction: TrackingActions.COPY_COMPOSER_PACKAGE_INCLUDE_COMMAND,
|
||||
});
|
||||
});
|
||||
|
||||
it('has the correct title', () => {
|
||||
expect(findPackageInclude().props('label')).toBe('Install package version');
|
||||
});
|
||||
|
||||
it('has the correct help text', () => {
|
||||
expect(findHelpText().text()).toBe(
|
||||
'For more information on Composer packages in GitLab, see the documentation.',
|
||||
);
|
||||
expect(findHelpLink().attributes()).toMatchObject({
|
||||
href: composerHelpPath,
|
||||
target: '_blank',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('root node', () => {
|
||||
it('is normally rendered', () => {
|
||||
createStore();
|
||||
createComponent();
|
||||
|
||||
expect(findRootNode().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('is not rendered when the group does not exist', () => {
|
||||
createStore(false);
|
||||
createComponent();
|
||||
|
||||
expect(findRootNode().exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
import { shallowMount, createLocalVue } from '@vue/test-utils';
|
||||
import Vuex from 'vuex';
|
||||
import ConanInstallation from '~/packages/details/components/conan_installation.vue';
|
||||
import InstallationTitle from '~/packages/details/components/installation_title.vue';
|
||||
import CodeInstructions from '~/vue_shared/components/registry/code_instruction.vue';
|
||||
import { conanPackage as packageEntity } from '../../mock_data';
|
||||
import { registryUrl as conanPath } from '../mock_data';
|
||||
|
||||
const localVue = createLocalVue();
|
||||
localVue.use(Vuex);
|
||||
|
||||
describe('ConanInstallation', () => {
|
||||
let wrapper;
|
||||
|
||||
const conanInstallationCommandStr = 'foo/command';
|
||||
const conanSetupCommandStr = 'foo/setup';
|
||||
|
||||
const store = new Vuex.Store({
|
||||
state: {
|
||||
packageEntity,
|
||||
conanPath,
|
||||
},
|
||||
getters: {
|
||||
conanInstallationCommand: () => conanInstallationCommandStr,
|
||||
conanSetupCommand: () => conanSetupCommandStr,
|
||||
},
|
||||
});
|
||||
|
||||
const findCodeInstructions = () => wrapper.findAll(CodeInstructions);
|
||||
const findInstallationTitle = () => wrapper.findComponent(InstallationTitle);
|
||||
|
||||
function createComponent() {
|
||||
wrapper = shallowMount(ConanInstallation, {
|
||||
localVue,
|
||||
store,
|
||||
});
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
createComponent();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
});
|
||||
|
||||
it('renders all the messages', () => {
|
||||
expect(wrapper.element).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe('install command switch', () => {
|
||||
it('has the installation title component', () => {
|
||||
expect(findInstallationTitle().exists()).toBe(true);
|
||||
expect(findInstallationTitle().props()).toMatchObject({
|
||||
packageType: 'conan',
|
||||
options: [{ value: 'conan', label: 'Show Conan commands' }],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('installation commands', () => {
|
||||
it('renders the correct command', () => {
|
||||
expect(findCodeInstructions().at(0).props('instruction')).toBe(conanInstallationCommandStr);
|
||||
});
|
||||
});
|
||||
|
||||
describe('setup commands', () => {
|
||||
it('renders the correct command', () => {
|
||||
expect(findCodeInstructions().at(1).props('instruction')).toBe(conanSetupCommandStr);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
import { shallowMount } from '@vue/test-utils';
|
||||
import DependencyRow from '~/packages/details/components/dependency_row.vue';
|
||||
import { dependencyLinks } from '../../mock_data';
|
||||
|
||||
describe('DependencyRow', () => {
|
||||
let wrapper;
|
||||
|
||||
const { withoutFramework, withoutVersion, fullLink } = dependencyLinks;
|
||||
|
||||
function createComponent({ dependencyLink = fullLink } = {}) {
|
||||
wrapper = shallowMount(DependencyRow, {
|
||||
propsData: {
|
||||
dependency: dependencyLink,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const dependencyVersion = () => wrapper.find('[data-testid="version-pattern"]');
|
||||
const dependencyFramework = () => wrapper.find('[data-testid="target-framework"]');
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
});
|
||||
|
||||
describe('renders', () => {
|
||||
it('full dependency', () => {
|
||||
createComponent();
|
||||
|
||||
expect(wrapper.element).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('version', () => {
|
||||
it('does not render any version information when not supplied', () => {
|
||||
createComponent({ dependencyLink: withoutVersion });
|
||||
|
||||
expect(dependencyVersion().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('does render version info when it exists', () => {
|
||||
createComponent();
|
||||
|
||||
expect(dependencyVersion().exists()).toBe(true);
|
||||
expect(dependencyVersion().text()).toBe(fullLink.version_pattern);
|
||||
});
|
||||
});
|
||||
|
||||
describe('target framework', () => {
|
||||
it('does not render any framework information when not supplied', () => {
|
||||
createComponent({ dependencyLink: withoutFramework });
|
||||
|
||||
expect(dependencyFramework().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('does render framework info when it exists', () => {
|
||||
createComponent();
|
||||
|
||||
expect(dependencyFramework().exists()).toBe(true);
|
||||
expect(dependencyFramework().text()).toBe(`(${fullLink.target_framework})`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
import { shallowMount } from '@vue/test-utils';
|
||||
|
||||
import InstallationTitle from '~/packages/details/components/installation_title.vue';
|
||||
import PersistedDropdownSelection from '~/vue_shared/components/registry/persisted_dropdown_selection.vue';
|
||||
|
||||
describe('InstallationTitle', () => {
|
||||
let wrapper;
|
||||
|
||||
const defaultProps = { packageType: 'foo', options: [{ value: 'foo', label: 'bar' }] };
|
||||
|
||||
const findPersistedDropdownSelection = () => wrapper.findComponent(PersistedDropdownSelection);
|
||||
const findTitle = () => wrapper.find('h3');
|
||||
|
||||
function createComponent({ props = {} } = {}) {
|
||||
wrapper = shallowMount(InstallationTitle, {
|
||||
propsData: {
|
||||
...defaultProps,
|
||||
...props,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
});
|
||||
|
||||
it('has a title', () => {
|
||||
createComponent();
|
||||
|
||||
expect(findTitle().exists()).toBe(true);
|
||||
expect(findTitle().text()).toBe('Installation');
|
||||
});
|
||||
|
||||
describe('persisted dropdown selection', () => {
|
||||
it('exists', () => {
|
||||
createComponent();
|
||||
|
||||
expect(findPersistedDropdownSelection().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('has the correct props', () => {
|
||||
createComponent();
|
||||
|
||||
expect(findPersistedDropdownSelection().props()).toMatchObject({
|
||||
storageKey: 'package_foo_installation_instructions',
|
||||
options: defaultProps.options,
|
||||
});
|
||||
});
|
||||
|
||||
it('on change event emits a change event', () => {
|
||||
createComponent();
|
||||
|
||||
findPersistedDropdownSelection().vm.$emit('change', 'baz');
|
||||
|
||||
expect(wrapper.emitted('change')).toEqual([['baz']]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
import { shallowMount } from '@vue/test-utils';
|
||||
import ComposerInstallation from '~/packages/details/components/composer_installation.vue';
|
||||
import ConanInstallation from '~/packages/details/components/conan_installation.vue';
|
||||
import InstallationCommands from '~/packages/details/components/installation_commands.vue';
|
||||
|
||||
import MavenInstallation from '~/packages/details/components/maven_installation.vue';
|
||||
import NpmInstallation from '~/packages/details/components/npm_installation.vue';
|
||||
import NugetInstallation from '~/packages/details/components/nuget_installation.vue';
|
||||
import PypiInstallation from '~/packages/details/components/pypi_installation.vue';
|
||||
import TerraformInstallation from '~/packages_and_registries/infrastructure_registry/components/terraform_installation.vue';
|
||||
|
||||
import {
|
||||
conanPackage,
|
||||
mavenPackage,
|
||||
npmPackage,
|
||||
nugetPackage,
|
||||
pypiPackage,
|
||||
composerPackage,
|
||||
terraformModule,
|
||||
} from '../../mock_data';
|
||||
|
||||
describe('InstallationCommands', () => {
|
||||
let wrapper;
|
||||
|
||||
function createComponent(propsData) {
|
||||
wrapper = shallowMount(InstallationCommands, {
|
||||
propsData,
|
||||
});
|
||||
}
|
||||
|
||||
const npmInstallation = () => wrapper.find(NpmInstallation);
|
||||
const mavenInstallation = () => wrapper.find(MavenInstallation);
|
||||
const conanInstallation = () => wrapper.find(ConanInstallation);
|
||||
const nugetInstallation = () => wrapper.find(NugetInstallation);
|
||||
const pypiInstallation = () => wrapper.find(PypiInstallation);
|
||||
const composerInstallation = () => wrapper.find(ComposerInstallation);
|
||||
const terraformInstallation = () => wrapper.findComponent(TerraformInstallation);
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
});
|
||||
|
||||
describe('installation instructions', () => {
|
||||
describe.each`
|
||||
packageEntity | selector
|
||||
${conanPackage} | ${conanInstallation}
|
||||
${mavenPackage} | ${mavenInstallation}
|
||||
${npmPackage} | ${npmInstallation}
|
||||
${nugetPackage} | ${nugetInstallation}
|
||||
${pypiPackage} | ${pypiInstallation}
|
||||
${composerPackage} | ${composerInstallation}
|
||||
${terraformModule} | ${terraformInstallation}
|
||||
`('renders', ({ packageEntity, selector }) => {
|
||||
it(`${packageEntity.package_type} instructions exist`, () => {
|
||||
createComponent({ packageEntity });
|
||||
|
||||
expect(selector()).toExist();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -1,184 +0,0 @@
|
|||
import { shallowMount, createLocalVue } from '@vue/test-utils';
|
||||
import { nextTick } from 'vue';
|
||||
import Vuex from 'vuex';
|
||||
import { registryUrl as mavenPath } from 'jest/packages/details/mock_data';
|
||||
import { mavenPackage as packageEntity } from 'jest/packages/mock_data';
|
||||
import InstallationTitle from '~/packages/details/components/installation_title.vue';
|
||||
import MavenInstallation from '~/packages/details/components/maven_installation.vue';
|
||||
import { TrackingActions } from '~/packages/details/constants';
|
||||
import CodeInstructions from '~/vue_shared/components/registry/code_instruction.vue';
|
||||
|
||||
const localVue = createLocalVue();
|
||||
localVue.use(Vuex);
|
||||
|
||||
describe('MavenInstallation', () => {
|
||||
let wrapper;
|
||||
|
||||
const xmlCodeBlock = 'foo/xml';
|
||||
const mavenCommandStr = 'foo/command';
|
||||
const mavenSetupXml = 'foo/setup';
|
||||
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: {
|
||||
packageEntity,
|
||||
mavenPath,
|
||||
},
|
||||
getters: {
|
||||
mavenInstallationXml: () => xmlCodeBlock,
|
||||
mavenInstallationCommand: () => mavenCommandStr,
|
||||
mavenSetupXml: () => mavenSetupXml,
|
||||
gradleGroovyInstalCommand: () => gradleGroovyInstallCommandText,
|
||||
gradleGroovyAddSourceCommand: () => gradleGroovyAddSourceCommandText,
|
||||
gradleKotlinInstalCommand: () => gradleKotlinInstallCommandText,
|
||||
gradleKotlinAddSourceCommand: () => gradleKotlinAddSourceCommandText,
|
||||
},
|
||||
});
|
||||
|
||||
const findCodeInstructions = () => wrapper.findAll(CodeInstructions);
|
||||
const findInstallationTitle = () => wrapper.findComponent(InstallationTitle);
|
||||
|
||||
function createComponent({ data = {} } = {}) {
|
||||
wrapper = shallowMount(MavenInstallation, {
|
||||
localVue,
|
||||
store,
|
||||
data() {
|
||||
return data;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
});
|
||||
|
||||
describe('install command switch', () => {
|
||||
it('has the installation title component', () => {
|
||||
createComponent();
|
||||
|
||||
expect(findInstallationTitle().exists()).toBe(true);
|
||||
expect(findInstallationTitle().props()).toMatchObject({
|
||||
packageType: 'maven',
|
||||
options: [
|
||||
{ value: 'maven', label: 'Maven XML' },
|
||||
{ value: 'groovy', label: 'Gradle Groovy DSL' },
|
||||
{ value: 'kotlin', label: 'Gradle Kotlin DSL' },
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it('on change event updates the instructions to show', async () => {
|
||||
createComponent();
|
||||
|
||||
expect(findCodeInstructions().at(0).props('instruction')).toBe(xmlCodeBlock);
|
||||
findInstallationTitle().vm.$emit('change', 'groovy');
|
||||
|
||||
await nextTick();
|
||||
|
||||
expect(findCodeInstructions().at(0).props('instruction')).toBe(
|
||||
gradleGroovyInstallCommandText,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('maven', () => {
|
||||
beforeEach(() => {
|
||||
createComponent();
|
||||
});
|
||||
|
||||
it('renders all the messages', () => {
|
||||
expect(wrapper.element).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe('installation commands', () => {
|
||||
it('renders the correct xml block', () => {
|
||||
expect(findCodeInstructions().at(0).props()).toMatchObject({
|
||||
instruction: xmlCodeBlock,
|
||||
multiline: true,
|
||||
trackingAction: TrackingActions.COPY_MAVEN_XML,
|
||||
});
|
||||
});
|
||||
|
||||
it('renders the correct maven command', () => {
|
||||
expect(findCodeInstructions().at(1).props()).toMatchObject({
|
||||
instruction: mavenCommandStr,
|
||||
multiline: false,
|
||||
trackingAction: TrackingActions.COPY_MAVEN_COMMAND,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('setup commands', () => {
|
||||
it('renders the correct xml block', () => {
|
||||
expect(findCodeInstructions().at(2).props()).toMatchObject({
|
||||
instruction: mavenSetupXml,
|
||||
multiline: true,
|
||||
trackingAction: TrackingActions.COPY_MAVEN_SETUP,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('groovy', () => {
|
||||
beforeEach(() => {
|
||||
createComponent({ data: { instructionType: 'groovy' } });
|
||||
});
|
||||
|
||||
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: gradleGroovyInstallCommandText,
|
||||
multiline: false,
|
||||
trackingAction: TrackingActions.COPY_GRADLE_INSTALL_COMMAND,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('setup commands', () => {
|
||||
it('renders the correct gradle command', () => {
|
||||
expect(findCodeInstructions().at(1).props()).toMatchObject({
|
||||
instruction: gradleGroovyAddSourceCommandText,
|
||||
multiline: true,
|
||||
trackingAction: TrackingActions.COPY_GRADLE_ADD_TO_SOURCE_COMMAND,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
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,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -1,123 +0,0 @@
|
|||
import { shallowMount, createLocalVue } from '@vue/test-utils';
|
||||
import { nextTick } from 'vue';
|
||||
import Vuex from 'vuex';
|
||||
import { registryUrl as nugetPath } from 'jest/packages/details/mock_data';
|
||||
import { npmPackage as packageEntity } from 'jest/packages/mock_data';
|
||||
import InstallationTitle from '~/packages/details/components/installation_title.vue';
|
||||
import NpmInstallation from '~/packages/details/components/npm_installation.vue';
|
||||
import { TrackingActions } from '~/packages/details/constants';
|
||||
import { npmInstallationCommand, npmSetupCommand } from '~/packages/details/store/getters';
|
||||
import CodeInstructions from '~/vue_shared/components/registry/code_instruction.vue';
|
||||
|
||||
const localVue = createLocalVue();
|
||||
localVue.use(Vuex);
|
||||
|
||||
describe('NpmInstallation', () => {
|
||||
let wrapper;
|
||||
|
||||
const npmInstallationCommandLabel = 'npm i @Test/package';
|
||||
const yarnInstallationCommandLabel = 'yarn add @Test/package';
|
||||
|
||||
const findCodeInstructions = () => wrapper.findAll(CodeInstructions);
|
||||
const findInstallationTitle = () => wrapper.findComponent(InstallationTitle);
|
||||
|
||||
function createComponent({ data = {} } = {}) {
|
||||
const store = new Vuex.Store({
|
||||
state: {
|
||||
packageEntity,
|
||||
nugetPath,
|
||||
},
|
||||
getters: {
|
||||
npmInstallationCommand,
|
||||
npmSetupCommand,
|
||||
},
|
||||
});
|
||||
|
||||
wrapper = shallowMount(NpmInstallation, {
|
||||
localVue,
|
||||
store,
|
||||
data() {
|
||||
return data;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
createComponent();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
});
|
||||
|
||||
it('renders all the messages', () => {
|
||||
expect(wrapper.element).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe('install command switch', () => {
|
||||
it('has the installation title component', () => {
|
||||
expect(findInstallationTitle().exists()).toBe(true);
|
||||
expect(findInstallationTitle().props()).toMatchObject({
|
||||
packageType: 'npm',
|
||||
options: [
|
||||
{ value: 'npm', label: 'Show NPM commands' },
|
||||
{ value: 'yarn', label: 'Show Yarn commands' },
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it('on change event updates the instructions to show', async () => {
|
||||
createComponent();
|
||||
|
||||
expect(findCodeInstructions().at(0).props('instruction')).toBe(npmInstallationCommandLabel);
|
||||
findInstallationTitle().vm.$emit('change', 'yarn');
|
||||
|
||||
await nextTick();
|
||||
|
||||
expect(findCodeInstructions().at(0).props('instruction')).toBe(yarnInstallationCommandLabel);
|
||||
});
|
||||
});
|
||||
|
||||
describe('npm', () => {
|
||||
beforeEach(() => {
|
||||
createComponent();
|
||||
});
|
||||
it('renders the correct installation command', () => {
|
||||
expect(findCodeInstructions().at(0).props()).toMatchObject({
|
||||
instruction: npmInstallationCommandLabel,
|
||||
multiline: false,
|
||||
trackingAction: TrackingActions.COPY_NPM_INSTALL_COMMAND,
|
||||
});
|
||||
});
|
||||
|
||||
it('renders the correct setup command', () => {
|
||||
expect(findCodeInstructions().at(1).props()).toMatchObject({
|
||||
instruction: 'echo @Test:registry=undefined/ >> .npmrc',
|
||||
multiline: false,
|
||||
trackingAction: TrackingActions.COPY_NPM_SETUP_COMMAND,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('yarn', () => {
|
||||
beforeEach(() => {
|
||||
createComponent({ data: { instructionType: 'yarn' } });
|
||||
});
|
||||
|
||||
it('renders the correct setup command', () => {
|
||||
expect(findCodeInstructions().at(0).props()).toMatchObject({
|
||||
instruction: yarnInstallationCommandLabel,
|
||||
multiline: false,
|
||||
trackingAction: TrackingActions.COPY_YARN_INSTALL_COMMAND,
|
||||
});
|
||||
});
|
||||
|
||||
it('renders the correct registry command', () => {
|
||||
expect(findCodeInstructions().at(1).props()).toMatchObject({
|
||||
instruction: 'echo \\"@Test:registry\\" \\"undefined/\\" >> .yarnrc',
|
||||
multiline: false,
|
||||
trackingAction: TrackingActions.COPY_YARN_SETUP_COMMAND,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
import { shallowMount, createLocalVue } from '@vue/test-utils';
|
||||
import Vuex from 'vuex';
|
||||
import { registryUrl as nugetPath } from 'jest/packages/details/mock_data';
|
||||
import { nugetPackage as packageEntity } from 'jest/packages/mock_data';
|
||||
import InstallationTitle from '~/packages/details/components/installation_title.vue';
|
||||
import NugetInstallation from '~/packages/details/components/nuget_installation.vue';
|
||||
import { TrackingActions } from '~/packages/details/constants';
|
||||
import CodeInstructions from '~/vue_shared/components/registry/code_instruction.vue';
|
||||
|
||||
const localVue = createLocalVue();
|
||||
localVue.use(Vuex);
|
||||
|
||||
describe('NugetInstallation', () => {
|
||||
let wrapper;
|
||||
|
||||
const nugetInstallationCommandStr = 'foo/command';
|
||||
const nugetSetupCommandStr = 'foo/setup';
|
||||
|
||||
const store = new Vuex.Store({
|
||||
state: {
|
||||
packageEntity,
|
||||
nugetPath,
|
||||
},
|
||||
getters: {
|
||||
nugetInstallationCommand: () => nugetInstallationCommandStr,
|
||||
nugetSetupCommand: () => nugetSetupCommandStr,
|
||||
},
|
||||
});
|
||||
|
||||
const findCodeInstructions = () => wrapper.findAll(CodeInstructions);
|
||||
const findInstallationTitle = () => wrapper.findComponent(InstallationTitle);
|
||||
|
||||
function createComponent() {
|
||||
wrapper = shallowMount(NugetInstallation, {
|
||||
localVue,
|
||||
store,
|
||||
});
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
createComponent();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
});
|
||||
|
||||
it('renders all the messages', () => {
|
||||
expect(wrapper.element).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe('install command switch', () => {
|
||||
it('has the installation title component', () => {
|
||||
expect(findInstallationTitle().exists()).toBe(true);
|
||||
expect(findInstallationTitle().props()).toMatchObject({
|
||||
packageType: 'nuget',
|
||||
options: [{ value: 'nuget', label: 'Show Nuget commands' }],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('installation commands', () => {
|
||||
it('renders the correct command', () => {
|
||||
expect(findCodeInstructions().at(0).props()).toMatchObject({
|
||||
instruction: nugetInstallationCommandStr,
|
||||
trackingAction: TrackingActions.COPY_NUGET_INSTALL_COMMAND,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('setup commands', () => {
|
||||
it('renders the correct command', () => {
|
||||
expect(findCodeInstructions().at(1).props()).toMatchObject({
|
||||
instruction: nugetSetupCommandStr,
|
||||
trackingAction: TrackingActions.COPY_NUGET_SETUP_COMMAND,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -1,189 +0,0 @@
|
|||
import { GlBreakpointInstance } from '@gitlab/ui/dist/utils';
|
||||
import { shallowMount, createLocalVue } from '@vue/test-utils';
|
||||
import Vuex from 'vuex';
|
||||
import PackageTitle from '~/packages/details/components/package_title.vue';
|
||||
import PackageTags from '~/packages/shared/components/package_tags.vue';
|
||||
import TitleArea from '~/vue_shared/components/registry/title_area.vue';
|
||||
import {
|
||||
conanPackage,
|
||||
mavenFiles,
|
||||
mavenPackage,
|
||||
mockTags,
|
||||
npmFiles,
|
||||
npmPackage,
|
||||
nugetPackage,
|
||||
} from '../../mock_data';
|
||||
|
||||
const localVue = createLocalVue();
|
||||
localVue.use(Vuex);
|
||||
|
||||
describe('PackageTitle', () => {
|
||||
let wrapper;
|
||||
let store;
|
||||
|
||||
function createComponent({
|
||||
packageEntity = mavenPackage,
|
||||
packageFiles = mavenFiles,
|
||||
icon = null,
|
||||
} = {}) {
|
||||
store = new Vuex.Store({
|
||||
state: {
|
||||
packageEntity,
|
||||
packageFiles,
|
||||
},
|
||||
getters: {
|
||||
packageTypeDisplay: ({ packageEntity: { package_type: type } }) => type,
|
||||
packagePipeline: ({ packageEntity: { pipeline = null } }) => pipeline,
|
||||
packageIcon: () => icon,
|
||||
},
|
||||
});
|
||||
|
||||
wrapper = shallowMount(PackageTitle, {
|
||||
localVue,
|
||||
store,
|
||||
stubs: {
|
||||
TitleArea,
|
||||
},
|
||||
});
|
||||
return wrapper.vm.$nextTick();
|
||||
}
|
||||
|
||||
const findTitleArea = () => wrapper.find(TitleArea);
|
||||
const packageType = () => wrapper.find('[data-testid="package-type"]');
|
||||
const packageSize = () => wrapper.find('[data-testid="package-size"]');
|
||||
const pipelineProject = () => wrapper.find('[data-testid="pipeline-project"]');
|
||||
const packageRef = () => wrapper.find('[data-testid="package-ref"]');
|
||||
const packageTags = () => wrapper.find(PackageTags);
|
||||
const packageBadges = () => wrapper.findAll('[data-testid="tag-badge"]');
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
});
|
||||
|
||||
describe('renders', () => {
|
||||
it('without tags', async () => {
|
||||
await createComponent();
|
||||
|
||||
expect(wrapper.element).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('with tags', async () => {
|
||||
await createComponent({ packageEntity: { ...mavenPackage, tags: mockTags } });
|
||||
|
||||
expect(wrapper.element).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('with tags on mobile', async () => {
|
||||
jest.spyOn(GlBreakpointInstance, 'isDesktop').mockReturnValue(false);
|
||||
await createComponent({ packageEntity: { ...mavenPackage, tags: mockTags } });
|
||||
await wrapper.vm.$nextTick();
|
||||
|
||||
expect(packageBadges()).toHaveLength(mockTags.length);
|
||||
});
|
||||
});
|
||||
|
||||
describe('package title', () => {
|
||||
it('is correctly bound', async () => {
|
||||
await createComponent();
|
||||
|
||||
expect(findTitleArea().props('title')).toBe('Test package');
|
||||
});
|
||||
});
|
||||
|
||||
describe('package icon', () => {
|
||||
const fakeSrc = 'a-fake-src';
|
||||
|
||||
it('binds an icon when provided one from vuex', async () => {
|
||||
await createComponent({ icon: fakeSrc });
|
||||
|
||||
expect(findTitleArea().props('avatar')).toBe(fakeSrc);
|
||||
});
|
||||
|
||||
it('do not binds an icon when not provided one', async () => {
|
||||
await createComponent();
|
||||
|
||||
expect(findTitleArea().props('avatar')).toBe(null);
|
||||
});
|
||||
});
|
||||
|
||||
describe.each`
|
||||
packageEntity | text
|
||||
${conanPackage} | ${'conan'}
|
||||
${mavenPackage} | ${'maven'}
|
||||
${npmPackage} | ${'npm'}
|
||||
${nugetPackage} | ${'nuget'}
|
||||
`(`package type`, ({ packageEntity, text }) => {
|
||||
beforeEach(() => createComponent({ packageEntity }));
|
||||
|
||||
it(`${packageEntity.package_type} should render from Vuex getters ${text}`, () => {
|
||||
expect(packageType().props()).toEqual(expect.objectContaining({ text, icon: 'package' }));
|
||||
});
|
||||
});
|
||||
|
||||
describe('calculates the package size', () => {
|
||||
it('correctly calculates when there is only 1 file', async () => {
|
||||
await createComponent({ packageEntity: npmPackage, packageFiles: npmFiles });
|
||||
|
||||
expect(packageSize().props()).toMatchObject({ text: '200 bytes', icon: 'disk' });
|
||||
});
|
||||
|
||||
it('correctly calulates when there are multiple files', async () => {
|
||||
await createComponent();
|
||||
|
||||
expect(packageSize().props('text')).toBe('300 bytes');
|
||||
});
|
||||
});
|
||||
|
||||
describe('package tags', () => {
|
||||
it('displays the package-tags component when the package has tags', async () => {
|
||||
await createComponent({
|
||||
packageEntity: {
|
||||
...npmPackage,
|
||||
tags: mockTags,
|
||||
},
|
||||
});
|
||||
|
||||
expect(packageTags().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('does not display the package-tags component when there are no tags', async () => {
|
||||
await createComponent();
|
||||
|
||||
expect(packageTags().exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('package ref', () => {
|
||||
it('does not display the ref if missing', async () => {
|
||||
await createComponent();
|
||||
|
||||
expect(packageRef().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('correctly shows the package ref if there is one', async () => {
|
||||
await createComponent({ packageEntity: npmPackage });
|
||||
expect(packageRef().props()).toMatchObject({
|
||||
text: npmPackage.pipeline.ref,
|
||||
icon: 'branch',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('pipeline project', () => {
|
||||
it('does not display the project if missing', async () => {
|
||||
await createComponent();
|
||||
|
||||
expect(pipelineProject().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('correctly shows the pipeline project if there is one', async () => {
|
||||
await createComponent({ packageEntity: npmPackage });
|
||||
|
||||
expect(pipelineProject().props()).toMatchObject({
|
||||
text: npmPackage.pipeline.project.name,
|
||||
icon: 'review-list',
|
||||
link: npmPackage.pipeline.project.web_url,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
import { shallowMount, createLocalVue } from '@vue/test-utils';
|
||||
import Vuex from 'vuex';
|
||||
import { pypiPackage as packageEntity } from 'jest/packages/mock_data';
|
||||
import InstallationTitle from '~/packages/details/components/installation_title.vue';
|
||||
import PypiInstallation from '~/packages/details/components/pypi_installation.vue';
|
||||
|
||||
const localVue = createLocalVue();
|
||||
localVue.use(Vuex);
|
||||
|
||||
describe('PypiInstallation', () => {
|
||||
let wrapper;
|
||||
|
||||
const pipCommandStr = 'pip install';
|
||||
const pypiSetupStr = 'python setup';
|
||||
|
||||
const store = new Vuex.Store({
|
||||
state: {
|
||||
packageEntity,
|
||||
pypiHelpPath: 'foo',
|
||||
},
|
||||
getters: {
|
||||
pypiPipCommand: () => pipCommandStr,
|
||||
pypiSetupCommand: () => pypiSetupStr,
|
||||
},
|
||||
});
|
||||
|
||||
const pipCommand = () => wrapper.find('[data-testid="pip-command"]');
|
||||
const setupInstruction = () => wrapper.find('[data-testid="pypi-setup-content"]');
|
||||
|
||||
const findInstallationTitle = () => wrapper.findComponent(InstallationTitle);
|
||||
|
||||
function createComponent() {
|
||||
wrapper = shallowMount(PypiInstallation, {
|
||||
localVue,
|
||||
store,
|
||||
});
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
createComponent();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
});
|
||||
|
||||
describe('install command switch', () => {
|
||||
it('has the installation title component', () => {
|
||||
expect(findInstallationTitle().exists()).toBe(true);
|
||||
expect(findInstallationTitle().props()).toMatchObject({
|
||||
packageType: 'pypi',
|
||||
options: [{ value: 'pypi', label: 'Show PyPi commands' }],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('renders all the messages', () => {
|
||||
expect(wrapper.element).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe('installation commands', () => {
|
||||
it('renders the correct pip command', () => {
|
||||
expect(pipCommand().props('instruction')).toBe(pipCommandStr);
|
||||
});
|
||||
});
|
||||
|
||||
describe('setup commands', () => {
|
||||
it('renders the correct setup block', () => {
|
||||
expect(setupInstruction().props('instruction')).toBe(pypiSetupStr);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -12,22 +12,29 @@ RSpec.describe Gitlab::Regex do
|
|||
it { is_expected.to match('Dash – is this') }
|
||||
end
|
||||
|
||||
shared_examples_for 'project/group name regex' do
|
||||
shared_examples_for 'group name regex' do
|
||||
it_behaves_like 'project/group name chars regex'
|
||||
it { is_expected.not_to match('?gitlab') }
|
||||
it { is_expected.not_to match("Users's something") }
|
||||
end
|
||||
|
||||
shared_examples_for 'project name regex' do
|
||||
it_behaves_like 'project/group name chars regex'
|
||||
it { is_expected.to match("Gitlab++") }
|
||||
it { is_expected.not_to match('?gitlab') }
|
||||
it { is_expected.not_to match("Users's something") }
|
||||
end
|
||||
|
||||
describe '.project_name_regex' do
|
||||
subject { described_class.project_name_regex }
|
||||
|
||||
it_behaves_like 'project/group name regex'
|
||||
it_behaves_like 'project name regex'
|
||||
end
|
||||
|
||||
describe '.group_name_regex' do
|
||||
subject { described_class.group_name_regex }
|
||||
|
||||
it_behaves_like 'project/group name regex'
|
||||
it_behaves_like 'group name regex'
|
||||
|
||||
it 'allows parenthesis' do
|
||||
is_expected.to match('Group One (Test)')
|
||||
|
|
@ -51,7 +58,7 @@ RSpec.describe Gitlab::Regex do
|
|||
describe '.project_name_regex_message' do
|
||||
subject { described_class.project_name_regex_message }
|
||||
|
||||
it { is_expected.to eq("can contain only letters, digits, emojis, '_', '.', dash, space. It must start with letter, digit, emoji or '_'.") }
|
||||
it { is_expected.to eq("can contain only letters, digits, emojis, '_', '.', '+', dashes, or spaces. It must start with a letter, digit, emoji, or '_'.") }
|
||||
end
|
||||
|
||||
describe '.group_name_regex_message' do
|
||||
|
|
|
|||
|
|
@ -1505,6 +1505,26 @@ RSpec.describe Issue do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#supports_move_and_clone?' do
|
||||
let_it_be(:project) { create(:project) }
|
||||
let_it_be_with_refind(:issue) { create(:incident, project: project) }
|
||||
|
||||
where(:issue_type, :supports_move_and_clone) do
|
||||
:issue | true
|
||||
:incident | true
|
||||
end
|
||||
|
||||
with_them do
|
||||
before do
|
||||
issue.update!(issue_type: issue_type)
|
||||
end
|
||||
|
||||
it do
|
||||
expect(issue.supports_move_and_clone?).to eq(supports_move_and_clone)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#email_participants_emails' do
|
||||
let_it_be(:issue) { create(:issue) }
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ RSpec.describe API::Environments do
|
|||
get api("/projects/#{project.id}/environments", user)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(response).to match_response_schema('public_api/v4/environments')
|
||||
expect(response).to include_pagination_headers
|
||||
expect(json_response).to be_an Array
|
||||
expect(json_response.size).to eq(1)
|
||||
|
|
@ -167,6 +168,7 @@ RSpec.describe API::Environments do
|
|||
post api("/projects/#{project.id}/environments", user), params: { name: "mepmep" }
|
||||
|
||||
expect(response).to have_gitlab_http_status(:created)
|
||||
expect(response).to match_response_schema('public_api/v4/environment')
|
||||
expect(json_response['name']).to eq('mepmep')
|
||||
expect(json_response['slug']).to eq('mepmep')
|
||||
expect(json_response['external']).to be nil
|
||||
|
|
@ -212,6 +214,7 @@ RSpec.describe API::Environments do
|
|||
params: { name: 'Mepmep', external_url: url }
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(response).to match_response_schema('public_api/v4/environment')
|
||||
expect(json_response['name']).to eq('Mepmep')
|
||||
expect(json_response['external_url']).to eq(url)
|
||||
end
|
||||
|
|
@ -250,7 +253,7 @@ RSpec.describe API::Environments do
|
|||
expect(response).to have_gitlab_http_status(:forbidden)
|
||||
end
|
||||
|
||||
it 'returns a 200 for stopped environment' do
|
||||
it 'returns a 204 for stopped environment' do
|
||||
environment.stop
|
||||
|
||||
delete api("/projects/#{project.id}/environments/#{environment.id}", user)
|
||||
|
|
@ -294,6 +297,7 @@ RSpec.describe API::Environments do
|
|||
|
||||
it 'returns a 200' do
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(response).to match_response_schema('public_api/v4/environment')
|
||||
end
|
||||
|
||||
it 'actually stops the environment' do
|
||||
|
|
@ -327,6 +331,7 @@ RSpec.describe API::Environments do
|
|||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(response).to match_response_schema('public_api/v4/environment')
|
||||
expect(json_response['last_deployment']).to be_present
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -374,7 +374,7 @@ RSpec.describe Projects::UpdateService do
|
|||
|
||||
expect(result).to eq({
|
||||
status: :error,
|
||||
message: "Name can contain only letters, digits, emojis, '_', '.', dash, space. It must start with letter, digit, emoji or '_'."
|
||||
message: "Name can contain only letters, digits, emojis, '_', '.', '+', dashes, or spaces. It must start with a letter, digit, emoji, or '_'."
|
||||
})
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -17,9 +17,11 @@ RSpec.shared_examples 'group and project packages query' do
|
|||
let(:package_names) { graphql_data_at(resource_type, :packages, :nodes, :name) }
|
||||
let(:target_shas) { graphql_data_at(resource_type, :packages, :nodes, :metadata, :target_sha) }
|
||||
let(:packages) { graphql_data_at(resource_type, :packages, :nodes) }
|
||||
let(:packages_count) { graphql_data_at(resource_type, :packages, :count) }
|
||||
|
||||
let(:fields) do
|
||||
<<~QUERY
|
||||
count
|
||||
nodes {
|
||||
#{all_graphql_fields_for('packages'.classify, excluded: ['project'])}
|
||||
metadata { #{query_graphql_fragment('ComposerMetadata')} }
|
||||
|
|
@ -55,6 +57,10 @@ RSpec.shared_examples 'group and project packages query' do
|
|||
it 'deals with metadata' do
|
||||
expect(target_shas).to contain_exactly(composer_metadatum.target_sha)
|
||||
end
|
||||
|
||||
it 'returns the count of the packages' do
|
||||
expect(packages_count).to eq(4)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the user does not have access to the resource' do
|
||||
|
|
|
|||
Loading…
Reference in New Issue