Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
4d68d8b937
commit
4f54ec92ed
|
@ -1 +1 @@
|
||||||
574ce1641f5de518338c2d4c7fbe17681d741363
|
3ec72513ce59862f022cf5375f1d4739653f8cee
|
||||||
|
|
|
@ -6,7 +6,8 @@
|
||||||
|
|
||||||
import { GlModal } from '@gitlab/ui';
|
import { GlModal } from '@gitlab/ui';
|
||||||
import { escape } from 'lodash';
|
import { escape } from 'lodash';
|
||||||
import { s__, sprintf } from '~/locale';
|
import csrf from '~/lib/utils/csrf';
|
||||||
|
import { __, s__, sprintf } from '~/locale';
|
||||||
|
|
||||||
import eventHub from '../event_hub';
|
import eventHub from '../event_hub';
|
||||||
|
|
||||||
|
@ -35,6 +36,11 @@ export default {
|
||||||
required: false,
|
required: false,
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
|
retryUrl: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -66,6 +72,12 @@ export default {
|
||||||
return this.environment.commitUrl;
|
return this.environment.commitUrl;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
modalActionText() {
|
||||||
|
return this.environment.isLastDeployment
|
||||||
|
? s__('Environments|Re-deploy')
|
||||||
|
: s__('Environments|Rollback');
|
||||||
|
},
|
||||||
|
|
||||||
modalText() {
|
modalText() {
|
||||||
const linkStart = `<a class="commit-sha mr-0" href="${escape(this.commitUrl)}">`;
|
const linkStart = `<a class="commit-sha mr-0" href="${escape(this.commitUrl)}">`;
|
||||||
const commitId = escape(this.commitShortSha);
|
const commitId = escape(this.commitShortSha);
|
||||||
|
@ -90,10 +102,17 @@ export default {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
modalActionText() {
|
primaryProps() {
|
||||||
return this.environment.isLastDeployment
|
let attributes = [{ variant: 'danger' }];
|
||||||
? s__('Environments|Re-deploy')
|
|
||||||
: s__('Environments|Rollback');
|
if (this.retryUrl) {
|
||||||
|
attributes = [...attributes, { 'data-method': 'post' }, { href: this.retryUrl }];
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
text: this.modalActionText,
|
||||||
|
attributes,
|
||||||
|
};
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -114,15 +133,20 @@ export default {
|
||||||
return '';
|
return '';
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
csrf,
|
||||||
|
cancelProps: {
|
||||||
|
text: __('Cancel'),
|
||||||
|
attributes: [{ variant: 'danger' }],
|
||||||
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<gl-modal
|
<gl-modal
|
||||||
:title="modalTitle"
|
:title="modalTitle"
|
||||||
:visible="visible"
|
:visible="visible"
|
||||||
|
:action-cancel="$options.cancelProps"
|
||||||
|
:action-primary="primaryProps"
|
||||||
modal-id="confirm-rollback-modal"
|
modal-id="confirm-rollback-modal"
|
||||||
:ok-title="modalActionText"
|
|
||||||
ok-variant="danger"
|
|
||||||
@ok="onOk"
|
@ok="onOk"
|
||||||
@change="handleChange"
|
@change="handleChange"
|
||||||
>
|
>
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
import { parseBoolean } from '~/lib/utils/common_utils';
|
import { parseBoolean } from '~/lib/utils/common_utils';
|
||||||
import { redirectTo } from '~/lib/utils/url_utility';
|
|
||||||
import eventHub from '../event_hub';
|
|
||||||
import ConfirmRollbackModal from './confirm_rollback_modal.vue';
|
import ConfirmRollbackModal from './confirm_rollback_modal.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -22,10 +20,6 @@ export default {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
eventHub.$on('rollbackEnvironment', () => {
|
|
||||||
redirectTo(this.retryPath);
|
|
||||||
});
|
|
||||||
|
|
||||||
document.querySelectorAll(this.selector).forEach((button) => {
|
document.querySelectorAll(this.selector).forEach((button) => {
|
||||||
button.addEventListener('click', (e) => {
|
button.addEventListener('click', (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
@ -57,6 +51,7 @@ export default {
|
||||||
v-model="visible"
|
v-model="visible"
|
||||||
:environment="environment"
|
:environment="environment"
|
||||||
:has-multiple-commits="false"
|
:has-multiple-commits="false"
|
||||||
|
:retry-url="retryPath"
|
||||||
/>
|
/>
|
||||||
<div v-else></div>
|
<div v-else></div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -20,7 +20,6 @@ import { numberToHumanSize } from '~/lib/utils/number_utils';
|
||||||
import { objectToQuery } from '~/lib/utils/url_utility';
|
import { objectToQuery } from '~/lib/utils/url_utility';
|
||||||
import { s__, __ } from '~/locale';
|
import { s__, __ } from '~/locale';
|
||||||
// import DependencyRow from '~/packages/details/components/dependency_row.vue';
|
// import DependencyRow from '~/packages/details/components/dependency_row.vue';
|
||||||
// import PackageListRow from '~/packages/shared/components/package_list_row.vue';
|
|
||||||
import PackagesListLoader from '~/packages/shared/components/packages_list_loader.vue';
|
import PackagesListLoader from '~/packages/shared/components/packages_list_loader.vue';
|
||||||
import { packageTypeToTrackCategory } from '~/packages/shared/utils';
|
import { packageTypeToTrackCategory } from '~/packages/shared/utils';
|
||||||
import AdditionalMetadata from '~/packages_and_registries/package_registry/components/details/additional_metadata.vue';
|
import AdditionalMetadata from '~/packages_and_registries/package_registry/components/details/additional_metadata.vue';
|
||||||
|
@ -28,6 +27,7 @@ import InstallationCommands from '~/packages_and_registries/package_registry/com
|
||||||
import PackageFiles from '~/packages_and_registries/package_registry/components/details/package_files.vue';
|
import PackageFiles from '~/packages_and_registries/package_registry/components/details/package_files.vue';
|
||||||
import PackageHistory from '~/packages_and_registries/package_registry/components/details/package_history.vue';
|
import PackageHistory from '~/packages_and_registries/package_registry/components/details/package_history.vue';
|
||||||
import PackageTitle from '~/packages_and_registries/package_registry/components/details/package_title.vue';
|
import PackageTitle from '~/packages_and_registries/package_registry/components/details/package_title.vue';
|
||||||
|
import VersionRow from '~/packages_and_registries/package_registry/components/details/version_row.vue';
|
||||||
import {
|
import {
|
||||||
PACKAGE_TYPE_NUGET,
|
PACKAGE_TYPE_NUGET,
|
||||||
PACKAGE_TYPE_COMPOSER,
|
PACKAGE_TYPE_COMPOSER,
|
||||||
|
@ -62,7 +62,7 @@ export default {
|
||||||
GlSprintf,
|
GlSprintf,
|
||||||
PackageTitle,
|
PackageTitle,
|
||||||
PackagesListLoader,
|
PackagesListLoader,
|
||||||
// PackageListRow,
|
VersionRow,
|
||||||
// DependencyRow,
|
// DependencyRow,
|
||||||
PackageHistory,
|
PackageHistory,
|
||||||
AdditionalMetadata,
|
AdditionalMetadata,
|
||||||
|
@ -138,7 +138,7 @@ export default {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
hasVersions() {
|
hasVersions() {
|
||||||
return this.packageEntity.versions?.length > 0;
|
return this.packageEntity.versions?.nodes?.length > 0;
|
||||||
},
|
},
|
||||||
packageDependencies() {
|
packageDependencies() {
|
||||||
return this.packageEntity.dependency_links || [];
|
return this.packageEntity.dependency_links || [];
|
||||||
|
@ -154,11 +154,6 @@ export default {
|
||||||
formatSize(size) {
|
formatSize(size) {
|
||||||
return numberToHumanSize(size);
|
return numberToHumanSize(size);
|
||||||
},
|
},
|
||||||
getPackageVersions() {
|
|
||||||
if (!this.packageEntity.versions) {
|
|
||||||
// this.fetchPackageVersions();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async deletePackage() {
|
async deletePackage() {
|
||||||
const { data } = await this.$apollo.mutate({
|
const { data } = await this.$apollo.mutate({
|
||||||
mutation: destroyPackageMutation,
|
mutation: destroyPackageMutation,
|
||||||
|
@ -329,24 +324,13 @@ export default {
|
||||||
</p>
|
</p>
|
||||||
</gl-tab>
|
</gl-tab>
|
||||||
|
|
||||||
<gl-tab
|
<gl-tab :title="__('Other versions')" title-item-class="js-versions-tab">
|
||||||
:title="__('Other versions')"
|
|
||||||
title-item-class="js-versions-tab"
|
|
||||||
@click="getPackageVersions"
|
|
||||||
>
|
|
||||||
<template v-if="isLoading && !hasVersions">
|
<template v-if="isLoading && !hasVersions">
|
||||||
<packages-list-loader />
|
<packages-list-loader />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-else-if="hasVersions">
|
<template v-else-if="hasVersions">
|
||||||
<!-- <package-list-row
|
<version-row v-for="v in packageEntity.versions.nodes" :key="v.id" :package-entity="v" />
|
||||||
v-for="v in packageEntity.versions"
|
|
||||||
:key="v.id"
|
|
||||||
:package-entity="{ name: packageEntity.name, ...v }"
|
|
||||||
:package-link="v.id.toString()"
|
|
||||||
:disable-delete="true"
|
|
||||||
:show-package-type="false"
|
|
||||||
/> -->
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<p v-else class="gl-mt-3" data-testid="no-versions-message">
|
<p v-else class="gl-mt-3" data-testid="no-versions-message">
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
<script>
|
||||||
|
import { GlLink, GlSprintf, GlTruncate } from '@gitlab/ui';
|
||||||
|
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
|
||||||
|
import PackageTags from '~/packages/shared/components/package_tags.vue';
|
||||||
|
import PublishMethod from '~/packages/shared/components/publish_method.vue';
|
||||||
|
import ListItem from '~/vue_shared/components/registry/list_item.vue';
|
||||||
|
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
|
||||||
|
import { PACKAGE_DEFAULT_STATUS } from '../../constants';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'PackageListRow',
|
||||||
|
components: {
|
||||||
|
GlLink,
|
||||||
|
GlSprintf,
|
||||||
|
GlTruncate,
|
||||||
|
PackageTags,
|
||||||
|
PublishMethod,
|
||||||
|
ListItem,
|
||||||
|
TimeAgoTooltip,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
packageEntity: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
packageLink() {
|
||||||
|
return `${getIdFromGraphQLId(this.packageEntity.id)}`;
|
||||||
|
},
|
||||||
|
disabledRow() {
|
||||||
|
return this.packageEntity.status && this.packageEntity.status !== PACKAGE_DEFAULT_STATUS;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<list-item :disabled="disabledRow">
|
||||||
|
<template #left-primary>
|
||||||
|
<div class="gl-display-flex gl-align-items-center gl-mr-3 gl-min-w-0">
|
||||||
|
<gl-link :href="packageLink" class="gl-text-body gl-min-w-0" :disabled="disabledRow">
|
||||||
|
<gl-truncate :text="packageEntity.name" />
|
||||||
|
</gl-link>
|
||||||
|
|
||||||
|
<package-tags
|
||||||
|
v-if="packageEntity.tags.nodes && packageEntity.tags.nodes.length"
|
||||||
|
class="gl-ml-3"
|
||||||
|
:tags="packageEntity.tags.nodes"
|
||||||
|
hide-label
|
||||||
|
:tag-display-limit="1"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #left-secondary>
|
||||||
|
{{ packageEntity.version }}
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #right-primary>
|
||||||
|
<publish-method :package-entity="packageEntity" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #right-secondary>
|
||||||
|
<gl-sprintf :message="__('Created %{timestamp}')">
|
||||||
|
<template #timestamp>
|
||||||
|
<time-ago-tooltip :time="packageEntity.createdAt" />
|
||||||
|
</template>
|
||||||
|
</gl-sprintf>
|
||||||
|
</template>
|
||||||
|
</list-item>
|
||||||
|
</template>
|
|
@ -79,10 +79,10 @@ export const FETCH_PACKAGE_DETAILS_ERROR_MESSAGE = s__(
|
||||||
'PackageRegistry|Failed to load the package data',
|
'PackageRegistry|Failed to load the package data',
|
||||||
);
|
);
|
||||||
|
|
||||||
export const PACKAGE_ERROR_STATUS = 'error';
|
export const PACKAGE_ERROR_STATUS = 'ERROR';
|
||||||
export const PACKAGE_DEFAULT_STATUS = 'default';
|
export const PACKAGE_DEFAULT_STATUS = 'DEFAULT';
|
||||||
export const PACKAGE_HIDDEN_STATUS = 'hidden';
|
export const PACKAGE_HIDDEN_STATUS = 'HIDDEN';
|
||||||
export const PACKAGE_PROCESSING_STATUS = 'processing';
|
export const PACKAGE_PROCESSING_STATUS = 'PROCESSING';
|
||||||
|
|
||||||
export const NPM_PACKAGE_MANAGER = 'npm';
|
export const NPM_PACKAGE_MANAGER = 'npm';
|
||||||
export const YARN_PACKAGE_MANAGER = 'yarn';
|
export const YARN_PACKAGE_MANAGER = 'yarn';
|
||||||
|
|
|
@ -7,7 +7,10 @@ query getPackageDetails($id: ID!) {
|
||||||
createdAt
|
createdAt
|
||||||
updatedAt
|
updatedAt
|
||||||
status
|
status
|
||||||
tags {
|
project {
|
||||||
|
path
|
||||||
|
}
|
||||||
|
tags(first: 10) {
|
||||||
nodes {
|
nodes {
|
||||||
id
|
id
|
||||||
name
|
name
|
||||||
|
@ -42,6 +45,21 @@ query getPackageDetails($id: ID!) {
|
||||||
downloadPath
|
downloadPath
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
versions(first: 100) {
|
||||||
|
nodes {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
createdAt
|
||||||
|
version
|
||||||
|
status
|
||||||
|
tags(first: 1) {
|
||||||
|
nodes {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
metadata {
|
metadata {
|
||||||
... on ComposerMetadata {
|
... on ComposerMetadata {
|
||||||
targetSha
|
targetSha
|
||||||
|
|
|
@ -14,7 +14,7 @@ export const initSecurityConfiguration = (el) => {
|
||||||
Vue.use(VueApollo);
|
Vue.use(VueApollo);
|
||||||
|
|
||||||
const apolloProvider = new VueApollo({
|
const apolloProvider = new VueApollo({
|
||||||
defaultClient: createDefaultClient(),
|
defaultClient: createDefaultClient({}, { assumeImmutableResults: true }),
|
||||||
});
|
});
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
|
|
@ -153,16 +153,16 @@
|
||||||
// pseudo-element that is the same size as our element, then
|
// pseudo-element that is the same size as our element, then
|
||||||
// animate opacity/transform to give a soothing single pulse
|
// animate opacity/transform to give a soothing single pulse
|
||||||
.board-column-highlighted::after {
|
.board-column-highlighted::after {
|
||||||
|
@include gl-focus;
|
||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: -1px;
|
||||||
bottom: 0;
|
bottom: -1px;
|
||||||
left: 0;
|
left: -1px;
|
||||||
right: 0;
|
right: -1px;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
z-index: -1;
|
border-radius: $border-radius-default;
|
||||||
box-shadow: 0 0 6px 3px $blue-200;
|
|
||||||
animation-name: board-column-flash-border;
|
animation-name: board-column-flash-border;
|
||||||
animation-duration: 1.2s;
|
animation-duration: 1.2s;
|
||||||
animation-fill-mode: forwards;
|
animation-fill-mode: forwards;
|
||||||
|
@ -173,18 +173,11 @@
|
||||||
0%,
|
0%,
|
||||||
100% {
|
100% {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: scale(0.98);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
25%,
|
25%,
|
||||||
75% {
|
75% {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
transform: scale(0.99);
|
|
||||||
}
|
|
||||||
|
|
||||||
50% {
|
|
||||||
opacity: 1;
|
|
||||||
transform: scale(1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Types
|
||||||
|
module Packages
|
||||||
|
class DependencyLinkMetadataType < BaseUnion
|
||||||
|
graphql_name 'DependencyLinkMetadata'
|
||||||
|
description 'Represents metadata associated with a dependency link'
|
||||||
|
|
||||||
|
possible_types ::Types::Packages::Nuget::DependencyLinkMetadatumType
|
||||||
|
|
||||||
|
def self.resolve_type(object, context)
|
||||||
|
case object
|
||||||
|
when ::Packages::Nuget::DependencyLinkMetadatum
|
||||||
|
::Types::Packages::Nuget::DependencyLinkMetadatumType
|
||||||
|
else
|
||||||
|
# NOTE: This method must be kept in sync with `PackageDependencyLinkType#metadata`,
|
||||||
|
# which must never produce data that this discriminator cannot handle.
|
||||||
|
raise 'Unsupported metadata type'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,17 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Types
|
||||||
|
module Packages
|
||||||
|
module Nuget
|
||||||
|
class DependencyLinkMetadatumType < BaseObject
|
||||||
|
graphql_name 'NugetDependencyLinkMetadata'
|
||||||
|
description 'Nuget dependency link metadata'
|
||||||
|
|
||||||
|
authorize :read_package
|
||||||
|
|
||||||
|
field :id, ::Types::GlobalIDType[::Packages::Nuget::DependencyLinkMetadatum], null: false, description: 'ID of the metadatum.'
|
||||||
|
field :target_framework, GraphQL::Types::String, null: false, description: 'Target framework of the depdency link package.'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,40 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Types
|
||||||
|
module Packages
|
||||||
|
class PackageDependencyLinkType < BaseObject
|
||||||
|
graphql_name 'PackageDependencyLink'
|
||||||
|
description 'Represents a package dependency link'
|
||||||
|
authorize :read_package
|
||||||
|
|
||||||
|
field :id, ::Types::GlobalIDType[::Packages::DependencyLink], null: false, description: 'ID of the dependency link.'
|
||||||
|
field :dependency_type, Types::Packages::PackageDependencyTypeEnum, null: false, description: 'Dependency type.'
|
||||||
|
field :dependency, Types::Packages::PackageDependencyType, null: true, description: 'Dependency.'
|
||||||
|
field :metadata, Types::Packages::DependencyLinkMetadataType, null: true, description: 'Dependency link metadata.'
|
||||||
|
|
||||||
|
# NOTE: This method must be kept in sync with the union
|
||||||
|
# type: `Types::Packages::DependencyLinkMetadata`.
|
||||||
|
#
|
||||||
|
# `Types::Packages::DependencyLinkMetadata.resolve_type(metadata, ctx)` must never raise.
|
||||||
|
def metadata
|
||||||
|
model_class = case object.package.package_type
|
||||||
|
when 'nuget'
|
||||||
|
::Packages::Nuget::DependencyLinkMetadatum
|
||||||
|
end
|
||||||
|
|
||||||
|
return unless model_class
|
||||||
|
|
||||||
|
# rubocop: disable CodeReuse/ActiveRecord
|
||||||
|
BatchLoader::GraphQL.for(object.id).batch do |ids, loader|
|
||||||
|
results = model_class.where(dependency_link_id: ids)
|
||||||
|
results.each { |record| loader.call(record.dependency_link_id, record) }
|
||||||
|
end
|
||||||
|
# rubocop: enable CodeReuse/ActiveRecord
|
||||||
|
end
|
||||||
|
|
||||||
|
def dependency
|
||||||
|
::Gitlab::Graphql::Loaders::BatchModelLoader.new(::Packages::Dependency, object.dependency_id).find
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,16 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
# this model does not have any kind of authorization so we disable it
|
||||||
|
# rubocop:disable Graphql/AuthorizeTypes
|
||||||
|
|
||||||
|
module Types
|
||||||
|
module Packages
|
||||||
|
class PackageDependencyType < BaseObject
|
||||||
|
graphql_name 'PackageDependency'
|
||||||
|
description 'Represents a package dependency.'
|
||||||
|
|
||||||
|
field :id, ::Types::GlobalIDType[::Packages::Dependency], null: false, description: 'ID of the dependency.'
|
||||||
|
field :name, GraphQL::Types::String, null: false, description: 'Name of the dependency.'
|
||||||
|
field :version_pattern, GraphQL::Types::String, null: false, description: 'Version pattern of the dependency.'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,13 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Types
|
||||||
|
module Packages
|
||||||
|
class PackageDependencyTypeEnum < BaseEnum
|
||||||
|
graphql_name 'PackageDependencyType'
|
||||||
|
|
||||||
|
::Packages::DependencyLink.dependency_types.keys.each do |type|
|
||||||
|
value type.to_s.underscore.upcase, description: "#{type} dependency type", value: type.to_s
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -12,6 +12,8 @@ module Types
|
||||||
|
|
||||||
field :package_files, Types::Packages::PackageFileType.connection_type, null: true, description: 'Package files.'
|
field :package_files, Types::Packages::PackageFileType.connection_type, null: true, description: 'Package files.'
|
||||||
|
|
||||||
|
field :dependency_links, Types::Packages::PackageDependencyLinkType.connection_type, null: true, description: 'Dependency link.'
|
||||||
|
|
||||||
def versions
|
def versions
|
||||||
object.versions
|
object.versions
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
module Packages
|
||||||
|
class DependencyLinkPolicy < BasePolicy
|
||||||
|
delegate { @subject.package }
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,8 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
module Packages
|
||||||
|
module Nuget
|
||||||
|
class DependencyLinkMetadatumPolicy < BasePolicy
|
||||||
|
delegate { @subject.dependency_link.package }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/328253
|
||||||
milestone: '14.1'
|
milestone: '14.1'
|
||||||
type: development
|
type: development
|
||||||
group: group::pipeline authoring
|
group: group::pipeline authoring
|
||||||
default_enabled: false
|
default_enabled: true
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class RenameTablesCiBuildTraceSection < ActiveRecord::Migration[6.1]
|
||||||
|
DOWNTIME = false
|
||||||
|
|
||||||
|
def change
|
||||||
|
# Shorten deprecated to dep to avoid 'Index name..too long'
|
||||||
|
rename_table(:ci_build_trace_sections, :dep_ci_build_trace_sections)
|
||||||
|
rename_table(:ci_build_trace_section_names, :dep_ci_build_trace_section_names)
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1 @@
|
||||||
|
35475ad862d713055a90af508dba393834ce8aa60eb1abf46b8f9698c2d42276
|
|
@ -10574,32 +10574,6 @@ CREATE SEQUENCE ci_build_trace_chunks_id_seq
|
||||||
|
|
||||||
ALTER SEQUENCE ci_build_trace_chunks_id_seq OWNED BY ci_build_trace_chunks.id;
|
ALTER SEQUENCE ci_build_trace_chunks_id_seq OWNED BY ci_build_trace_chunks.id;
|
||||||
|
|
||||||
CREATE TABLE ci_build_trace_section_names (
|
|
||||||
id integer NOT NULL,
|
|
||||||
project_id integer NOT NULL,
|
|
||||||
name character varying NOT NULL
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE SEQUENCE ci_build_trace_section_names_id_seq
|
|
||||||
START WITH 1
|
|
||||||
INCREMENT BY 1
|
|
||||||
NO MINVALUE
|
|
||||||
NO MAXVALUE
|
|
||||||
CACHE 1;
|
|
||||||
|
|
||||||
ALTER SEQUENCE ci_build_trace_section_names_id_seq OWNED BY ci_build_trace_section_names.id;
|
|
||||||
|
|
||||||
CREATE TABLE ci_build_trace_sections (
|
|
||||||
project_id integer NOT NULL,
|
|
||||||
date_start timestamp without time zone NOT NULL,
|
|
||||||
date_end timestamp without time zone NOT NULL,
|
|
||||||
byte_start bigint NOT NULL,
|
|
||||||
byte_end bigint NOT NULL,
|
|
||||||
build_id integer NOT NULL,
|
|
||||||
section_name_id integer NOT NULL,
|
|
||||||
build_id_convert_to_bigint bigint DEFAULT 0 NOT NULL
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE ci_builds (
|
CREATE TABLE ci_builds (
|
||||||
id integer NOT NULL,
|
id integer NOT NULL,
|
||||||
status character varying,
|
status character varying,
|
||||||
|
@ -12303,6 +12277,33 @@ CREATE SEQUENCE dast_sites_id_seq
|
||||||
|
|
||||||
ALTER SEQUENCE dast_sites_id_seq OWNED BY dast_sites.id;
|
ALTER SEQUENCE dast_sites_id_seq OWNED BY dast_sites.id;
|
||||||
|
|
||||||
|
CREATE TABLE dep_ci_build_trace_section_names (
|
||||||
|
id integer NOT NULL,
|
||||||
|
project_id integer NOT NULL,
|
||||||
|
name character varying NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE SEQUENCE dep_ci_build_trace_section_names_id_seq
|
||||||
|
AS integer
|
||||||
|
START WITH 1
|
||||||
|
INCREMENT BY 1
|
||||||
|
NO MINVALUE
|
||||||
|
NO MAXVALUE
|
||||||
|
CACHE 1;
|
||||||
|
|
||||||
|
ALTER SEQUENCE dep_ci_build_trace_section_names_id_seq OWNED BY dep_ci_build_trace_section_names.id;
|
||||||
|
|
||||||
|
CREATE TABLE dep_ci_build_trace_sections (
|
||||||
|
project_id integer NOT NULL,
|
||||||
|
date_start timestamp without time zone NOT NULL,
|
||||||
|
date_end timestamp without time zone NOT NULL,
|
||||||
|
byte_start bigint NOT NULL,
|
||||||
|
byte_end bigint NOT NULL,
|
||||||
|
build_id integer NOT NULL,
|
||||||
|
section_name_id integer NOT NULL,
|
||||||
|
build_id_convert_to_bigint bigint DEFAULT 0 NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
CREATE TABLE dependency_proxy_blobs (
|
CREATE TABLE dependency_proxy_blobs (
|
||||||
id integer NOT NULL,
|
id integer NOT NULL,
|
||||||
group_id integer NOT NULL,
|
group_id integer NOT NULL,
|
||||||
|
@ -20087,8 +20088,6 @@ ALTER TABLE ONLY ci_build_report_results ALTER COLUMN build_id SET DEFAULT nextv
|
||||||
|
|
||||||
ALTER TABLE ONLY ci_build_trace_chunks ALTER COLUMN id SET DEFAULT nextval('ci_build_trace_chunks_id_seq'::regclass);
|
ALTER TABLE ONLY ci_build_trace_chunks ALTER COLUMN id SET DEFAULT nextval('ci_build_trace_chunks_id_seq'::regclass);
|
||||||
|
|
||||||
ALTER TABLE ONLY ci_build_trace_section_names ALTER COLUMN id SET DEFAULT nextval('ci_build_trace_section_names_id_seq'::regclass);
|
|
||||||
|
|
||||||
ALTER TABLE ONLY ci_builds ALTER COLUMN id SET DEFAULT nextval('ci_builds_id_seq'::regclass);
|
ALTER TABLE ONLY ci_builds ALTER COLUMN id SET DEFAULT nextval('ci_builds_id_seq'::regclass);
|
||||||
|
|
||||||
ALTER TABLE ONLY ci_builds_metadata ALTER COLUMN id SET DEFAULT nextval('ci_builds_metadata_id_seq'::regclass);
|
ALTER TABLE ONLY ci_builds_metadata ALTER COLUMN id SET DEFAULT nextval('ci_builds_metadata_id_seq'::regclass);
|
||||||
|
@ -20237,6 +20236,8 @@ ALTER TABLE ONLY dast_site_validations ALTER COLUMN id SET DEFAULT nextval('dast
|
||||||
|
|
||||||
ALTER TABLE ONLY dast_sites ALTER COLUMN id SET DEFAULT nextval('dast_sites_id_seq'::regclass);
|
ALTER TABLE ONLY dast_sites ALTER COLUMN id SET DEFAULT nextval('dast_sites_id_seq'::regclass);
|
||||||
|
|
||||||
|
ALTER TABLE ONLY dep_ci_build_trace_section_names ALTER COLUMN id SET DEFAULT nextval('dep_ci_build_trace_section_names_id_seq'::regclass);
|
||||||
|
|
||||||
ALTER TABLE ONLY dependency_proxy_blobs ALTER COLUMN id SET DEFAULT nextval('dependency_proxy_blobs_id_seq'::regclass);
|
ALTER TABLE ONLY dependency_proxy_blobs ALTER COLUMN id SET DEFAULT nextval('dependency_proxy_blobs_id_seq'::regclass);
|
||||||
|
|
||||||
ALTER TABLE ONLY dependency_proxy_group_settings ALTER COLUMN id SET DEFAULT nextval('dependency_proxy_group_settings_id_seq'::regclass);
|
ALTER TABLE ONLY dependency_proxy_group_settings ALTER COLUMN id SET DEFAULT nextval('dependency_proxy_group_settings_id_seq'::regclass);
|
||||||
|
@ -21292,10 +21293,7 @@ ALTER TABLE ONLY ci_build_report_results
|
||||||
ALTER TABLE ONLY ci_build_trace_chunks
|
ALTER TABLE ONLY ci_build_trace_chunks
|
||||||
ADD CONSTRAINT ci_build_trace_chunks_pkey PRIMARY KEY (id);
|
ADD CONSTRAINT ci_build_trace_chunks_pkey PRIMARY KEY (id);
|
||||||
|
|
||||||
ALTER TABLE ONLY ci_build_trace_section_names
|
ALTER TABLE ONLY dep_ci_build_trace_sections
|
||||||
ADD CONSTRAINT ci_build_trace_section_names_pkey PRIMARY KEY (id);
|
|
||||||
|
|
||||||
ALTER TABLE ONLY ci_build_trace_sections
|
|
||||||
ADD CONSTRAINT ci_build_trace_sections_pkey PRIMARY KEY (build_id, section_name_id);
|
ADD CONSTRAINT ci_build_trace_sections_pkey PRIMARY KEY (build_id, section_name_id);
|
||||||
|
|
||||||
ALTER TABLE ONLY ci_builds_metadata
|
ALTER TABLE ONLY ci_builds_metadata
|
||||||
|
@ -21541,6 +21539,9 @@ ALTER TABLE ONLY dast_site_validations
|
||||||
ALTER TABLE ONLY dast_sites
|
ALTER TABLE ONLY dast_sites
|
||||||
ADD CONSTRAINT dast_sites_pkey PRIMARY KEY (id);
|
ADD CONSTRAINT dast_sites_pkey PRIMARY KEY (id);
|
||||||
|
|
||||||
|
ALTER TABLE ONLY dep_ci_build_trace_section_names
|
||||||
|
ADD CONSTRAINT dep_ci_build_trace_section_names_pkey PRIMARY KEY (id);
|
||||||
|
|
||||||
ALTER TABLE ONLY dependency_proxy_blobs
|
ALTER TABLE ONLY dependency_proxy_blobs
|
||||||
ADD CONSTRAINT dependency_proxy_blobs_pkey PRIMARY KEY (id);
|
ADD CONSTRAINT dependency_proxy_blobs_pkey PRIMARY KEY (id);
|
||||||
|
|
||||||
|
@ -23241,12 +23242,6 @@ CREATE INDEX index_ci_build_report_results_on_project_id ON ci_build_report_resu
|
||||||
|
|
||||||
CREATE UNIQUE INDEX index_ci_build_trace_chunks_on_build_id_and_chunk_index ON ci_build_trace_chunks USING btree (build_id, chunk_index);
|
CREATE UNIQUE INDEX index_ci_build_trace_chunks_on_build_id_and_chunk_index ON ci_build_trace_chunks USING btree (build_id, chunk_index);
|
||||||
|
|
||||||
CREATE UNIQUE INDEX index_ci_build_trace_section_names_on_project_id_and_name ON ci_build_trace_section_names USING btree (project_id, name);
|
|
||||||
|
|
||||||
CREATE INDEX index_ci_build_trace_sections_on_project_id ON ci_build_trace_sections USING btree (project_id);
|
|
||||||
|
|
||||||
CREATE INDEX index_ci_build_trace_sections_on_section_name_id ON ci_build_trace_sections USING btree (section_name_id);
|
|
||||||
|
|
||||||
CREATE UNIQUE INDEX index_ci_builds_metadata_on_build_id ON ci_builds_metadata USING btree (build_id);
|
CREATE UNIQUE INDEX index_ci_builds_metadata_on_build_id ON ci_builds_metadata USING btree (build_id);
|
||||||
|
|
||||||
CREATE INDEX index_ci_builds_metadata_on_build_id_and_has_exposed_artifacts ON ci_builds_metadata USING btree (build_id) WHERE (has_exposed_artifacts IS TRUE);
|
CREATE INDEX index_ci_builds_metadata_on_build_id_and_has_exposed_artifacts ON ci_builds_metadata USING btree (build_id) WHERE (has_exposed_artifacts IS TRUE);
|
||||||
|
@ -23647,6 +23642,12 @@ CREATE INDEX index_dast_sites_on_dast_site_validation_id ON dast_sites USING btr
|
||||||
|
|
||||||
CREATE UNIQUE INDEX index_dast_sites_on_project_id_and_url ON dast_sites USING btree (project_id, url);
|
CREATE UNIQUE INDEX index_dast_sites_on_project_id_and_url ON dast_sites USING btree (project_id, url);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX index_dep_ci_build_trace_section_names_on_project_id_and_name ON dep_ci_build_trace_section_names USING btree (project_id, name);
|
||||||
|
|
||||||
|
CREATE INDEX index_dep_ci_build_trace_sections_on_project_id ON dep_ci_build_trace_sections USING btree (project_id);
|
||||||
|
|
||||||
|
CREATE INDEX index_dep_ci_build_trace_sections_on_section_name_id ON dep_ci_build_trace_sections USING btree (section_name_id);
|
||||||
|
|
||||||
CREATE INDEX index_dependency_proxy_blobs_on_group_id_and_file_name ON dependency_proxy_blobs USING btree (group_id, file_name);
|
CREATE INDEX index_dependency_proxy_blobs_on_group_id_and_file_name ON dependency_proxy_blobs USING btree (group_id, file_name);
|
||||||
|
|
||||||
CREATE INDEX index_dependency_proxy_group_settings_on_group_id ON dependency_proxy_group_settings USING btree (group_id);
|
CREATE INDEX index_dependency_proxy_group_settings_on_group_id ON dependency_proxy_group_settings USING btree (group_id);
|
||||||
|
@ -25989,7 +25990,7 @@ CREATE TRIGGER trigger_8485e97c00e3 BEFORE INSERT OR UPDATE ON ci_sources_pipeli
|
||||||
|
|
||||||
CREATE TRIGGER trigger_8487d4de3e7b BEFORE INSERT OR UPDATE ON ci_builds_metadata FOR EACH ROW EXECUTE FUNCTION trigger_8487d4de3e7b();
|
CREATE TRIGGER trigger_8487d4de3e7b BEFORE INSERT OR UPDATE ON ci_builds_metadata FOR EACH ROW EXECUTE FUNCTION trigger_8487d4de3e7b();
|
||||||
|
|
||||||
CREATE TRIGGER trigger_91dc388a5fe6 BEFORE INSERT OR UPDATE ON ci_build_trace_sections FOR EACH ROW EXECUTE FUNCTION trigger_91dc388a5fe6();
|
CREATE TRIGGER trigger_91dc388a5fe6 BEFORE INSERT OR UPDATE ON dep_ci_build_trace_sections FOR EACH ROW EXECUTE FUNCTION trigger_91dc388a5fe6();
|
||||||
|
|
||||||
CREATE TRIGGER trigger_aebe8b822ad3 BEFORE INSERT OR UPDATE ON taggings FOR EACH ROW EXECUTE FUNCTION trigger_aebe8b822ad3();
|
CREATE TRIGGER trigger_aebe8b822ad3 BEFORE INSERT OR UPDATE ON taggings FOR EACH ROW EXECUTE FUNCTION trigger_aebe8b822ad3();
|
||||||
|
|
||||||
|
@ -26133,8 +26134,8 @@ ALTER TABLE ONLY projects
|
||||||
ALTER TABLE ONLY ci_pipelines
|
ALTER TABLE ONLY ci_pipelines
|
||||||
ADD CONSTRAINT fk_262d4c2d19 FOREIGN KEY (auto_canceled_by_id) REFERENCES ci_pipelines(id) ON DELETE SET NULL;
|
ADD CONSTRAINT fk_262d4c2d19 FOREIGN KEY (auto_canceled_by_id) REFERENCES ci_pipelines(id) ON DELETE SET NULL;
|
||||||
|
|
||||||
ALTER TABLE ONLY ci_build_trace_sections
|
ALTER TABLE ONLY dep_ci_build_trace_sections
|
||||||
ADD CONSTRAINT fk_264e112c66 FOREIGN KEY (section_name_id) REFERENCES ci_build_trace_section_names(id) ON DELETE CASCADE;
|
ADD CONSTRAINT fk_264e112c66 FOREIGN KEY (section_name_id) REFERENCES dep_ci_build_trace_section_names(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
ALTER TABLE ONLY geo_event_log
|
ALTER TABLE ONLY geo_event_log
|
||||||
ADD CONSTRAINT fk_27548c6db3 FOREIGN KEY (hashed_storage_migrated_event_id) REFERENCES geo_hashed_storage_migrated_events(id) ON DELETE CASCADE;
|
ADD CONSTRAINT fk_27548c6db3 FOREIGN KEY (hashed_storage_migrated_event_id) REFERENCES geo_hashed_storage_migrated_events(id) ON DELETE CASCADE;
|
||||||
|
@ -26220,7 +26221,7 @@ ALTER TABLE ONLY releases
|
||||||
ALTER TABLE ONLY geo_event_log
|
ALTER TABLE ONLY geo_event_log
|
||||||
ADD CONSTRAINT fk_4a99ebfd60 FOREIGN KEY (repositories_changed_event_id) REFERENCES geo_repositories_changed_events(id) ON DELETE CASCADE;
|
ADD CONSTRAINT fk_4a99ebfd60 FOREIGN KEY (repositories_changed_event_id) REFERENCES geo_repositories_changed_events(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
ALTER TABLE ONLY ci_build_trace_sections
|
ALTER TABLE ONLY dep_ci_build_trace_sections
|
||||||
ADD CONSTRAINT fk_4ebe41f502 FOREIGN KEY (build_id) REFERENCES ci_builds(id) ON DELETE CASCADE;
|
ADD CONSTRAINT fk_4ebe41f502 FOREIGN KEY (build_id) REFERENCES ci_builds(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
ALTER TABLE ONLY alert_management_alerts
|
ALTER TABLE ONLY alert_management_alerts
|
||||||
|
@ -26517,6 +26518,9 @@ ALTER TABLE ONLY alert_management_alerts
|
||||||
ALTER TABLE ONLY identities
|
ALTER TABLE ONLY identities
|
||||||
ADD CONSTRAINT fk_aade90f0fc FOREIGN KEY (saml_provider_id) REFERENCES saml_providers(id) ON DELETE CASCADE;
|
ADD CONSTRAINT fk_aade90f0fc FOREIGN KEY (saml_provider_id) REFERENCES saml_providers(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
ALTER TABLE ONLY dep_ci_build_trace_sections
|
||||||
|
ADD CONSTRAINT fk_ab7c104e26 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
ALTER TABLE ONLY ci_sources_pipelines
|
ALTER TABLE ONLY ci_sources_pipelines
|
||||||
ADD CONSTRAINT fk_acd9737679 FOREIGN KEY (source_project_id) REFERENCES projects(id) ON DELETE CASCADE;
|
ADD CONSTRAINT fk_acd9737679 FOREIGN KEY (source_project_id) REFERENCES projects(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
@ -26787,6 +26791,9 @@ ALTER TABLE ONLY cluster_agents
|
||||||
ALTER TABLE ONLY protected_tag_create_access_levels
|
ALTER TABLE ONLY protected_tag_create_access_levels
|
||||||
ADD CONSTRAINT fk_f7dfda8c51 FOREIGN KEY (protected_tag_id) REFERENCES protected_tags(id) ON DELETE CASCADE;
|
ADD CONSTRAINT fk_f7dfda8c51 FOREIGN KEY (protected_tag_id) REFERENCES protected_tags(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
ALTER TABLE ONLY dep_ci_build_trace_section_names
|
||||||
|
ADD CONSTRAINT fk_f8cd72cd26 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
ALTER TABLE ONLY ci_stages
|
ALTER TABLE ONLY ci_stages
|
||||||
ADD CONSTRAINT fk_fb57e6cc56 FOREIGN KEY (pipeline_id) REFERENCES ci_pipelines(id) ON DELETE CASCADE;
|
ADD CONSTRAINT fk_fb57e6cc56 FOREIGN KEY (pipeline_id) REFERENCES ci_pipelines(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
@ -27903,9 +27910,6 @@ ALTER TABLE ONLY merge_request_user_mentions
|
||||||
ALTER TABLE ONLY x509_commit_signatures
|
ALTER TABLE ONLY x509_commit_signatures
|
||||||
ADD CONSTRAINT fk_rails_ab07452314 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
|
ADD CONSTRAINT fk_rails_ab07452314 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
ALTER TABLE ONLY ci_build_trace_sections
|
|
||||||
ADD CONSTRAINT fk_rails_ab7c104e26 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
|
|
||||||
|
|
||||||
ALTER TABLE ONLY resource_iteration_events
|
ALTER TABLE ONLY resource_iteration_events
|
||||||
ADD CONSTRAINT fk_rails_abf5d4affa FOREIGN KEY (issue_id) REFERENCES issues(id) ON DELETE CASCADE;
|
ADD CONSTRAINT fk_rails_abf5d4affa FOREIGN KEY (issue_id) REFERENCES issues(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
@ -28365,9 +28369,6 @@ ALTER TABLE ONLY issues_self_managed_prometheus_alert_events
|
||||||
ALTER TABLE ONLY merge_requests_closing_issues
|
ALTER TABLE ONLY merge_requests_closing_issues
|
||||||
ADD CONSTRAINT fk_rails_f8540692be FOREIGN KEY (issue_id) REFERENCES issues(id) ON DELETE CASCADE;
|
ADD CONSTRAINT fk_rails_f8540692be FOREIGN KEY (issue_id) REFERENCES issues(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
ALTER TABLE ONLY ci_build_trace_section_names
|
|
||||||
ADD CONSTRAINT fk_rails_f8cd72cd26 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
|
|
||||||
|
|
||||||
ALTER TABLE ONLY merge_trains
|
ALTER TABLE ONLY merge_trains
|
||||||
ADD CONSTRAINT fk_rails_f90820cb08 FOREIGN KEY (pipeline_id) REFERENCES ci_pipelines(id) ON DELETE SET NULL;
|
ADD CONSTRAINT fk_rails_f90820cb08 FOREIGN KEY (pipeline_id) REFERENCES ci_pipelines(id) ON DELETE SET NULL;
|
||||||
|
|
||||||
|
|
|
@ -200,7 +200,7 @@ successfully, you must replicate their data using some other means.
|
||||||
|[Package Registry for generic packages](../../../user/packages/generic_packages/index.md) | **Yes** (13.5) | [**Yes**](#limitation-of-verification-for-files-in-object-storage) (13.10) | Via Object Storage provider if supported. Native Geo support (Beta). | Behind feature flag `geo_package_file_replication`, enabled by default. |
|
|[Package Registry for generic packages](../../../user/packages/generic_packages/index.md) | **Yes** (13.5) | [**Yes**](#limitation-of-verification-for-files-in-object-storage) (13.10) | Via Object Storage provider if supported. Native Geo support (Beta). | Behind feature flag `geo_package_file_replication`, enabled by default. |
|
||||||
|[Versioned Terraform State](../../terraform_state.md) | **Yes** (13.5) | [**Yes**](#limitation-of-verification-for-files-in-object-storage) (13.12) | Via Object Storage provider if supported. Native Geo support (Beta). | Replication is behind the feature flag `geo_terraform_state_version_replication`, enabled by default. Verification was behind the feature flag `geo_terraform_state_version_verification`, which was removed in 14.0|
|
|[Versioned Terraform State](../../terraform_state.md) | **Yes** (13.5) | [**Yes**](#limitation-of-verification-for-files-in-object-storage) (13.12) | Via Object Storage provider if supported. Native Geo support (Beta). | Replication is behind the feature flag `geo_terraform_state_version_replication`, enabled by default. Verification was behind the feature flag `geo_terraform_state_version_verification`, which was removed in 14.0|
|
||||||
|[External merge request diffs](../../merge_request_diffs.md) | **Yes** (13.5) | No | Via Object Storage provider if supported. Native Geo support (Beta). | Replication is behind the feature flag `geo_merge_request_diff_replication`, enabled by default. Verification is under development, behind the feature flag `geo_merge_request_diff_verification`, introduced in 14.0.|
|
|[External merge request diffs](../../merge_request_diffs.md) | **Yes** (13.5) | No | Via Object Storage provider if supported. Native Geo support (Beta). | Replication is behind the feature flag `geo_merge_request_diff_replication`, enabled by default. Verification is under development, behind the feature flag `geo_merge_request_diff_verification`, introduced in 14.0.|
|
||||||
|[Versioned snippets](../../../user/snippets.md#versioned-snippets) | [**Yes** (13.7)](https://gitlab.com/groups/gitlab-org/-/epics/2809) | [**Yes**](https://gitlab.com/groups/gitlab-org/-/epics/2810) | No | Verification was implemented behind the feature flag `geo_snippet_repository_verification` in 13.11, and the feature flag was removed in 14.2. |
|
|[Versioned snippets](../../../user/snippets.md#versioned-snippets) | [**Yes** (13.7)](https://gitlab.com/groups/gitlab-org/-/epics/2809) | [**Yes** (14.2)](https://gitlab.com/groups/gitlab-org/-/epics/2810) | No | Verification was implemented behind the feature flag `geo_snippet_repository_verification` in 13.11, and the feature flag was removed in 14.2. |
|
||||||
|[Server-side Git hooks](../../server_hooks.md) | [No](https://gitlab.com/groups/gitlab-org/-/epics/1867) | No | No | |
|
|[Server-side Git hooks](../../server_hooks.md) | [No](https://gitlab.com/groups/gitlab-org/-/epics/1867) | No | No | |
|
||||||
|[Elasticsearch integration](../../../integration/elasticsearch.md) | [No](https://gitlab.com/gitlab-org/gitlab/-/issues/1186) | No | No | |
|
|[Elasticsearch integration](../../../integration/elasticsearch.md) | [No](https://gitlab.com/gitlab-org/gitlab/-/issues/1186) | No | No | |
|
||||||
|[GitLab Pages](../../pages/index.md) | [No](https://gitlab.com/groups/gitlab-org/-/epics/589) | No | Via Object Storage provider if supported. **No** native Geo support (Beta). | |
|
|[GitLab Pages](../../pages/index.md) | [No](https://gitlab.com/groups/gitlab-org/-/epics/589) | No | Via Object Storage provider if supported. **No** native Geo support (Beta). | |
|
||||||
|
|
|
@ -323,7 +323,7 @@ See more information in [!19581](https://gitlab.com/gitlab-org/gitlab-foss/-/mer
|
||||||
|
|
||||||
### LFS commands fail on TLS v1.3 server
|
### LFS commands fail on TLS v1.3 server
|
||||||
|
|
||||||
If you configure GitLab to [disable TLS v1.2](https://docs.gitlab.com/omnibus/settings/nginx.md)
|
If you configure GitLab to [disable TLS v1.2](https://docs.gitlab.com/omnibus/settings/nginx.html)
|
||||||
and only enable TLS v1.3 connections, LFS operations require a
|
and only enable TLS v1.3 connections, LFS operations require a
|
||||||
[Git LFS client](https://git-lfs.github.com) version 2.11.0 or later. If you use
|
[Git LFS client](https://git-lfs.github.com) version 2.11.0 or later. If you use
|
||||||
a Git LFS client earlier than version 2.11.0, GitLab displays an error:
|
a Git LFS client earlier than version 2.11.0, GitLab displays an error:
|
||||||
|
@ -334,7 +334,7 @@ error: failed to fetch some objects from 'https://username:[MASKED]@gitlab.examp
|
||||||
```
|
```
|
||||||
|
|
||||||
When using GitLab CI over a TLS v1.3 configured GitLab server, you must
|
When using GitLab CI over a TLS v1.3 configured GitLab server, you must
|
||||||
[upgrade to GitLab Runner](https://docs.gitlab.com/runner/install/index.md) 13.2.0
|
[upgrade to GitLab Runner](https://docs.gitlab.com/runner/install/index.html) 13.2.0
|
||||||
or later to receive an updated Git LFS client version via
|
or later to receive an updated Git LFS client version via
|
||||||
the included [GitLab Runner Helper image](https://docs.gitlab.com/runner/configuration/advanced-configuration.html#helper-image).
|
the included [GitLab Runner Helper image](https://docs.gitlab.com/runner/configuration/advanced-configuration.html#helper-image).
|
||||||
|
|
||||||
|
|
|
@ -303,6 +303,63 @@ If you enable Monitoring, it must be enabled on **all** database servers.
|
||||||
|
|
||||||
1. Run `sudo gitlab-ctl reconfigure` to compile the configuration.
|
1. Run `sudo gitlab-ctl reconfigure` to compile the configuration.
|
||||||
|
|
||||||
|
#### Enable TLS support for the Patroni API
|
||||||
|
|
||||||
|
By default, Patroni's [REST API](https://patroni.readthedocs.io/en/latest/rest_api.html#rest-api) is served over HTTP.
|
||||||
|
You have the option to enable TLS and use HTTPS over the same [port](https://docs.gitlab.com/omnibus/package-information/defaults.html#patroni).
|
||||||
|
|
||||||
|
To enable TLS, you need PEM-formatted certificate and private key files. Both files must be readable by the PostgreSQL user (`gitlab-psql` by default, or the one set by `postgresql['username']`):
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
patroni['tls_certificate_file'] = '/path/to/server/certificate.pem'
|
||||||
|
patroni['tls_key_file'] = '/path/to/server/key.pem'
|
||||||
|
```
|
||||||
|
|
||||||
|
If the server's private key is encrypted, specify the password to decrypt it:
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
patroni['tls_key_password'] = 'private-key-password' # This is the plain-text password.
|
||||||
|
```
|
||||||
|
|
||||||
|
If you are using a self-signed certificate or an internal CA, you need to either disable the TLS verification or pass the certificate of the
|
||||||
|
internal CA, otherwise you may run into an unexpected error when using the `gitlab-ctl patroni ....` commands. Omnibus ensures that Patroni API
|
||||||
|
clients honor this configuration.
|
||||||
|
|
||||||
|
TLS certificate verification is enabled by default. To disable it:
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
patroni['tls_verify'] = false
|
||||||
|
```
|
||||||
|
|
||||||
|
Alternatively, you can pass a PEM-formatted certificate of the internal CA. Again, the file must be readable by the PostgreSQL user:
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
patroni['tls_ca_file'] = '/path/to/ca.pem'
|
||||||
|
```
|
||||||
|
|
||||||
|
When TLS is enabled, mutual authentication of the API server and client is possible for all endpoints, the extent of which depends on
|
||||||
|
the `patroni['tls_client_mode']` attribute:
|
||||||
|
|
||||||
|
- `none` (default): the API will not check for any client certificates.
|
||||||
|
- `optional`: client certificates are required for all [unsafe](https://patroni.readthedocs.io/en/latest/security.html#protecting-the-rest-api) API calls.
|
||||||
|
- `required`: client certificates are required for all API calls.
|
||||||
|
|
||||||
|
The client certificates are verified against the CA certificate that is specified with the `patroni['tls_ca_file']` attribute. Therefore,
|
||||||
|
this attribute is required for mutual TLS authentication. You also need to specify PEM-formatted client certificate and private key files.
|
||||||
|
Both files must be readable by the PostgreSQL user:
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
patroni['tls_client_mode'] = 'required'
|
||||||
|
patroni['tls_ca_file'] = '/path/to/ca.pem'
|
||||||
|
|
||||||
|
patroni['tls_client_certificate_file'] = '/path/to/client/certificate.pem'
|
||||||
|
patroni['tls_client_key_file'] = '/path/to/client/key.pem'
|
||||||
|
```
|
||||||
|
|
||||||
|
You can use different certificates and keys for both API server and client on different Patroni nodes as long as they can be verified.
|
||||||
|
However, the CA certificate (`patroni['tls_ca_file']`), TLS certificate verification (`patroni['tls_verify']`), and client TLS
|
||||||
|
authentication mode (`patroni['tls_client_mode']`), must each have the same value on all nodes.
|
||||||
|
|
||||||
### Configuring the PgBouncer node
|
### Configuring the PgBouncer node
|
||||||
|
|
||||||
1. Make sure you collect [`CONSUL_SERVER_NODES`](#consul-information), [`CONSUL_PASSWORD_HASH`](#consul-information), and [`PGBOUNCER_PASSWORD_HASH`](#pgbouncer-information) before executing the next step.
|
1. Make sure you collect [`CONSUL_SERVER_NODES`](#consul-information), [`CONSUL_PASSWORD_HASH`](#consul-information), and [`PGBOUNCER_PASSWORD_HASH`](#pgbouncer-information) before executing the next step.
|
||||||
|
|
|
@ -285,5 +285,5 @@ The output in `/tmp/puma.txt` may help diagnose the root cause.
|
||||||
|
|
||||||
## More information
|
## More information
|
||||||
|
|
||||||
- [Debugging Stuck Ruby Processes](https://newrelic.com/blog/engineering/debugging-stuck-ruby-processes-what-to-do-before-you-kill-9/)
|
- [Debugging Stuck Ruby Processes](https://newrelic.com/blog/best-practices/debugging-stuck-ruby-processes-what-to-do-before-you-kill-9)
|
||||||
- [Cheat sheet of using GDB and Ruby processes](gdb-stuck-ruby.txt)
|
- [Cheat sheet of using GDB and Ruby processes](gdb-stuck-ruby.txt)
|
||||||
|
|
|
@ -6237,6 +6237,29 @@ The connection type for [`Package`](#package).
|
||||||
| <a id="packageconnectionnodes"></a>`nodes` | [`[Package]`](#package) | A list of nodes. |
|
| <a id="packageconnectionnodes"></a>`nodes` | [`[Package]`](#package) | A list of nodes. |
|
||||||
| <a id="packageconnectionpageinfo"></a>`pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
|
| <a id="packageconnectionpageinfo"></a>`pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
|
||||||
|
|
||||||
|
#### `PackageDependencyLinkConnection`
|
||||||
|
|
||||||
|
The connection type for [`PackageDependencyLink`](#packagedependencylink).
|
||||||
|
|
||||||
|
##### Fields
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
| ---- | ---- | ----------- |
|
||||||
|
| <a id="packagedependencylinkconnectionedges"></a>`edges` | [`[PackageDependencyLinkEdge]`](#packagedependencylinkedge) | A list of edges. |
|
||||||
|
| <a id="packagedependencylinkconnectionnodes"></a>`nodes` | [`[PackageDependencyLink]`](#packagedependencylink) | A list of nodes. |
|
||||||
|
| <a id="packagedependencylinkconnectionpageinfo"></a>`pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
|
||||||
|
|
||||||
|
#### `PackageDependencyLinkEdge`
|
||||||
|
|
||||||
|
The edge type for [`PackageDependencyLink`](#packagedependencylink).
|
||||||
|
|
||||||
|
##### Fields
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
| ---- | ---- | ----------- |
|
||||||
|
| <a id="packagedependencylinkedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
|
||||||
|
| <a id="packagedependencylinkedgenode"></a>`node` | [`PackageDependencyLink`](#packagedependencylink) | The item at the end of the edge. |
|
||||||
|
|
||||||
#### `PackageEdge`
|
#### `PackageEdge`
|
||||||
|
|
||||||
The edge type for [`Package`](#package).
|
The edge type for [`Package`](#package).
|
||||||
|
@ -11330,6 +11353,17 @@ Represents the network policy.
|
||||||
| <a id="notepermissionsrepositionnote"></a>`repositionNote` | [`Boolean!`](#boolean) | Indicates the user can perform `reposition_note` on this resource. |
|
| <a id="notepermissionsrepositionnote"></a>`repositionNote` | [`Boolean!`](#boolean) | Indicates the user can perform `reposition_note` on this resource. |
|
||||||
| <a id="notepermissionsresolvenote"></a>`resolveNote` | [`Boolean!`](#boolean) | Indicates the user can perform `resolve_note` on this resource. |
|
| <a id="notepermissionsresolvenote"></a>`resolveNote` | [`Boolean!`](#boolean) | Indicates the user can perform `resolve_note` on this resource. |
|
||||||
|
|
||||||
|
### `NugetDependencyLinkMetadata`
|
||||||
|
|
||||||
|
Nuget dependency link metadata.
|
||||||
|
|
||||||
|
#### Fields
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
| ---- | ---- | ----------- |
|
||||||
|
| <a id="nugetdependencylinkmetadataid"></a>`id` | [`PackagesNugetDependencyLinkMetadatumID!`](#packagesnugetdependencylinkmetadatumid) | ID of the metadatum. |
|
||||||
|
| <a id="nugetdependencylinkmetadatatargetframework"></a>`targetFramework` | [`String!`](#string) | Target framework of the depdency link package. |
|
||||||
|
|
||||||
### `NugetMetadata`
|
### `NugetMetadata`
|
||||||
|
|
||||||
Nuget metadata.
|
Nuget metadata.
|
||||||
|
@ -11401,6 +11435,31 @@ Represents a composer JSON file.
|
||||||
| <a id="packagecomposerjsontypetype"></a>`type` | [`String`](#string) | The type set in the Composer JSON file. |
|
| <a id="packagecomposerjsontypetype"></a>`type` | [`String`](#string) | The type set in the Composer JSON file. |
|
||||||
| <a id="packagecomposerjsontypeversion"></a>`version` | [`String`](#string) | The version set in the Composer JSON file. |
|
| <a id="packagecomposerjsontypeversion"></a>`version` | [`String`](#string) | The version set in the Composer JSON file. |
|
||||||
|
|
||||||
|
### `PackageDependency`
|
||||||
|
|
||||||
|
Represents a package dependency.
|
||||||
|
|
||||||
|
#### Fields
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
| ---- | ---- | ----------- |
|
||||||
|
| <a id="packagedependencyid"></a>`id` | [`PackagesDependencyID!`](#packagesdependencyid) | ID of the dependency. |
|
||||||
|
| <a id="packagedependencyname"></a>`name` | [`String!`](#string) | Name of the dependency. |
|
||||||
|
| <a id="packagedependencyversionpattern"></a>`versionPattern` | [`String!`](#string) | Version pattern of the dependency. |
|
||||||
|
|
||||||
|
### `PackageDependencyLink`
|
||||||
|
|
||||||
|
Represents a package dependency link.
|
||||||
|
|
||||||
|
#### Fields
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
| ---- | ---- | ----------- |
|
||||||
|
| <a id="packagedependencylinkdependency"></a>`dependency` | [`PackageDependency`](#packagedependency) | Dependency. |
|
||||||
|
| <a id="packagedependencylinkdependencytype"></a>`dependencyType` | [`PackageDependencyType!`](#packagedependencytype) | Dependency type. |
|
||||||
|
| <a id="packagedependencylinkid"></a>`id` | [`PackagesDependencyLinkID!`](#packagesdependencylinkid) | ID of the dependency link. |
|
||||||
|
| <a id="packagedependencylinkmetadata"></a>`metadata` | [`DependencyLinkMetadata`](#dependencylinkmetadata) | Dependency link metadata. |
|
||||||
|
|
||||||
### `PackageDetailsType`
|
### `PackageDetailsType`
|
||||||
|
|
||||||
Represents a package details in the Package Registry. Note that this type is in beta and susceptible to changes.
|
Represents a package details in the Package Registry. Note that this type is in beta and susceptible to changes.
|
||||||
|
@ -11410,6 +11469,7 @@ Represents a package details in the Package Registry. Note that this type is in
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
| ---- | ---- | ----------- |
|
| ---- | ---- | ----------- |
|
||||||
| <a id="packagedetailstypecreatedat"></a>`createdAt` | [`Time!`](#time) | Date of creation. |
|
| <a id="packagedetailstypecreatedat"></a>`createdAt` | [`Time!`](#time) | Date of creation. |
|
||||||
|
| <a id="packagedetailstypedependencylinks"></a>`dependencyLinks` | [`PackageDependencyLinkConnection`](#packagedependencylinkconnection) | Dependency link. (see [Connections](#connections)) |
|
||||||
| <a id="packagedetailstypeid"></a>`id` | [`PackagesPackageID!`](#packagespackageid) | ID of the package. |
|
| <a id="packagedetailstypeid"></a>`id` | [`PackagesPackageID!`](#packagespackageid) | ID of the package. |
|
||||||
| <a id="packagedetailstypemetadata"></a>`metadata` | [`PackageMetadata`](#packagemetadata) | Package metadata. |
|
| <a id="packagedetailstypemetadata"></a>`metadata` | [`PackageMetadata`](#packagemetadata) | Package metadata. |
|
||||||
| <a id="packagedetailstypename"></a>`name` | [`String!`](#string) | Name of the package. |
|
| <a id="packagedetailstypename"></a>`name` | [`String!`](#string) | Name of the package. |
|
||||||
|
@ -15330,6 +15390,15 @@ Rotation length unit of an on-call rotation.
|
||||||
| <a id="oncallrotationunitenumhours"></a>`HOURS` | Hours. |
|
| <a id="oncallrotationunitenumhours"></a>`HOURS` | Hours. |
|
||||||
| <a id="oncallrotationunitenumweeks"></a>`WEEKS` | Weeks. |
|
| <a id="oncallrotationunitenumweeks"></a>`WEEKS` | Weeks. |
|
||||||
|
|
||||||
|
### `PackageDependencyType`
|
||||||
|
|
||||||
|
| Value | Description |
|
||||||
|
| ----- | ----------- |
|
||||||
|
| <a id="packagedependencytypebundle_dependencies"></a>`BUNDLE_DEPENDENCIES` | bundleDependencies dependency type. |
|
||||||
|
| <a id="packagedependencytypedependencies"></a>`DEPENDENCIES` | dependencies dependency type. |
|
||||||
|
| <a id="packagedependencytypedev_dependencies"></a>`DEV_DEPENDENCIES` | devDependencies dependency type. |
|
||||||
|
| <a id="packagedependencytypepeer_dependencies"></a>`PEER_DEPENDENCIES` | peerDependencies dependency type. |
|
||||||
|
|
||||||
### `PackageGroupSort`
|
### `PackageGroupSort`
|
||||||
|
|
||||||
Values for sorting group packages.
|
Values for sorting group packages.
|
||||||
|
@ -16204,12 +16273,30 @@ A `PackagesConanMetadatumID` is a global ID. It is encoded as a string.
|
||||||
|
|
||||||
An example `PackagesConanMetadatumID` is: `"gid://gitlab/Packages::Conan::Metadatum/1"`.
|
An example `PackagesConanMetadatumID` is: `"gid://gitlab/Packages::Conan::Metadatum/1"`.
|
||||||
|
|
||||||
|
### `PackagesDependencyID`
|
||||||
|
|
||||||
|
A `PackagesDependencyID` is a global ID. It is encoded as a string.
|
||||||
|
|
||||||
|
An example `PackagesDependencyID` is: `"gid://gitlab/Packages::Dependency/1"`.
|
||||||
|
|
||||||
|
### `PackagesDependencyLinkID`
|
||||||
|
|
||||||
|
A `PackagesDependencyLinkID` is a global ID. It is encoded as a string.
|
||||||
|
|
||||||
|
An example `PackagesDependencyLinkID` is: `"gid://gitlab/Packages::DependencyLink/1"`.
|
||||||
|
|
||||||
### `PackagesMavenMetadatumID`
|
### `PackagesMavenMetadatumID`
|
||||||
|
|
||||||
A `PackagesMavenMetadatumID` is a global ID. It is encoded as a string.
|
A `PackagesMavenMetadatumID` is a global ID. It is encoded as a string.
|
||||||
|
|
||||||
An example `PackagesMavenMetadatumID` is: `"gid://gitlab/Packages::Maven::Metadatum/1"`.
|
An example `PackagesMavenMetadatumID` is: `"gid://gitlab/Packages::Maven::Metadatum/1"`.
|
||||||
|
|
||||||
|
### `PackagesNugetDependencyLinkMetadatumID`
|
||||||
|
|
||||||
|
A `PackagesNugetDependencyLinkMetadatumID` is a global ID. It is encoded as a string.
|
||||||
|
|
||||||
|
An example `PackagesNugetDependencyLinkMetadatumID` is: `"gid://gitlab/Packages::Nuget::DependencyLinkMetadatum/1"`.
|
||||||
|
|
||||||
### `PackagesNugetMetadatumID`
|
### `PackagesNugetMetadatumID`
|
||||||
|
|
||||||
A `PackagesNugetMetadatumID` is a global ID. It is encoded as a string.
|
A `PackagesNugetMetadatumID` is a global ID. It is encoded as a string.
|
||||||
|
@ -16339,6 +16426,14 @@ abstract types.
|
||||||
|
|
||||||
### Unions
|
### Unions
|
||||||
|
|
||||||
|
#### `DependencyLinkMetadata`
|
||||||
|
|
||||||
|
Represents metadata associated with a dependency link.
|
||||||
|
|
||||||
|
One of:
|
||||||
|
|
||||||
|
- [`NugetDependencyLinkMetadata`](#nugetdependencylinkmetadata)
|
||||||
|
|
||||||
#### `Issuable`
|
#### `Issuable`
|
||||||
|
|
||||||
Represents an issuable.
|
Represents an issuable.
|
||||||
|
|
|
@ -115,11 +115,15 @@ We also use two secure variables:
|
||||||
|
|
||||||
## Storing API keys
|
## Storing API keys
|
||||||
|
|
||||||
To add secure variables, navigate to your project's
|
To store API keys as secure variables:
|
||||||
**Settings > CI/CD > Variables**. The variables defined
|
|
||||||
in the project settings are sent along with the build script to the runner.
|
1. On the top bar, select **Menu > Projects** and find your project.
|
||||||
|
1. On the left sidebar, select **Settings > CI/CD**.
|
||||||
|
1. Expand **Variables**.
|
||||||
|
|
||||||
|
The variables defined in the project settings are sent along with the build script to the runner.
|
||||||
The secure variables are stored out of the repository. Never store secrets in
|
The secure variables are stored out of the repository. Never store secrets in
|
||||||
your project's `.gitlab-ci.yml`. It is also important that the secret's value
|
your project's `.gitlab-ci.yml` file. It is also important that the secret's value
|
||||||
is hidden in the job log.
|
is hidden in the job log.
|
||||||
|
|
||||||
You access added variable by prefixing it's name with `$` (on non-Windows runners)
|
You access added variable by prefixing it's name with `$` (on non-Windows runners)
|
||||||
|
@ -128,4 +132,4 @@ or `%` (for Windows Batch runners):
|
||||||
- `$VARIABLE`: Use for non-Windows runners
|
- `$VARIABLE`: Use for non-Windows runners
|
||||||
- `%VARIABLE%`: Use for Windows Batch runners
|
- `%VARIABLE%`: Use for Windows Batch runners
|
||||||
|
|
||||||
Read more about the [CI/CD variables](../../variables/index.md).
|
Read more about [CI/CD variables](../../variables/index.md).
|
||||||
|
|
|
@ -1471,6 +1471,7 @@ in the project.
|
||||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/47063) in GitLab 12.2.
|
> - [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/47063) in GitLab 12.2.
|
||||||
> - In GitLab 12.3, maximum number of jobs in `needs` array raised from five to 50.
|
> - In GitLab 12.3, maximum number of jobs in `needs` array raised from five to 50.
|
||||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/30631) in GitLab 12.8, `needs: []` lets jobs start immediately.
|
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/30631) in GitLab 12.8, `needs: []` lets jobs start immediately.
|
||||||
|
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/30632) in GitLab 14.2, you can refer to jobs in the same stage as the job you are configuring.
|
||||||
|
|
||||||
Use `needs:` to execute jobs out-of-order. Relationships between jobs
|
Use `needs:` to execute jobs out-of-order. Relationships between jobs
|
||||||
that use `needs` can be visualized as a [directed acyclic graph](../directed_acyclic_graph/index.md).
|
that use `needs` can be visualized as a [directed acyclic graph](../directed_acyclic_graph/index.md).
|
||||||
|
@ -1531,15 +1532,10 @@ production:
|
||||||
#### Requirements and limitations
|
#### Requirements and limitations
|
||||||
|
|
||||||
- In [GitLab 14.1 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/30632) you
|
- In [GitLab 14.1 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/30632) you
|
||||||
can refer to jobs in the same stage as the job you are configuring. This feature is:
|
can refer to jobs in the same stage as the job you are configuring. This feature is
|
||||||
|
enabled on GitLab.com and ready for production use. On self-managed [GitLab 14.2 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/30632)
|
||||||
- [Deployed behind a feature flag](../../user/feature_flags.md), disabled by default.
|
this feature is available by default. To hide the feature, ask an administrator to
|
||||||
- Disabled on GitLab.com.
|
[disable the `ci_same_stage_job_needs` flag](../../administration/feature_flags.md).
|
||||||
- Not recommended for production use.
|
|
||||||
|
|
||||||
For GitLab self-managed instances, GitLab administrators can choose to
|
|
||||||
[enable it](#enable-or-disable-needs-for-jobs-in-the-same-stage).
|
|
||||||
|
|
||||||
- In GitLab 14.0 and older, you can only refer to jobs in earlier stages.
|
- In GitLab 14.0 and older, you can only refer to jobs in earlier stages.
|
||||||
- In GitLab 13.9 and older, if `needs:` refers to a job that might not be added to
|
- In GitLab 13.9 and older, if `needs:` refers to a job that might not be added to
|
||||||
a pipeline because of `only`, `except`, or `rules`, the pipeline might fail to create.
|
a pipeline because of `only`, `except`, or `rules`, the pipeline might fail to create.
|
||||||
|
@ -1557,22 +1553,6 @@ production:
|
||||||
- Stages must be explicitly defined for all jobs
|
- Stages must be explicitly defined for all jobs
|
||||||
that have the keyword `needs:` or are referred to by one.
|
that have the keyword `needs:` or are referred to by one.
|
||||||
|
|
||||||
##### Enable or disable `needs` for jobs in the same stage **(FREE SELF)**
|
|
||||||
|
|
||||||
`needs` for jobs in the same stage is under development but ready for production use.
|
|
||||||
It is deployed behind a feature flag that is **enabled by default**.
|
|
||||||
[GitLab administrators with access to the GitLab Rails
|
|
||||||
console](../../administration/feature_flags.md)
|
|
||||||
can opt to disable it.
|
|
||||||
|
|
||||||
To enable it:
|
|
||||||
|
|
||||||
`Feature.enable(:ci_same_stage_job_needs)`
|
|
||||||
|
|
||||||
To disable it:
|
|
||||||
|
|
||||||
`Feature.disable(:ci_same_stage_job_needs)`
|
|
||||||
|
|
||||||
##### Changing the `needs:` job limit **(FREE SELF)**
|
##### Changing the `needs:` job limit **(FREE SELF)**
|
||||||
|
|
||||||
The maximum number of jobs that can be defined in `needs:` defaults to 50.
|
The maximum number of jobs that can be defined in `needs:` defaults to 50.
|
||||||
|
|
|
@ -122,7 +122,7 @@ Title case.
|
||||||
|
|
||||||
## GitLab
|
## GitLab
|
||||||
|
|
||||||
Do not make possessive (GitLab's). This guidance follows [GitLab Brand Guidelines](https://about.gitlab.com/handbook/marketing/corporate-marketing/brand-activation/brand-guidelines/#trademark).
|
Do not make possessive (GitLab's). This guidance follows [GitLab Trademark Guidelines](https://about.gitlab.com/handbook/marketing/corporate-marketing/brand-activation/trademark-guidelines/).
|
||||||
|
|
||||||
## GitLab.com
|
## GitLab.com
|
||||||
|
|
||||||
|
|
|
@ -338,6 +338,16 @@ Page::Project::Pipeline::Show.perform do |pipeline|
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Use `eventually_` matchers for expectations that require waiting
|
||||||
|
|
||||||
|
When something requires waiting to be matched, use `eventually_` matchers with clear wait duration definition.
|
||||||
|
|
||||||
|
`Eventually` matchers use the following naming pattern: `eventually_${rspec_matcher_name}`. They are defined in [eventually_matcher.rb](https://gitlab.com/gitlab-org/gitlab/-/blob/master/qa/spec/support/matchers/eventually_matcher.rb).
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
expect { async_value }.to eventually_eq(value).within(max_duration: 120, max_attempts: 60, reload_page: page)
|
||||||
|
```
|
||||||
|
|
||||||
### Create negatable matchers to speed `expect` checks
|
### Create negatable matchers to speed `expect` checks
|
||||||
|
|
||||||
However, sometimes we want to check that something is _not_ as we _don't_ want it to be. In other
|
However, sometimes we want to check that something is _not_ as we _don't_ want it to be. In other
|
||||||
|
|
|
@ -85,11 +85,15 @@ entire content by selecting **Show file contents**.
|
||||||
|
|
||||||
## Ignore whitespace changes in Merge Request diff view
|
## Ignore whitespace changes in Merge Request diff view
|
||||||
|
|
||||||
If you select the **Hide whitespace changes** button, you can see the diff
|
Whitespace changes can make it more difficult to see the substantive changes in
|
||||||
without whitespace changes (if there are any). This is also working when on a
|
a merge request. You can choose to hide or show whitespace changes:
|
||||||
specific commit page.
|
|
||||||
|
|
||||||
![MR diff](img/merge_request_diff.png)
|
1. Go to your merge request, and select the **Changes** tab.
|
||||||
|
1. Above the list of changed files, select **(settings)** **Preferences** to
|
||||||
|
display the preferences menu.
|
||||||
|
1. Select or deselect **Show whitespace changes**:
|
||||||
|
|
||||||
|
![MR diff](img/merge_request_diff_v14_2.png)
|
||||||
|
|
||||||
## Mark files as viewed
|
## Mark files as viewed
|
||||||
|
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 26 KiB |
Binary file not shown.
After Width: | Height: | Size: 26 KiB |
|
@ -16,11 +16,8 @@ module Gitlab
|
||||||
environment coverage retry parallel interruptible timeout
|
environment coverage retry parallel interruptible timeout
|
||||||
release dast_configuration secrets].freeze
|
release dast_configuration secrets].freeze
|
||||||
|
|
||||||
REQUIRED_BY_NEEDS = %i[stage].freeze
|
|
||||||
|
|
||||||
validations do
|
validations do
|
||||||
validates :config, allowed_keys: ALLOWED_KEYS + PROCESSABLE_ALLOWED_KEYS
|
validates :config, allowed_keys: ALLOWED_KEYS + PROCESSABLE_ALLOWED_KEYS
|
||||||
validates :config, required_keys: REQUIRED_BY_NEEDS, if: :has_needs?
|
|
||||||
validates :script, presence: true
|
validates :script, presence: true
|
||||||
|
|
||||||
with_options allow_nil: true do
|
with_options allow_nil: true do
|
||||||
|
|
|
@ -9198,7 +9198,7 @@ msgstr ""
|
||||||
msgid "CorpusManagement|Latest Job:"
|
msgid "CorpusManagement|Latest Job:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "CorpusManagement|New corpus needs to be a upload in *.zip format. Maximum 10Gib"
|
msgid "CorpusManagement|New corpus needs to be a upload in *.zip format. Maximum 10GB"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "CorpusManagement|New upload"
|
msgid "CorpusManagement|New upload"
|
||||||
|
@ -10737,6 +10737,9 @@ msgstr ""
|
||||||
msgid "Delete comment"
|
msgid "Delete comment"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Delete corpus"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Delete domain"
|
msgid "Delete domain"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
|
@ -81,7 +81,9 @@ module QA
|
||||||
Page::Group::BulkImport.perform do |import_page|
|
Page::Group::BulkImport.perform do |import_page|
|
||||||
imported_group
|
imported_group
|
||||||
|
|
||||||
expect { imported_group.import_status }.to eventually_eq('finished').within(duration: 300, interval: 2)
|
expect { imported_group.import_status }.to(
|
||||||
|
eventually_eq('finished').within(max_duration: 300, sleep_interval: 2)
|
||||||
|
)
|
||||||
|
|
||||||
aggregate_failures do
|
aggregate_failures do
|
||||||
expect(imported_group.reload!).to eq(source_group)
|
expect(imported_group.reload!).to eq(source_group)
|
||||||
|
|
|
@ -33,7 +33,7 @@ module QA
|
||||||
it 'imports Github repo via api', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1858' do
|
it 'imports Github repo via api', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1858' do
|
||||||
imported_project # import the project
|
imported_project # import the project
|
||||||
|
|
||||||
expect { imported_project.reload!.import_status }.to eventually_eq('finished').within(duration: 90)
|
expect { imported_project.reload!.import_status }.to eventually_eq('finished').within(max_duration: 90)
|
||||||
|
|
||||||
aggregate_failures do
|
aggregate_failures do
|
||||||
verify_repository_import
|
verify_repository_import
|
||||||
|
|
|
@ -138,7 +138,7 @@ module QA
|
||||||
raise "Import of '#{imported_project.name}' failed!" if status == 'failed'
|
raise "Import of '#{imported_project.name}' failed!" if status == 'failed'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
expect(import_status).to eventually_eq('finished').within(duration: import_max_duration, interval: 30)
|
expect(import_status).to eventually_eq('finished').within(max_duration: import_max_duration, sleep_interval: 30)
|
||||||
@import_time = Time.now - start
|
@import_time = Time.now - start
|
||||||
|
|
||||||
aggregate_failures do
|
aggregate_failures do
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
module QA
|
module QA
|
||||||
RSpec.describe 'Configure', except: { job: 'review-qa-*' } do
|
RSpec.describe 'Configure', except: { job: 'review-qa-*' } do
|
||||||
describe 'Kubernetes Cluster Integration', :requires_admin, :skip_live_env do
|
describe 'Kubernetes Cluster Integration', :requires_admin, :skip_live_env, :smoke do
|
||||||
context 'Project Clusters' do
|
context 'Project Clusters' do
|
||||||
let!(:cluster) { Service::KubernetesCluster.new(provider_class: Service::ClusterProvider::K3s).create! }
|
let!(:cluster) { Service::KubernetesCluster.new(provider_class: Service::ClusterProvider::K3s).create! }
|
||||||
let(:project) do
|
let(:project) do
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
# expect { Something.that.takes.time.to_appear }.not_to eventually_eq(expected_result)
|
# expect { Something.that.takes.time.to_appear }.not_to eventually_eq(expected_result)
|
||||||
#
|
#
|
||||||
# With duration and attempts override
|
# With duration and attempts override
|
||||||
# expect { Something.that.takes.time.to_appear }.to eventually_eq(expected_result).within(duration: 10, attempts: 5)
|
# expect { Something.that.takes.time.to_appear }.to eventually_eq(expected_result).within(max_duration: 10, max_attempts: 5)
|
||||||
|
|
||||||
module Matchers
|
module Matchers
|
||||||
%w[
|
%w[
|
||||||
|
@ -21,11 +21,9 @@ module Matchers
|
||||||
be_empty
|
be_empty
|
||||||
].each do |op|
|
].each do |op|
|
||||||
RSpec::Matchers.define(:"eventually_#{op}") do |*expected|
|
RSpec::Matchers.define(:"eventually_#{op}") do |*expected|
|
||||||
chain(:within) do |options = {}|
|
chain(:within) do |kwargs = {}|
|
||||||
@duration = options[:duration]
|
@retry_args = kwargs
|
||||||
@attempts = options[:attempts]
|
@retry_args[:sleep_interval] = 0.5 unless @retry_args[:sleep_interval]
|
||||||
@interval = options[:interval]
|
|
||||||
@reload_page = options[:reload_page]
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def supports_block_expectations?
|
def supports_block_expectations?
|
||||||
|
@ -57,12 +55,7 @@ module Matchers
|
||||||
attempt = 0
|
attempt = 0
|
||||||
|
|
||||||
QA::Runtime::Logger.debug("Running eventually matcher with '#{operator_msg}' operator")
|
QA::Runtime::Logger.debug("Running eventually matcher with '#{operator_msg}' operator")
|
||||||
QA::Support::Retrier.retry_until(
|
QA::Support::Retrier.retry_until(**@retry_args) do
|
||||||
max_attempts: @attempts,
|
|
||||||
max_duration: @duration,
|
|
||||||
sleep_interval: @interval || 0.5,
|
|
||||||
reload_page: @reload_page
|
|
||||||
) do
|
|
||||||
QA::Runtime::Logger.debug("evaluating expectation, attempt: #{attempt += 1}")
|
QA::Runtime::Logger.debug("evaluating expectation, attempt: #{attempt += 1}")
|
||||||
|
|
||||||
public_send(expectation_name, actual)
|
public_send(expectation_name, actual)
|
||||||
|
|
|
@ -99,6 +99,48 @@
|
||||||
"status": {
|
"status": {
|
||||||
"type": ["string"],
|
"type": ["string"],
|
||||||
"enum": ["DEFAULT", "HIDDEN", "PROCESSING", "ERROR"]
|
"enum": ["DEFAULT", "HIDDEN", "PROCESSING", "ERROR"]
|
||||||
|
},
|
||||||
|
"dependencyLinks": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"pageInfo": { "type": "object" },
|
||||||
|
"edges": { "type": "array" },
|
||||||
|
"nodes": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"dependencyType": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"dependency": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"versionPattern": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"anyOf": [
|
||||||
|
{ "$ref": "./package_nuget_dependency_link_metadata.json" },
|
||||||
|
{ "type": "null" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
12
spec/fixtures/api/schemas/graphql/packages/package_nuget_dependency_link_metadata.json
vendored
Normal file
12
spec/fixtures/api/schemas/graphql/packages/package_nuget_dependency_link_metadata.json
vendored
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"targetFramework": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,11 +23,15 @@ describe('Confirm Rollback Modal Component', () => {
|
||||||
commitUrl: 'test/-/commit/abc0123',
|
commitUrl: 'test/-/commit/abc0123',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const retryPath = 'test/-/jobs/123/retry';
|
||||||
|
|
||||||
describe.each`
|
describe.each`
|
||||||
hasMultipleCommits | environmentData
|
hasMultipleCommits | environmentData | retryUrl | primaryPropsAttrs
|
||||||
${true} | ${envWithLastDeployment}
|
${true} | ${envWithLastDeployment} | ${null} | ${[{ variant: 'danger' }]}
|
||||||
${false} | ${envWithoutLastDeployment}
|
${false} | ${envWithoutLastDeployment} | ${retryPath} | ${[{ variant: 'danger' }, { 'data-method': 'post' }, { href: retryPath }]}
|
||||||
`('when hasMultipleCommits=$hasMultipleCommits', ({ hasMultipleCommits, environmentData }) => {
|
`(
|
||||||
|
'when hasMultipleCommits=$hasMultipleCommits',
|
||||||
|
({ hasMultipleCommits, environmentData, retryUrl, primaryPropsAttrs }) => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
environment = environmentData;
|
environment = environmentData;
|
||||||
});
|
});
|
||||||
|
@ -40,13 +44,15 @@ describe('Confirm Rollback Modal Component', () => {
|
||||||
isLastDeployment: false,
|
isLastDeployment: false,
|
||||||
},
|
},
|
||||||
hasMultipleCommits,
|
hasMultipleCommits,
|
||||||
|
retryUrl,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const modal = component.find(GlModal);
|
const modal = component.find(GlModal);
|
||||||
|
|
||||||
expect(modal.attributes('title')).toContain('Rollback');
|
expect(modal.attributes('title')).toContain('Rollback');
|
||||||
expect(modal.attributes('title')).toContain('test');
|
expect(modal.attributes('title')).toContain('test');
|
||||||
expect(modal.attributes('ok-title')).toBe('Rollback');
|
expect(modal.props('actionPrimary').text).toBe('Rollback');
|
||||||
|
expect(modal.props('actionPrimary').attributes).toEqual(primaryPropsAttrs);
|
||||||
expect(modal.text()).toContain('commit abc0123');
|
expect(modal.text()).toContain('commit abc0123');
|
||||||
expect(modal.text()).toContain('Are you sure you want to continue?');
|
expect(modal.text()).toContain('Are you sure you want to continue?');
|
||||||
});
|
});
|
||||||
|
@ -65,7 +71,7 @@ describe('Confirm Rollback Modal Component', () => {
|
||||||
|
|
||||||
expect(modal.attributes('title')).toContain('Re-deploy');
|
expect(modal.attributes('title')).toContain('Re-deploy');
|
||||||
expect(modal.attributes('title')).toContain('test');
|
expect(modal.attributes('title')).toContain('test');
|
||||||
expect(modal.attributes('ok-title')).toBe('Re-deploy');
|
expect(modal.props('actionPrimary').text).toBe('Re-deploy');
|
||||||
expect(modal.text()).toContain('commit abc0123');
|
expect(modal.text()).toContain('commit abc0123');
|
||||||
expect(modal.text()).toContain('Are you sure you want to continue?');
|
expect(modal.text()).toContain('Are you sure you want to continue?');
|
||||||
});
|
});
|
||||||
|
@ -84,5 +90,6 @@ describe('Confirm Rollback Modal Component', () => {
|
||||||
|
|
||||||
expect(eventHubSpy).toHaveBeenCalledWith('rollbackEnvironment', env);
|
expect(eventHubSpy).toHaveBeenCalledWith('rollbackEnvironment', env);
|
||||||
});
|
});
|
||||||
});
|
},
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,101 @@
|
||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`VersionRow renders 1`] = `
|
||||||
|
<div
|
||||||
|
class="gl-display-flex gl-flex-direction-column gl-border-b-solid gl-border-t-solid gl-border-t-1 gl-border-b-1 gl-border-t-transparent gl-border-b-gray-100"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="gl-display-flex gl-align-items-center gl-py-3 gl-px-5"
|
||||||
|
>
|
||||||
|
<!---->
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="gl-display-flex gl-xs-flex-direction-column gl-justify-content-space-between gl-align-items-stretch gl-flex-grow-1"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="gl-display-flex gl-flex-direction-column gl-xs-mb-3 gl-min-w-0 gl-flex-grow-1"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="gl-display-flex gl-align-items-center gl-text-body gl-font-weight-bold gl-min-h-6 gl-min-w-0"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="gl-display-flex gl-align-items-center gl-mr-3 gl-min-w-0"
|
||||||
|
>
|
||||||
|
<gl-link-stub
|
||||||
|
class="gl-text-body gl-min-w-0"
|
||||||
|
href="243"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="gl-truncate"
|
||||||
|
title="@gitlab-org/package-15"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="gl-truncate-end"
|
||||||
|
>
|
||||||
|
@gitlab-org/package-15
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</gl-link-stub>
|
||||||
|
|
||||||
|
<package-tags-stub
|
||||||
|
class="gl-ml-3"
|
||||||
|
hidelabel="true"
|
||||||
|
tagdisplaylimit="1"
|
||||||
|
tags="[object Object],[object Object],[object Object]"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!---->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="gl-display-flex gl-align-items-center gl-text-gray-500 gl-min-h-6 gl-min-w-0 gl-flex-grow-1"
|
||||||
|
>
|
||||||
|
|
||||||
|
1.0.1
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="gl-display-flex gl-flex-direction-column gl-sm-align-items-flex-end gl-justify-content-space-between gl-text-gray-500 gl-flex-shrink-0"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="gl-display-flex gl-align-items-center gl-sm-text-body gl-sm-font-weight-bold gl-min-h-6"
|
||||||
|
>
|
||||||
|
<publish-method-stub
|
||||||
|
packageentity="[object Object]"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="gl-display-flex gl-align-items-center gl-min-h-6"
|
||||||
|
>
|
||||||
|
Created
|
||||||
|
<time-ago-tooltip-stub
|
||||||
|
cssclass=""
|
||||||
|
time="2021-08-10T09:33:54Z"
|
||||||
|
tooltipplacement="top"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!---->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="gl-display-flex"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="gl-w-7"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!---->
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="gl-w-9"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
|
@ -14,6 +14,7 @@ import InstallationCommands from '~/packages_and_registries/package_registry/com
|
||||||
import PackageFiles from '~/packages_and_registries/package_registry/components/details/package_files.vue';
|
import PackageFiles from '~/packages_and_registries/package_registry/components/details/package_files.vue';
|
||||||
import PackageHistory from '~/packages_and_registries/package_registry/components/details/package_history.vue';
|
import PackageHistory from '~/packages_and_registries/package_registry/components/details/package_history.vue';
|
||||||
import PackageTitle from '~/packages_and_registries/package_registry/components/details/package_title.vue';
|
import PackageTitle from '~/packages_and_registries/package_registry/components/details/package_title.vue';
|
||||||
|
import VersionRow from '~/packages_and_registries/package_registry/components/details/version_row.vue';
|
||||||
import {
|
import {
|
||||||
FETCH_PACKAGE_DETAILS_ERROR_MESSAGE,
|
FETCH_PACKAGE_DETAILS_ERROR_MESSAGE,
|
||||||
DELETE_PACKAGE_ERROR_MESSAGE,
|
DELETE_PACKAGE_ERROR_MESSAGE,
|
||||||
|
@ -28,6 +29,7 @@ import getPackageDetails from '~/packages_and_registries/package_registry/graphq
|
||||||
import {
|
import {
|
||||||
packageDetailsQuery,
|
packageDetailsQuery,
|
||||||
packageData,
|
packageData,
|
||||||
|
packageVersions,
|
||||||
emptyPackageDetailsQuery,
|
emptyPackageDetailsQuery,
|
||||||
packageDestroyMutation,
|
packageDestroyMutation,
|
||||||
packageDestroyMutationError,
|
packageDestroyMutationError,
|
||||||
|
@ -96,6 +98,8 @@ describe('PackagesApp', () => {
|
||||||
const findDeleteButton = () => wrapper.findByTestId('delete-package');
|
const findDeleteButton = () => wrapper.findByTestId('delete-package');
|
||||||
const findPackageFiles = () => wrapper.findComponent(PackageFiles);
|
const findPackageFiles = () => wrapper.findComponent(PackageFiles);
|
||||||
const findDeleteFileModal = () => wrapper.findByTestId('delete-file-modal');
|
const findDeleteFileModal = () => wrapper.findByTestId('delete-file-modal');
|
||||||
|
const findVersionRows = () => wrapper.findAllComponents(VersionRow);
|
||||||
|
const noVersionsMessage = () => wrapper.findByTestId('no-versions-message');
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
wrapper.destroy();
|
wrapper.destroy();
|
||||||
|
@ -362,4 +366,39 @@ describe('PackagesApp', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('versions', () => {
|
||||||
|
it('displays the correct version count when the package has versions', async () => {
|
||||||
|
createComponent();
|
||||||
|
|
||||||
|
await waitForPromises();
|
||||||
|
|
||||||
|
expect(findVersionRows()).toHaveLength(packageVersions().length);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('binds the correct props', async () => {
|
||||||
|
const [versionPackage] = packageVersions();
|
||||||
|
// eslint-disable-next-line no-underscore-dangle
|
||||||
|
delete versionPackage.__typename;
|
||||||
|
delete versionPackage.tags;
|
||||||
|
|
||||||
|
createComponent();
|
||||||
|
|
||||||
|
await waitForPromises();
|
||||||
|
|
||||||
|
expect(findVersionRows().at(0).props()).toMatchObject({
|
||||||
|
packageEntity: expect.objectContaining(versionPackage),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('displays the no versions message when there are none', async () => {
|
||||||
|
createComponent({
|
||||||
|
resolver: jest.fn().mockResolvedValue(packageDetailsQuery({ versions: { nodes: [] } })),
|
||||||
|
});
|
||||||
|
|
||||||
|
await waitForPromises();
|
||||||
|
|
||||||
|
expect(noVersionsMessage().exists()).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,89 @@
|
||||||
|
import { GlLink, GlSprintf, GlTruncate } from '@gitlab/ui';
|
||||||
|
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
||||||
|
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
|
||||||
|
import PackageTags from '~/packages/shared/components/package_tags.vue';
|
||||||
|
import PublishMethod from '~/packages/shared/components/publish_method.vue';
|
||||||
|
import VersionRow from '~/packages_and_registries/package_registry/components/details/version_row.vue';
|
||||||
|
import ListItem from '~/vue_shared/components/registry/list_item.vue';
|
||||||
|
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
|
||||||
|
|
||||||
|
import { packageVersions } from '../../mock_data';
|
||||||
|
|
||||||
|
const packageVersion = packageVersions()[0];
|
||||||
|
|
||||||
|
describe('VersionRow', () => {
|
||||||
|
let wrapper;
|
||||||
|
|
||||||
|
const findListItem = () => wrapper.findComponent(ListItem);
|
||||||
|
const findLink = () => wrapper.findComponent(GlLink);
|
||||||
|
const findPackageTags = () => wrapper.findComponent(PackageTags);
|
||||||
|
const findPublishMethod = () => wrapper.findComponent(PublishMethod);
|
||||||
|
const findTimeAgoTooltip = () => wrapper.findComponent(TimeAgoTooltip);
|
||||||
|
|
||||||
|
function createComponent(packageEntity = packageVersion) {
|
||||||
|
wrapper = shallowMountExtended(VersionRow, {
|
||||||
|
propsData: {
|
||||||
|
packageEntity,
|
||||||
|
},
|
||||||
|
stubs: {
|
||||||
|
ListItem,
|
||||||
|
GlSprintf,
|
||||||
|
GlTruncate,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
wrapper.destroy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders', () => {
|
||||||
|
createComponent();
|
||||||
|
|
||||||
|
expect(wrapper.element).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('has a link to the version detail', () => {
|
||||||
|
createComponent();
|
||||||
|
|
||||||
|
expect(findLink().attributes('href')).toBe(`${getIdFromGraphQLId(packageVersion.id)}`);
|
||||||
|
expect(findLink().text()).toBe(packageVersion.name);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('has the version of the package', () => {
|
||||||
|
createComponent();
|
||||||
|
|
||||||
|
expect(wrapper.text()).toContain(packageVersion.version);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('has a package tags component', () => {
|
||||||
|
createComponent();
|
||||||
|
|
||||||
|
expect(findPackageTags().props('tags')).toBe(packageVersion.tags.nodes);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('has a publish method component', () => {
|
||||||
|
createComponent();
|
||||||
|
|
||||||
|
expect(findPublishMethod().props('packageEntity')).toBe(packageVersion);
|
||||||
|
});
|
||||||
|
it('has a time-ago tooltip', () => {
|
||||||
|
createComponent();
|
||||||
|
|
||||||
|
expect(findTimeAgoTooltip().props('time')).toBe(packageVersion.createdAt);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('disabled status', () => {
|
||||||
|
it('disables the list item', () => {
|
||||||
|
createComponent({ ...packageVersion, status: 'something' });
|
||||||
|
|
||||||
|
expect(findListItem().props('disabled')).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('disables the link', () => {
|
||||||
|
createComponent({ ...packageVersion, status: 'something' });
|
||||||
|
|
||||||
|
expect(findLink().attributes('disabled')).toBe('true');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -51,6 +51,27 @@ export const packageFiles = () => [
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export const packageVersions = () => [
|
||||||
|
{
|
||||||
|
createdAt: '2021-08-10T09:33:54Z',
|
||||||
|
id: 'gid://gitlab/Packages::Package/243',
|
||||||
|
name: '@gitlab-org/package-15',
|
||||||
|
status: 'DEFAULT',
|
||||||
|
tags: { nodes: packageTags() },
|
||||||
|
version: '1.0.1',
|
||||||
|
__typename: 'Package',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
createdAt: '2021-08-10T09:33:54Z',
|
||||||
|
id: 'gid://gitlab/Packages::Package/244',
|
||||||
|
name: '@gitlab-org/package-15',
|
||||||
|
status: 'DEFAULT',
|
||||||
|
tags: { nodes: packageTags() },
|
||||||
|
version: '1.0.2',
|
||||||
|
__typename: 'Package',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
export const packageData = (extend) => ({
|
export const packageData = (extend) => ({
|
||||||
id: 'gid://gitlab/Packages::Package/111',
|
id: 'gid://gitlab/Packages::Package/111',
|
||||||
name: '@gitlab-org/package-15',
|
name: '@gitlab-org/package-15',
|
||||||
|
@ -105,6 +126,9 @@ export const packageDetailsQuery = (extendPackage) => ({
|
||||||
...mavenMetadata(),
|
...mavenMetadata(),
|
||||||
...nugetMetadata(),
|
...nugetMetadata(),
|
||||||
},
|
},
|
||||||
|
project: {
|
||||||
|
path: 'projectPath',
|
||||||
|
},
|
||||||
tags: {
|
tags: {
|
||||||
nodes: packageTags(),
|
nodes: packageTags(),
|
||||||
__typename: 'PackageTagConnection',
|
__typename: 'PackageTagConnection',
|
||||||
|
@ -117,6 +141,10 @@ export const packageDetailsQuery = (extendPackage) => ({
|
||||||
nodes: packageFiles(),
|
nodes: packageFiles(),
|
||||||
__typename: 'PackageFileConnection',
|
__typename: 'PackageFileConnection',
|
||||||
},
|
},
|
||||||
|
versions: {
|
||||||
|
nodes: packageVersions(),
|
||||||
|
__typename: 'PackageConnection',
|
||||||
|
},
|
||||||
__typename: 'PackageDetailsType',
|
__typename: 'PackageDetailsType',
|
||||||
...extendPackage,
|
...extendPackage,
|
||||||
},
|
},
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
RSpec.describe GitlabSchema.types['NugetDependencyLinkMetadata'] do
|
||||||
|
it 'includes nuget dependency link metadatum fields' do
|
||||||
|
expected_fields = %w[
|
||||||
|
id target_framework
|
||||||
|
]
|
||||||
|
|
||||||
|
expect(described_class).to include_graphql_fields(*expected_fields)
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,13 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
RSpec.describe GitlabSchema.types['PackageDependencyLink'] do
|
||||||
|
it 'includes package file fields' do
|
||||||
|
expected_fields = %w[
|
||||||
|
id dependency_type dependency metadata
|
||||||
|
]
|
||||||
|
|
||||||
|
expect(described_class).to include_graphql_fields(*expected_fields)
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,9 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
RSpec.describe GitlabSchema.types['PackageDependencyType'] do
|
||||||
|
it 'exposes all depeendency type values' do
|
||||||
|
expect(described_class.values.keys).to contain_exactly(*%w[DEPENDENCIES DEV_DEPENDENCIES BUNDLE_DEPENDENCIES PEER_DEPENDENCIES])
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,13 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
RSpec.describe GitlabSchema.types['PackageDependency'] do
|
||||||
|
it 'includes package file fields' do
|
||||||
|
expected_fields = %w[
|
||||||
|
id name version_pattern
|
||||||
|
]
|
||||||
|
|
||||||
|
expect(described_class).to include_graphql_fields(*expected_fields)
|
||||||
|
end
|
||||||
|
end
|
|
@ -5,7 +5,7 @@ require 'spec_helper'
|
||||||
RSpec.describe GitlabSchema.types['PackageDetailsType'] do
|
RSpec.describe GitlabSchema.types['PackageDetailsType'] do
|
||||||
it 'includes all the package fields' do
|
it 'includes all the package fields' do
|
||||||
expected_fields = %w[
|
expected_fields = %w[
|
||||||
id name version created_at updated_at package_type tags project pipelines versions package_files
|
id name version created_at updated_at package_type tags project pipelines versions package_files dependency_links
|
||||||
]
|
]
|
||||||
|
|
||||||
expect(described_class).to include_graphql_fields(*expected_fields)
|
expect(described_class).to include_graphql_fields(*expected_fields)
|
||||||
|
|
|
@ -7,6 +7,15 @@ RSpec.describe 'Rails asset host initializer' do
|
||||||
load Rails.root.join('config/initializers/rails_asset_host.rb')
|
load Rails.root.join('config/initializers/rails_asset_host.rb')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
around do |example|
|
||||||
|
old_asset_host = Rails.application.config.action_controller.asset_host
|
||||||
|
|
||||||
|
example.run
|
||||||
|
|
||||||
|
Rails.application.config.action_controller.asset_host = old_asset_host
|
||||||
|
ActionController::Base.asset_host = old_asset_host
|
||||||
|
end
|
||||||
|
|
||||||
subject { Rails.application.config.action_controller.asset_host }
|
subject { Rails.application.config.action_controller.asset_host }
|
||||||
|
|
||||||
it 'uses no asset host by default' do
|
it 'uses no asset host by default' do
|
||||||
|
|
|
@ -434,20 +434,6 @@ RSpec.describe Gitlab::Ci::Config::Entry::Job do
|
||||||
expect(entry.errors).to include 'job dependencies the another-job should be part of needs'
|
expect(entry.errors).to include 'job dependencies the another-job should be part of needs'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when stage: is missing' do
|
|
||||||
let(:config) do
|
|
||||||
{
|
|
||||||
script: 'echo',
|
|
||||||
needs: ['build-job']
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns error about invalid data' do
|
|
||||||
expect(entry).not_to be_valid
|
|
||||||
expect(entry.errors).to include 'job config missing required keys: stage'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when timeout value is not correct' do
|
context 'when timeout value is not correct' do
|
||||||
|
|
|
@ -6,8 +6,11 @@ RSpec.describe 'nuget package details' do
|
||||||
include_context 'package details setup'
|
include_context 'package details setup'
|
||||||
|
|
||||||
let_it_be(:package) { create(:nuget_package, :with_metadatum, project: project) }
|
let_it_be(:package) { create(:nuget_package, :with_metadatum, project: project) }
|
||||||
|
let_it_be(:dependency_link) { create(:packages_dependency_link, :with_nuget_metadatum, package: package) }
|
||||||
|
|
||||||
let(:metadata) { query_graphql_fragment('NugetMetadata') }
|
let(:metadata) { query_graphql_fragment('NugetMetadata') }
|
||||||
|
let(:dependency_link_response) { graphql_data_at(:package, :dependency_links, :nodes, 0) }
|
||||||
|
let(:dependency_response) { graphql_data_at(:package, :dependency_links, :nodes, 0, :dependency) }
|
||||||
|
|
||||||
subject { post_graphql(query, current_user: user) }
|
subject { post_graphql(query, current_user: user) }
|
||||||
|
|
||||||
|
@ -26,4 +29,34 @@ RSpec.describe 'nuget package details' do
|
||||||
'iconUrl' => package.nuget_metadatum.icon_url
|
'iconUrl' => package.nuget_metadatum.icon_url
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'has dependency links' do
|
||||||
|
expect(dependency_link_response).to include(
|
||||||
|
'id' => global_id_of(dependency_link),
|
||||||
|
'dependencyType' => dependency_link.dependency_type.upcase
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(dependency_response).to include(
|
||||||
|
'id' => global_id_of(dependency_link.dependency),
|
||||||
|
'name' => dependency_link.dependency.name,
|
||||||
|
'versionPattern' => dependency_link.dependency.version_pattern
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'avoids N+1 queries' do
|
||||||
|
first_user = create(:user)
|
||||||
|
second_user = create(:user)
|
||||||
|
|
||||||
|
control_count = ActiveRecord::QueryRecorder.new do
|
||||||
|
post_graphql(query, current_user: first_user)
|
||||||
|
end
|
||||||
|
|
||||||
|
create_list(:packages_dependency_link, 10, :with_nuget_metadatum, package: package)
|
||||||
|
|
||||||
|
expect do
|
||||||
|
post_graphql(query, current_user: second_user)
|
||||||
|
end.not_to exceed_query_limit(control_count)
|
||||||
|
|
||||||
|
expect(response).to have_gitlab_http_status(:ok)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -9,6 +9,7 @@ RSpec.shared_context 'package details setup' do
|
||||||
let(:depth) { 3 }
|
let(:depth) { 3 }
|
||||||
let(:excluded) { %w[metadata apiFuzzingCiConfiguration pipeline packageFiles] }
|
let(:excluded) { %w[metadata apiFuzzingCiConfiguration pipeline packageFiles] }
|
||||||
let(:package_files) { all_graphql_fields_for('PackageFile') }
|
let(:package_files) { all_graphql_fields_for('PackageFile') }
|
||||||
|
let(:dependency_links) { all_graphql_fields_for('PackageDependencyLink') }
|
||||||
let(:user) { project.owner }
|
let(:user) { project.owner }
|
||||||
let(:package_details) { graphql_data_at(:package) }
|
let(:package_details) { graphql_data_at(:package) }
|
||||||
let(:metadata_response) { graphql_data_at(:package, :metadata) }
|
let(:metadata_response) { graphql_data_at(:package, :metadata) }
|
||||||
|
@ -28,6 +29,11 @@ RSpec.shared_context 'package details setup' do
|
||||||
#{package_files}
|
#{package_files}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
dependencyLinks {
|
||||||
|
nodes {
|
||||||
|
#{dependency_links}
|
||||||
|
}
|
||||||
|
}
|
||||||
FIELDS
|
FIELDS
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue